Compare commits
73 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
317233cec9 | ||
|
|
7b92d53b84 | ||
|
|
f7dd832517 | ||
|
|
c21f958eaf | ||
|
|
5a195b441c | ||
|
|
c46516475d | ||
|
|
97af062f7b | ||
|
|
8004b135b1 | ||
|
|
4b9264531b | ||
|
|
9a506d3755 | ||
|
|
e320eb29c2 | ||
|
|
282f11a7c2 | ||
|
|
91f3e29c08 | ||
|
|
1fd6cf1a2f | ||
|
|
efed23701a | ||
|
|
ad1bf5cf6e | ||
|
|
ee8eb1d8a6 | ||
|
|
39f5c50acd | ||
|
|
d4a4bda645 | ||
|
|
2069eddf98 | ||
|
|
c652653ea4 | ||
|
|
6889837785 | ||
|
|
cf7c12c97b | ||
|
|
d88181343c | ||
|
|
e7e638443f | ||
|
|
2f515e8d8f | ||
|
|
e54fc9b1e9 | ||
|
|
66345e855e | ||
|
|
37e046acc4 | ||
|
|
f40ef76c79 | ||
|
|
123ca87388 | ||
|
|
994906fbd4 | ||
|
|
06d465b0d1 | ||
|
|
ca313521dc | ||
|
|
2902f030be | ||
|
|
371261b2c6 | ||
|
|
d26c480d03 | ||
|
|
b6d00f774b | ||
|
|
d3ada9881a | ||
|
|
7309a53356 | ||
|
|
15b937d68b | ||
|
|
681c604c22 | ||
|
|
9fda7bfd34 | ||
|
|
826b314f19 | ||
|
|
156c199bbb | ||
|
|
040596f3a0 | ||
|
|
fde082af44 | ||
|
|
329e144b4f | ||
|
|
367b319f10 | ||
|
|
d6fe0bd740 | ||
|
|
ae7bd79a6c | ||
|
|
0211424191 | ||
|
|
ea8d634f65 | ||
|
|
0fec990bcf | ||
|
|
a7680a593a | ||
|
|
cbc7985e75 | ||
|
|
941eb1dd73 | ||
|
|
fc64e0089e | ||
|
|
24b41100c3 | ||
|
|
b72a3d01b8 | ||
|
|
0393e41096 | ||
|
|
c77b2a0ce5 | ||
|
|
db52f7a3ac | ||
|
|
381f2f651d | ||
|
|
620b51e3ea | ||
|
|
757ddb06f8 | ||
|
|
d6043e2352 | ||
|
|
aeec9a86e2 | ||
|
|
584182e264 | ||
|
|
96cd512d32 | ||
|
|
11898a3f73 | ||
|
|
a91a257b15 | ||
|
|
76a74b271b |
130
.github/ISSUE_TEMPLATE/bug.yml
vendored
130
.github/ISSUE_TEMPLATE/bug.yml
vendored
@@ -10,52 +10,58 @@
|
||||
- 'label': >
|
||||
I have checked the
|
||||
[Wiki](https://github.com/AdguardTeam/AdGuardHome/wiki) and
|
||||
[Discussions](https://github.com/AdguardTeam/AdGuardHome/discussions)
|
||||
[Discussions](https://github.com/AdguardTeam/AdGuardHome/discussions/categories/q-a)
|
||||
and found no answer
|
||||
'required': true
|
||||
- 'label': >
|
||||
I have searched other issues and found no duplicates
|
||||
'required': true
|
||||
- 'label': >
|
||||
I want to report a bug and not ask a question
|
||||
I want to report a bug and not [ask a question or ask for
|
||||
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
|
||||
'id': 'prerequisites'
|
||||
'type': 'checkboxes'
|
||||
- 'attributes':
|
||||
'description': 'On which operating system type does the issue occur?'
|
||||
'label': 'Operating system type'
|
||||
'description': 'On which Platform does the issue occur?'
|
||||
'label': 'Platform (OS and CPU architecture)'
|
||||
'options':
|
||||
- 'FreeBSD'
|
||||
- 'Linux, OpenWrt'
|
||||
- 'Linux, Other (please mention the version in the description)'
|
||||
- 'macOS (aka Darwin)'
|
||||
- 'OpenBSD'
|
||||
- 'Windows'
|
||||
- 'Other (please mention in the description)'
|
||||
- 'Darwin (aka macOS)/AMD64 (aka x86_64)'
|
||||
- 'Darwin (aka macOS)/ARM64'
|
||||
- 'FreeBSD/386'
|
||||
- 'FreeBSD/AMD64 (aka x86_64)'
|
||||
- 'FreeBSD/ARM64'
|
||||
- 'FreeBSD/ARMv5'
|
||||
- 'FreeBSD/ARMv6'
|
||||
- 'FreeBSD/ARMv7'
|
||||
- 'Linux/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'
|
||||
- 'OpenBSD/AMD64 (aka x86_64)'
|
||||
- 'OpenBSD/ARM64'
|
||||
- 'Windows/386'
|
||||
- 'Windows/AMD64 (aka x86_64)'
|
||||
- 'Windows/ARM64'
|
||||
- 'Custom (please mention in the description)'
|
||||
'id': 'os'
|
||||
'type': 'dropdown'
|
||||
'validations':
|
||||
'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':
|
||||
'description': 'How did you install AdGuard Home?'
|
||||
'label': 'Installation'
|
||||
@@ -63,7 +69,7 @@
|
||||
- 'GitHub releases or script from README'
|
||||
- 'Docker'
|
||||
- 'Snapcraft'
|
||||
- 'Custom port'
|
||||
- 'Custom package (OpenWrt, HomeAssistant, etc; please mention in the description)'
|
||||
- 'Other (please mention in the description)'
|
||||
'id': 'install'
|
||||
'type': 'dropdown'
|
||||
@@ -89,21 +95,55 @@
|
||||
'validations':
|
||||
'required': true
|
||||
- 'attributes':
|
||||
'description': 'Please describe the bug'
|
||||
'label': 'Description'
|
||||
'description': >
|
||||
Please describe what you did. An `nslookup` or a `dig` command is
|
||||
the best way. For crashes, please provide a full failure log.
|
||||
'label': 'Action'
|
||||
'value': |
|
||||
#### What did you do?
|
||||
|
||||
#### Expected result
|
||||
|
||||
#### Actual result
|
||||
|
||||
#### Screenshots (if applicable)
|
||||
|
||||
#### Additional information
|
||||
'id': 'description'
|
||||
```sh
|
||||
nslookup -debug -type=a 'www.example.com' '$YOUR_AGH_ADDRESS'
|
||||
```
|
||||
'id': 'failing_action'
|
||||
'type': 'textarea'
|
||||
'validations':
|
||||
'required': true
|
||||
'description': 'File a bug report'
|
||||
- 'attributes':
|
||||
'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
|
||||
'description': >
|
||||
Open a bug report. Please do not open bug reports for questions or help
|
||||
with configuring clients. If you want to ask for help, use the Discussions
|
||||
section.
|
||||
'name': 'Bug'
|
||||
|
||||
35
.github/ISSUE_TEMPLATE/feature.yml
vendored
35
.github/ISSUE_TEMPLATE/feature.yml
vendored
@@ -23,19 +23,32 @@
|
||||
'id': 'prerequisites'
|
||||
'type': 'checkboxes'
|
||||
- 'attributes':
|
||||
'description': 'Please describe the request'
|
||||
'label': 'Description'
|
||||
'value': |
|
||||
#### What problem are you trying to solve?
|
||||
|
||||
#### Proposed solution
|
||||
|
||||
#### Alternatives considered
|
||||
|
||||
#### Additional information
|
||||
'id': 'description'
|
||||
'description': 'Please describe the problem you are trying to solve'
|
||||
'label': 'The problem'
|
||||
'placeholder': >
|
||||
Please describe the problem you are trying to solve
|
||||
'id': 'problem'
|
||||
'type': 'textarea'
|
||||
'validations':
|
||||
'required': true
|
||||
- 'attributes':
|
||||
'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
|
||||
'description': 'Suggest a feature or an enhancement for AdGuard Home'
|
||||
'labels':
|
||||
- 'feature request'
|
||||
'name': 'Feature request or enhancement'
|
||||
|
||||
20
.github/PULL_REQUEST_TEMPLATE
vendored
Normal file
20
.github/PULL_REQUEST_TEMPLATE
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
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.
|
||||
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@@ -1,7 +1,7 @@
|
||||
'name': 'build'
|
||||
|
||||
'env':
|
||||
'GO_VERSION': '1.19.8'
|
||||
'GO_VERSION': '1.19.10'
|
||||
'NODE_VERSION': '14'
|
||||
|
||||
'on':
|
||||
|
||||
2
.github/workflows/lint.yml
vendored
2
.github/workflows/lint.yml
vendored
@@ -1,7 +1,7 @@
|
||||
'name': 'lint'
|
||||
|
||||
'env':
|
||||
'GO_VERSION': '1.19.8'
|
||||
'GO_VERSION': '1.19.10'
|
||||
|
||||
'on':
|
||||
'push':
|
||||
|
||||
18
.github/workflows/potential-duplicates.yml
vendored
Normal file
18
.github/workflows/potential-duplicates.yml
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
'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}}
|
||||
7
.gitignore
vendored
7
.gitignore
vendored
@@ -9,6 +9,7 @@
|
||||
*.db
|
||||
*.log
|
||||
*.snap
|
||||
*.test
|
||||
/agh-backup/
|
||||
/bin/
|
||||
/build/*
|
||||
@@ -16,12 +17,14 @@
|
||||
/dist/
|
||||
/filtering/tests/filtering.TestLotsOfRules*.pprof
|
||||
/filtering/tests/top-1m.csv
|
||||
/internal/next/AdGuardHome.yaml
|
||||
/launchpad_credentials
|
||||
/querylog.json*
|
||||
/snapcraft_login
|
||||
AdGuardHome*
|
||||
AdGuardHome
|
||||
AdGuardHome.exe
|
||||
AdGuardHome.yaml*
|
||||
coverage.txt
|
||||
leases.db
|
||||
node_modules/
|
||||
|
||||
!/build/gitkeep
|
||||
|
||||
313
CHANGELOG.md
313
CHANGELOG.md
@@ -14,20 +14,302 @@ and this project adheres to
|
||||
<!--
|
||||
## [v0.108.0] - TBA
|
||||
|
||||
## [v0.107.29] - 2023-04-26 (APPROX.)
|
||||
## [v0.107.34] - 2023-07-26 (APPROX.)
|
||||
|
||||
See also the [v0.107.29 GitHub milestone][ms-v0.107.29].
|
||||
See also the [v0.107.34 GitHub milestone][ms-v0.107.34].
|
||||
|
||||
[ms-v0.107.29]: https://github.com/AdguardTeam/AdGuardHome/milestone/65?closed=1
|
||||
[ms-v0.107.34]: https://github.com/AdguardTeam/AdGuardHome/milestone/69?closed=1
|
||||
|
||||
NOTE: Add new changes BELOW THIS COMMENT.
|
||||
-->
|
||||
|
||||
### 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
|
||||
|
||||
- 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
|
||||
|
||||
<!--
|
||||
NOTE: Add new changes ABOVE THIS COMMENT.
|
||||
-->
|
||||
|
||||
|
||||
|
||||
## [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].
|
||||
|
||||
### Security
|
||||
|
||||
- Go version has been updated to prevent the possibility of exploiting the
|
||||
CVE-2023-29402, CVE-2023-29403, and CVE-2023-29404 Go vulnerabilities fixed in
|
||||
[Go 1.19.10][go-1.19.10].
|
||||
|
||||
### Fixed
|
||||
|
||||
- Unquoted IPv6 bind hosts with trailing colons erroneously considered
|
||||
unspecified addresses are now properly validated ([#5752]).
|
||||
|
||||
**NOTE:** the Docker healthcheck script now also doesn't interpret the `""`
|
||||
value as unspecified address.
|
||||
- Incorrect `Content-Type` header value in `POST /control/version.json` and `GET
|
||||
/control/dhcp/interfaces` HTTP APIs ([#5716]).
|
||||
- Provided bootstrap servers are now used to resolve the hostnames of plain
|
||||
UDP/TCP upstream servers.
|
||||
|
||||
[#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
|
||||
|
||||
|
||||
|
||||
## [v0.107.29] - 2023-04-18
|
||||
|
||||
See also the [v0.107.29 GitHub milestone][ms-v0.107.29].
|
||||
|
||||
### Added
|
||||
|
||||
- The ability to exclude client activity from the query log or statistics by
|
||||
editing client's settings on the Clients settings page in the UI ([#1717],
|
||||
[#4299]).
|
||||
editing client's settings on the respective page in the UI ([#1717], [#4299]).
|
||||
|
||||
### Changed
|
||||
|
||||
- Stored DHCP leases moved from `leases.db` to `data/leases.json`. The file
|
||||
format has also been optimized.
|
||||
|
||||
### Fixed
|
||||
|
||||
@@ -38,14 +320,12 @@ NOTE: Add new changes BELOW THIS COMMENT.
|
||||
- All Safe Search services being unchecked by default.
|
||||
- Panic when a DNSCrypt stamp is invalid ([#5721]).
|
||||
|
||||
[#1717]: https://github.com/AdguardTeam/AdGuardHome/issues/1717
|
||||
[#4299]: https://github.com/AdguardTeam/AdGuardHome/issues/4299
|
||||
[#5712]: https://github.com/AdguardTeam/AdGuardHome/issues/5712
|
||||
[#5721]: https://github.com/AdguardTeam/AdGuardHome/issues/5721
|
||||
[#5725]: https://github.com/AdguardTeam/AdGuardHome/issues/5725
|
||||
[#5752]: https://github.com/AdguardTeam/AdGuardHome/issues/5752
|
||||
|
||||
<!--
|
||||
NOTE: Add new changes ABOVE THIS COMMENT.
|
||||
-->
|
||||
[ms-v0.107.29]: https://github.com/AdguardTeam/AdGuardHome/milestone/65?closed=1
|
||||
|
||||
|
||||
|
||||
@@ -170,11 +450,9 @@ In this release, the schema version has changed from 17 to 20.
|
||||
[#1163]: https://github.com/AdguardTeam/AdGuardHome/issues/1163
|
||||
[#1333]: https://github.com/AdguardTeam/AdGuardHome/issues/1333
|
||||
[#1472]: https://github.com/AdguardTeam/AdGuardHome/issues/1472
|
||||
[#1717]: https://github.com/AdguardTeam/AdGuardHome/issues/1717
|
||||
[#3290]: https://github.com/AdguardTeam/AdGuardHome/issues/3290
|
||||
[#3459]: https://github.com/AdguardTeam/AdGuardHome/issues/3459
|
||||
[#4262]: https://github.com/AdguardTeam/AdGuardHome/issues/4262
|
||||
[#4299]: https://github.com/AdguardTeam/AdGuardHome/issues/4299
|
||||
[#5567]: https://github.com/AdguardTeam/AdGuardHome/issues/5567
|
||||
[#5701]: https://github.com/AdguardTeam/AdGuardHome/issues/5701
|
||||
|
||||
@@ -1940,11 +2218,16 @@ See also the [v0.104.2 GitHub milestone][ms-v0.104.2].
|
||||
|
||||
|
||||
<!--
|
||||
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.29...HEAD
|
||||
[v0.107.29]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.28...v0.107.29
|
||||
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.34...HEAD
|
||||
[v0.107.34]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.33...v0.107.34
|
||||
-->
|
||||
|
||||
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.28...HEAD
|
||||
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.33...HEAD
|
||||
[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.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.26]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.25...v0.107.26
|
||||
|
||||
4
Makefile
4
Makefile
@@ -78,7 +78,7 @@ build: deps quick-build
|
||||
|
||||
quick-build: js-build go-build
|
||||
|
||||
ci: deps test
|
||||
ci: deps test go-bench go-fuzz
|
||||
|
||||
deps: js-deps go-deps
|
||||
lint: js-lint go-lint
|
||||
@@ -104,8 +104,10 @@ js-deps:
|
||||
js-lint: ; $(NPM) $(NPM_FLAGS) run lint
|
||||
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-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-tools: ; $(ENV) "$(SHELL)" ./scripts/make/go-tools.sh
|
||||
|
||||
|
||||
@@ -466,6 +466,10 @@ bug or implementing the feature.
|
||||
Home](https://github.com/ebrianne/adguard-exporter) by
|
||||
[@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
|
||||
routers](https://forum.gl-inet.com/t/adguardhome-on-gl-routers/10664) by
|
||||
[Gl-Inet](https://gl-inet.com/).
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
---
|
||||
!include test.yaml
|
||||
|
||||
---
|
||||
!include release.yaml
|
||||
|
||||
---
|
||||
!include snapcraft.yaml
|
||||
|
||||
---
|
||||
!include test.yaml
|
||||
|
||||
@@ -1,349 +1,290 @@
|
||||
---
|
||||
'version': 2
|
||||
'plan':
|
||||
'project-key': 'AGH'
|
||||
'key': 'AGHBSNAPSPECS'
|
||||
'name': 'AdGuard Home - Build and publish release'
|
||||
'project-key': 'AGH'
|
||||
'key': 'AGHBSNAPSPECS'
|
||||
'name': 'AdGuard Home - Build and publish release'
|
||||
# Make sure to sync any changes with the branch overrides below.
|
||||
'variables':
|
||||
'channel': 'edge'
|
||||
'dockerGo': 'adguard/golang-ubuntu:6.3'
|
||||
'channel': 'edge'
|
||||
'dockerGo': 'adguard/golang-ubuntu:6.7'
|
||||
|
||||
'stages':
|
||||
- 'Build frontend':
|
||||
'manual': false
|
||||
'final': false
|
||||
'jobs':
|
||||
- 'Build frontend'
|
||||
- 'Build frontend':
|
||||
'manual': false
|
||||
'final': false
|
||||
'jobs':
|
||||
- 'Build frontend'
|
||||
|
||||
- 'Make release':
|
||||
'manual': false
|
||||
'final': false
|
||||
'jobs':
|
||||
- 'Make release'
|
||||
- 'Make release':
|
||||
'manual': false
|
||||
'final': false
|
||||
'jobs':
|
||||
- 'Make release'
|
||||
|
||||
- 'Make and publish docker':
|
||||
'manual': false
|
||||
'final': false
|
||||
'jobs':
|
||||
- 'Make and publish docker'
|
||||
- 'Make and publish docker':
|
||||
'manual': false
|
||||
'final': false
|
||||
'jobs':
|
||||
- 'Make and publish docker'
|
||||
|
||||
- 'Publish to static storage':
|
||||
'manual': false
|
||||
'final': false
|
||||
'jobs':
|
||||
- 'Publish to static storage'
|
||||
- 'Publish to static storage':
|
||||
'manual': false
|
||||
'final': false
|
||||
'jobs':
|
||||
- 'Publish to static storage'
|
||||
|
||||
- 'Publish to Snapstore':
|
||||
'manual': false
|
||||
'final': false
|
||||
'jobs':
|
||||
- 'Publish to Snapstore'
|
||||
|
||||
- 'Publish to GitHub Releases':
|
||||
'manual': false
|
||||
'final': false
|
||||
'jobs':
|
||||
- 'Publish to GitHub Releases'
|
||||
- 'Publish to GitHub Releases':
|
||||
'manual': false
|
||||
'final': false
|
||||
'jobs':
|
||||
- 'Publish to GitHub Releases'
|
||||
|
||||
'Build frontend':
|
||||
'docker':
|
||||
'image': '${bamboo.dockerGo}'
|
||||
'volumes':
|
||||
'${system.YARN_DIR}': '${bamboo.cacheYarn}'
|
||||
'key': 'BF'
|
||||
'other':
|
||||
'clean-working-dir': true
|
||||
'tasks':
|
||||
- 'checkout':
|
||||
'force-clean-build': true
|
||||
- 'script':
|
||||
'interpreter': 'SHELL'
|
||||
'scripts':
|
||||
- |
|
||||
#!/bin/sh
|
||||
'docker':
|
||||
'image': '${bamboo.dockerGo}'
|
||||
'volumes':
|
||||
'${system.YARN_DIR}': '${bamboo.cacheYarn}'
|
||||
'key': 'BF'
|
||||
'other':
|
||||
'clean-working-dir': true
|
||||
'tasks':
|
||||
- 'checkout':
|
||||
'force-clean-build': true
|
||||
- 'script':
|
||||
'interpreter': 'SHELL'
|
||||
'scripts':
|
||||
- |
|
||||
#!/bin/sh
|
||||
|
||||
set -e -f -u -x
|
||||
set -e -f -u -x
|
||||
|
||||
# Explicitly checkout the revision that we need.
|
||||
git checkout "${bamboo.repository.revision.number}"
|
||||
# Explicitly checkout the revision that we need.
|
||||
git checkout "${bamboo.repository.revision.number}"
|
||||
|
||||
make js-deps js-build
|
||||
'artifacts':
|
||||
- 'name': 'AdGuardHome frontend'
|
||||
'pattern': 'build*/**'
|
||||
'shared': true
|
||||
'required': true
|
||||
'requirements':
|
||||
- 'adg-docker': 'true'
|
||||
make js-deps js-build
|
||||
'artifacts':
|
||||
- 'name': 'AdGuardHome frontend'
|
||||
'pattern': 'build/**'
|
||||
'shared': true
|
||||
'required': true
|
||||
'requirements':
|
||||
- 'adg-docker': 'true'
|
||||
|
||||
'Make release':
|
||||
'docker':
|
||||
'image': '${bamboo.dockerGo}'
|
||||
'volumes':
|
||||
'${system.GO_CACHE_DIR}': '${bamboo.cacheGo}'
|
||||
'${system.GO_PKG_CACHE_DIR}': '${bamboo.cacheGoPkg}'
|
||||
'key': 'MR'
|
||||
'other':
|
||||
'clean-working-dir': true
|
||||
'tasks':
|
||||
- 'checkout':
|
||||
'force-clean-build': true
|
||||
- 'script':
|
||||
'interpreter': 'SHELL'
|
||||
'scripts':
|
||||
- |
|
||||
#!/bin/sh
|
||||
'docker':
|
||||
'image': '${bamboo.dockerGo}'
|
||||
'volumes':
|
||||
'${system.GO_CACHE_DIR}': '${bamboo.cacheGo}'
|
||||
'${system.GO_PKG_CACHE_DIR}': '${bamboo.cacheGoPkg}'
|
||||
'key': 'MR'
|
||||
'other':
|
||||
'clean-working-dir': true
|
||||
'tasks':
|
||||
- 'checkout':
|
||||
'force-clean-build': true
|
||||
- 'script':
|
||||
'interpreter': 'SHELL'
|
||||
'scripts':
|
||||
- |
|
||||
#!/bin/sh
|
||||
|
||||
set -e -f -u -x
|
||||
set -e -f -u -x
|
||||
|
||||
# Explicitly checkout the revision that we need.
|
||||
git checkout "${bamboo.repository.revision.number}"
|
||||
# Explicitly checkout the revision that we need.
|
||||
git checkout "${bamboo.repository.revision.number}"
|
||||
|
||||
# Run the build with the specified channel.
|
||||
echo "${bamboo.gpgSecretKeyPart1}${bamboo.gpgSecretKeyPart2}"\
|
||||
| awk '{ gsub(/\\n/, "\n"); print; }'\
|
||||
| gpg --import --batch --yes
|
||||
# Run the build with the specified channel.
|
||||
echo "${bamboo.gpgSecretKeyPart1}${bamboo.gpgSecretKeyPart2}"\
|
||||
| awk '{ gsub(/\\n/, "\n"); print; }'\
|
||||
| gpg --import --batch --yes
|
||||
|
||||
make\
|
||||
CHANNEL=${bamboo.channel}\
|
||||
GPG_KEY_PASSPHRASE=${bamboo.gpgPassword}\
|
||||
FRONTEND_PREBUILT=1\
|
||||
PARALLELISM=1\
|
||||
VERBOSE=2\
|
||||
build-release
|
||||
# TODO(a.garipov): Use more fine-grained artifact rules.
|
||||
'artifacts':
|
||||
- 'name': 'AdGuardHome dists'
|
||||
'pattern': 'dist/**'
|
||||
'shared': true
|
||||
'required': true
|
||||
'requirements':
|
||||
- 'adg-docker': 'true'
|
||||
make\
|
||||
CHANNEL=${bamboo.channel}\
|
||||
GPG_KEY_PASSPHRASE=${bamboo.gpgPassword}\
|
||||
FRONTEND_PREBUILT=1\
|
||||
PARALLELISM=1\
|
||||
VERBOSE=2\
|
||||
build-release
|
||||
# TODO(a.garipov): Use more fine-grained artifact rules.
|
||||
'artifacts':
|
||||
- 'name': 'AdGuardHome dists'
|
||||
'pattern': 'dist/**'
|
||||
'shared': true
|
||||
'required': true
|
||||
'requirements':
|
||||
- 'adg-docker': 'true'
|
||||
|
||||
'Make and publish docker':
|
||||
'key': 'MPD'
|
||||
'other':
|
||||
'clean-working-dir': true
|
||||
'tasks':
|
||||
- 'checkout':
|
||||
'force-clean-build': true
|
||||
- 'script':
|
||||
'interpreter': 'SHELL'
|
||||
'scripts':
|
||||
- |
|
||||
#!/bin/sh
|
||||
'key': 'MPD'
|
||||
'other':
|
||||
'clean-working-dir': true
|
||||
'tasks':
|
||||
- 'checkout':
|
||||
'force-clean-build': true
|
||||
- 'script':
|
||||
'interpreter': 'SHELL'
|
||||
'scripts':
|
||||
- |
|
||||
#!/bin/sh
|
||||
|
||||
set -e -f -u -x
|
||||
set -e -f -u -x
|
||||
|
||||
COMMIT="${bamboo.repository.revision.number}"
|
||||
export COMMIT
|
||||
readonly COMMIT
|
||||
COMMIT="${bamboo.repository.revision.number}"
|
||||
export COMMIT
|
||||
readonly COMMIT
|
||||
|
||||
# Explicitly checkout the revision that we need.
|
||||
git checkout "$COMMIT"
|
||||
# Explicitly checkout the revision that we need.
|
||||
git checkout "$COMMIT"
|
||||
|
||||
# Install Qemu, create builder.
|
||||
docker version -f '{{ .Server.Experimental }}'
|
||||
docker buildx rm buildx-builder || :
|
||||
docker buildx create --name buildx-builder --driver docker-container\
|
||||
--use
|
||||
docker buildx inspect --bootstrap
|
||||
# Install Qemu, create builder.
|
||||
docker version -f '{{ .Server.Experimental }}'
|
||||
docker buildx rm buildx-builder || :
|
||||
docker buildx create --name buildx-builder --driver docker-container\
|
||||
--use
|
||||
docker buildx inspect --bootstrap
|
||||
|
||||
# Login to DockerHub.
|
||||
docker login -u="${bamboo.dockerHubUsername}"\
|
||||
-p="${bamboo.dockerHubPassword}"
|
||||
# Login to DockerHub.
|
||||
docker login -u="${bamboo.dockerHubUsername}"\
|
||||
-p="${bamboo.dockerHubPassword}"
|
||||
|
||||
# Boot the builder.
|
||||
docker buildx inspect --bootstrap
|
||||
# Boot the builder.
|
||||
docker buildx inspect --bootstrap
|
||||
|
||||
# Print Docker info.
|
||||
docker info
|
||||
# Print Docker info.
|
||||
docker info
|
||||
|
||||
# Prepare and push the build.
|
||||
env\
|
||||
CHANNEL="${bamboo.channel}"\
|
||||
DIST_DIR='dist'\
|
||||
DOCKER_IMAGE_NAME='adguard/adguardhome'\
|
||||
DOCKER_OUTPUT="type=image,name=adguard/adguardhome,push=true"\
|
||||
VERBOSE='1'\
|
||||
sh ./scripts/make/build-docker.sh
|
||||
'environment':
|
||||
DOCKER_CLI_EXPERIMENTAL=enabled
|
||||
'final-tasks':
|
||||
- 'clean'
|
||||
'requirements':
|
||||
- 'adg-docker': 'true'
|
||||
# Prepare and push the build.
|
||||
env\
|
||||
CHANNEL="${bamboo.channel}"\
|
||||
DIST_DIR='dist'\
|
||||
DOCKER_IMAGE_NAME='adguard/adguardhome'\
|
||||
DOCKER_OUTPUT="type=image,name=adguard/adguardhome,push=true"\
|
||||
VERBOSE='1'\
|
||||
sh ./scripts/make/build-docker.sh
|
||||
'environment':
|
||||
DOCKER_CLI_EXPERIMENTAL=enabled
|
||||
'final-tasks':
|
||||
- 'clean'
|
||||
'requirements':
|
||||
- 'adg-docker': 'true'
|
||||
|
||||
'Publish to static storage':
|
||||
'key': 'PUB'
|
||||
'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
|
||||
'key': 'PUB'
|
||||
'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
|
||||
set -e -f -u -x
|
||||
|
||||
cd ./dist/
|
||||
cd ./dist/
|
||||
|
||||
CHANNEL="${bamboo.channel}"
|
||||
export CHANNEL
|
||||
CHANNEL="${bamboo.channel}"
|
||||
export CHANNEL
|
||||
|
||||
../bamboo-deploy-publisher/deploy.sh adguard-home-"$CHANNEL"
|
||||
'final-tasks':
|
||||
- 'clean'
|
||||
'requirements':
|
||||
- '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'
|
||||
../bamboo-deploy-publisher/deploy.sh adguard-home-"$CHANNEL"
|
||||
'final-tasks':
|
||||
- 'clean'
|
||||
'requirements':
|
||||
- 'adg-docker': 'true'
|
||||
|
||||
'Publish to GitHub Releases':
|
||||
'key': 'PTGR'
|
||||
'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
|
||||
'key': 'PTGR'
|
||||
'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
|
||||
set -e -f -u -x
|
||||
|
||||
channel="${bamboo.channel}"
|
||||
readonly channel
|
||||
channel="${bamboo.channel}"
|
||||
readonly channel
|
||||
|
||||
if [ "$channel" != 'release' ] && [ "${channel}" != 'beta' ]
|
||||
then
|
||||
echo "don't publish to GitHub Releases for this channel"
|
||||
if [ "$channel" != 'release' ] && [ "${channel}" != 'beta' ]
|
||||
then
|
||||
echo "don't publish to GitHub Releases for this channel"
|
||||
|
||||
exit 0
|
||||
fi
|
||||
exit 0
|
||||
fi
|
||||
|
||||
cd ./dist/
|
||||
cd ./dist/
|
||||
|
||||
env\
|
||||
GITHUB_TOKEN="${bamboo.githubPublicRepoPassword}"\
|
||||
../bamboo-deploy-publisher/deploy.sh adguard-home-github
|
||||
'final-tasks':
|
||||
- 'clean'
|
||||
'requirements':
|
||||
- 'adg-docker': 'true'
|
||||
env\
|
||||
GITHUB_TOKEN="${bamboo.githubPublicRepoPassword}"\
|
||||
../bamboo-deploy-publisher/deploy.sh adguard-home-github
|
||||
'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.
|
||||
- 'cron': '0 42 13 ? * MON-FRI *'
|
||||
# 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.
|
||||
- 'cron': '0 42 13 ? * 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 release'
|
||||
'link-to-jira': true
|
||||
'create': 'manually'
|
||||
'delete':
|
||||
'after-deleted-days': 1
|
||||
'after-inactive-days': 30
|
||||
'integration':
|
||||
'push-on-success': false
|
||||
'merge-from': 'AdGuard Home - Build and publish 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'
|
||||
- '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'
|
||||
'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:6.3'
|
||||
# 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:6.3'
|
||||
# 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:6.7'
|
||||
# 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:6.7'
|
||||
|
||||
211
bamboo-specs/snapcraft.yaml
Normal file
211
bamboo-specs/snapcraft.yaml
Normal file
@@ -0,0 +1,211 @@
|
||||
---
|
||||
# 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:6.7'
|
||||
'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:6.7'
|
||||
'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:6.7'
|
||||
'snapcraftChannel': 'candidate'
|
||||
@@ -1,64 +1,64 @@
|
||||
---
|
||||
'version': 2
|
||||
'plan':
|
||||
'project-key': 'AGH'
|
||||
'key': 'AHBRTSPECS'
|
||||
'name': 'AdGuard Home - Build and run tests'
|
||||
'project-key': 'AGH'
|
||||
'key': 'AHBRTSPECS'
|
||||
'name': 'AdGuard Home - Build and run tests'
|
||||
'variables':
|
||||
'dockerGo': 'adguard/golang-ubuntu:6.3'
|
||||
'dockerGo': 'adguard/golang-ubuntu:6.7'
|
||||
|
||||
'stages':
|
||||
- 'Tests':
|
||||
'manual': false
|
||||
'final': false
|
||||
'jobs':
|
||||
- 'Test'
|
||||
- 'Tests':
|
||||
'manual': false
|
||||
'final': false
|
||||
'jobs':
|
||||
- 'Test'
|
||||
|
||||
'Test':
|
||||
'docker':
|
||||
'image': '${bamboo.dockerGo}'
|
||||
'volumes':
|
||||
'${system.YARN_DIR}': '${bamboo.cacheYarn}'
|
||||
'${system.GO_CACHE_DIR}': '${bamboo.cacheGo}'
|
||||
'${system.GO_PKG_CACHE_DIR}': '${bamboo.cacheGoPkg}'
|
||||
'key': 'TEST'
|
||||
'other':
|
||||
'clean-working-dir': true
|
||||
'tasks':
|
||||
- 'checkout':
|
||||
'force-clean-build': true
|
||||
- 'script':
|
||||
'interpreter': 'SHELL'
|
||||
'scripts':
|
||||
- |
|
||||
#!/bin/sh
|
||||
'docker':
|
||||
'image': '${bamboo.dockerGo}'
|
||||
'volumes':
|
||||
'${system.YARN_DIR}': '${bamboo.cacheYarn}'
|
||||
'${system.GO_CACHE_DIR}': '${bamboo.cacheGo}'
|
||||
'${system.GO_PKG_CACHE_DIR}': '${bamboo.cacheGoPkg}'
|
||||
'key': 'TEST'
|
||||
'other':
|
||||
'clean-working-dir': true
|
||||
'tasks':
|
||||
- 'checkout':
|
||||
'force-clean-build': true
|
||||
- 'script':
|
||||
'interpreter': 'SHELL'
|
||||
'scripts':
|
||||
- |
|
||||
#!/bin/sh
|
||||
|
||||
set -e -f -u -x
|
||||
set -e -f -u -x
|
||||
|
||||
make VERBOSE=1 ci go-tools lint
|
||||
'final-tasks':
|
||||
- 'clean'
|
||||
'requirements':
|
||||
- 'adg-docker': 'true'
|
||||
make VERBOSE=1 ci go-tools lint
|
||||
'final-tasks':
|
||||
- 'clean'
|
||||
'requirements':
|
||||
- 'adg-docker': 'true'
|
||||
|
||||
'branches':
|
||||
'create': 'for-pull-request'
|
||||
'delete':
|
||||
'after-deleted-days': 1
|
||||
'after-inactive-days': 5
|
||||
'integration':
|
||||
'push-on-success': false
|
||||
'merge-from': 'AdGuard Home - Build and run tests'
|
||||
'link-to-jira': true
|
||||
'create': 'for-pull-request'
|
||||
'delete':
|
||||
'after-deleted-days': 1
|
||||
'after-inactive-days': 5
|
||||
'integration':
|
||||
'push-on-success': false
|
||||
'merge-from': 'AdGuard Home - Build and run tests'
|
||||
'link-to-jira': true
|
||||
|
||||
'notifications':
|
||||
- 'events':
|
||||
- 'plan-status-changed'
|
||||
'recipients':
|
||||
- 'webhook':
|
||||
'name': 'Build webhook'
|
||||
'url': 'http://prod.jirahub.service.eu.consul/v1/webhook/bamboo'
|
||||
- 'events':
|
||||
- 'plan-status-changed'
|
||||
'recipients':
|
||||
- 'webhook':
|
||||
'name': 'Build webhook'
|
||||
'url': 'http://prod.jirahub.service.eu.consul/v1/webhook/bamboo'
|
||||
|
||||
'labels': []
|
||||
'other':
|
||||
'concurrent-build-plugin': 'system-default'
|
||||
'concurrent-build-plugin': 'system-default'
|
||||
|
||||
@@ -635,5 +635,6 @@
|
||||
"parental_control": "الرقابة الابويه",
|
||||
"safe_browsing": "تصفح آمن",
|
||||
"served_from_cache": "{{value}} <i>(يتم تقديمه من ذاكرة التخزين المؤقت)</i>",
|
||||
"form_error_password_length": "يجب أن تتكون كلمة المرور من {{value}} من الأحرف على الأقل"
|
||||
"form_error_password_length": "يجب أن تتكون كلمة المرور من {{value}} من الأحرف على الأقل",
|
||||
"protection_section_label": "الحماية"
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@
|
||||
"dns_allowlists": "Белыя спісы DNS",
|
||||
"dns_blocklists_desc": "AdGuard Home будзе блакаваць дамены з чорных спісаў.",
|
||||
"dns_allowlists_desc": "Дамены з белых спісаў DNS будуць дазволены, нават калі яны знаходзяцца ў любым з чорных спісаў.",
|
||||
"custom_filtering_rules": "Карыстацкія правілы фільтрацыі",
|
||||
"custom_filtering_rules": "Карыстальніцкія правілы фільтрацыі",
|
||||
"encryption_settings": "Налады шыфравання",
|
||||
"dhcp_settings": "Налады DHCP",
|
||||
"upstream_dns": "Upstream DNS-серверы",
|
||||
@@ -247,7 +247,7 @@
|
||||
"loading_table_status": "Загрузка...",
|
||||
"page_table_footer_text": "Старонка",
|
||||
"rows_table_footer_text": "радкоў",
|
||||
"updated_custom_filtering_toast": "Занесены змены ў карыстацкія правілы",
|
||||
"updated_custom_filtering_toast": "Карыстальніцкія правілы паспяхова захаваны",
|
||||
"rule_removed_from_custom_filtering_toast": "Карыстацкае правіла выдалена: {{rule}}",
|
||||
"rule_added_to_custom_filtering_toast": "Карыстацкае правіла дададзена: {{rule}}",
|
||||
"query_log_response_status": "Статус: {{value}}",
|
||||
@@ -475,7 +475,9 @@
|
||||
"setup_dns_notice": "Каб выкарыстоўваць <1>DNS-over-HTTPS</1> ці <1>DNS-over-TLS</1>, вам патрэбна <0>наладзіць шыфраванне</0> у наладах AdGuard Home.",
|
||||
"rewrite_added": "Правіла перанакіравання DNS для «{{key}}» паспяхова дададзена",
|
||||
"rewrite_deleted": "Правіла перанакіравання DNS для «{{key}}» паспяхова выдалена",
|
||||
"rewrite_updated": "Перазапіс DNS паспяхова абноўлены",
|
||||
"rewrite_add": "Дадаць правіла перанакіравання DNS",
|
||||
"rewrite_edit": "Рэдагаваць перазапіс DNS",
|
||||
"rewrite_not_found": "Не знойдзена правілаў перанакіравання DNS",
|
||||
"rewrite_confirm_delete": "Вы ўпэўнены, што хочаце выдаліць правіла перанакіравання DNS для «{{key}}»?",
|
||||
"rewrite_desc": "Дазваляе лёгка наладзіць карыстацкі DNS-адказ для пэўнага дамена.",
|
||||
@@ -568,7 +570,7 @@
|
||||
"check_desc": "Праверыць фільтрацыю імя хаста",
|
||||
"check": "Праверыць",
|
||||
"form_enter_host": "Увядзіце імя хаста",
|
||||
"filtered_custom_rules": "Адфільтраваны з дапамогай карыстацкіх правілаў фільтрацыі",
|
||||
"filtered_custom_rules": "Адфільтраваны з дапамогай карыстальніцкіх правіл фільтрацыі",
|
||||
"choose_from_list": "Абраць са спіса",
|
||||
"add_custom_list": "Дадаць свой спіс",
|
||||
"host_whitelisted": "Хост занесены ў белы спіс",
|
||||
@@ -642,5 +644,6 @@
|
||||
"anonymizer_notification": "<0>Заўвага:</0> Ананімізацыя IP уключана. Вы можаце адключыць яе ў <1>Агульных наладах</1>.",
|
||||
"confirm_dns_cache_clear": "Вы ўпэўнены, што хочаце ачысціць кэш DNS?",
|
||||
"cache_cleared": "Кэш DNS паспяхова ачышчаны",
|
||||
"clear_cache": "Ачысціць кэш"
|
||||
"clear_cache": "Ачысціць кэш",
|
||||
"protection_section_label": "Ахова"
|
||||
}
|
||||
|
||||
@@ -257,12 +257,12 @@
|
||||
"query_log_cleared": "Protokol dotazů byl úspěšně vymazán",
|
||||
"query_log_updated": "Protokol dotazů byl úspěšně aktualizován",
|
||||
"query_log_clear": "Vymazat protokoly dotazů",
|
||||
"query_log_retention": "Uchování protokolů dotazů",
|
||||
"query_log_retention": "Rotace protokolů dotazů",
|
||||
"query_log_enable": "Povolit protokol",
|
||||
"query_log_configuration": "Konfigurace protokolů",
|
||||
"query_log_disabled": "Protokol dotazu je zakázán a lze jej nakonfigurovat v <0>nastavení</0>",
|
||||
"query_log_strict_search": "Pro striktní vyhledávání použijte dvojité uvozovky",
|
||||
"query_log_retention_confirm": "Opravdu chcete změnit uchovávání protokolu dotazů? Pokud snížíte hodnotu intervalu, některá data budou ztracena",
|
||||
"query_log_retention_confirm": "Opravdu chcete změnit rotaci protokolu dotazů? Pokud snížíte hodnotu intervalu, některá data budou ztracena",
|
||||
"anonymize_client_ip": "Anonymizovat IP klienta",
|
||||
"anonymize_client_ip_desc": "Neukládat úplnou IP adresu klienta do protokolů a statistik",
|
||||
"dns_config": "Konfigurace DNS serveru",
|
||||
@@ -478,7 +478,9 @@
|
||||
"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_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_edit": "Upravit přesměrování DNS",
|
||||
"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_desc": "Umožňuje snadno nakonfigurovat vlastní DNS odezvy pro konkrétní název domény.",
|
||||
@@ -668,5 +670,11 @@
|
||||
"disable_notify_for_hours": "Vypnout ochranu na {{count}} hod.",
|
||||
"disable_notify_for_hours_plural": "Vypnout ochranu na {{count}} hod.",
|
||||
"disable_notify_until_tomorrow": "Vypnout ochranu do zítřka",
|
||||
"enable_protection_timer": "Ochrana bude zapnuta za {{time}}"
|
||||
"enable_protection_timer": "Ochrana bude zapnuta za {{time}}",
|
||||
"custom_retention_input": "Zadejte retenci v hodinách",
|
||||
"custom_rotation_input": "Zadejte rotaci v hodinách",
|
||||
"protection_section_label": "Ochrana",
|
||||
"log_and_stats_section_label": "Protokol dotazů a statistiky",
|
||||
"ignore_query_log": "Ignorovat tohoto klienta v protokolu dotazů",
|
||||
"ignore_statistics": "Ignorovat tohoto klienta ve statistikách"
|
||||
}
|
||||
|
||||
@@ -257,12 +257,12 @@
|
||||
"query_log_cleared": "Forespørgselsloggen er blevet ryddet",
|
||||
"query_log_updated": "Forespørgselsloggen er blevet opdateret",
|
||||
"query_log_clear": "Ryd forespørgselslogfiler",
|
||||
"query_log_retention": "Opbevar forespørgselslogger i",
|
||||
"query_log_retention": "Rotation af forespørgselslog",
|
||||
"query_log_enable": "Aktivér log",
|
||||
"query_log_configuration": "Opsætning af logger",
|
||||
"query_log_disabled": "Forespørgselsloggen er deaktiveret og kan opsættes i <0>indstillingerne</0>",
|
||||
"query_log_strict_search": "Brug dobbelt anførselstegn til stringent søgning",
|
||||
"query_log_retention_confirm": "Sikker på, at du vil ændre forespørgselsloggens opbevaringperiode? Mindskes intervalværdien, mistes data",
|
||||
"query_log_retention_confirm": "Sikker på, at forespørgselsloggens rotationstid skal ændres? Mindskes intervalværdien, mistes nogle data",
|
||||
"anonymize_client_ip": "Anonymisér klient-IP",
|
||||
"anonymize_client_ip_desc": "Gem ikke fuld klient IP-adresse i logfiler eller statistikker",
|
||||
"dns_config": "DNS-serveropsætning",
|
||||
@@ -478,7 +478,9 @@
|
||||
"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_deleted": "DNS-omskrivning for \"{{key}}\" blev slettet",
|
||||
"rewrite_updated": "DNS-omskrivning hermed opdateret",
|
||||
"rewrite_add": "Tilføj DNS-omskrivning",
|
||||
"rewrite_edit": "Redigér DNS-omskrivning",
|
||||
"rewrite_not_found": "Ingen DNS-omskrivninger fundet",
|
||||
"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.",
|
||||
@@ -668,5 +670,11 @@
|
||||
"disable_notify_for_hours": "Deaktivere beskyttelse i {{count}} time",
|
||||
"disable_notify_for_hours_plural": "Deaktivere beskyttelse i {{count}} timer",
|
||||
"disable_notify_until_tomorrow": "Deaktiver beskyttelse indtil i morgen",
|
||||
"enable_protection_timer": "Beskyttelse deaktiveres om {{time}}"
|
||||
"enable_protection_timer": "Beskyttelse deaktiveres om {{time}}",
|
||||
"custom_retention_input": "Angiv opbevaringstid i timer",
|
||||
"custom_rotation_input": "Angiv rotationstid i timer",
|
||||
"protection_section_label": "Beskyttelse",
|
||||
"log_and_stats_section_label": "Forespørgselslog og statistik",
|
||||
"ignore_query_log": "Ignorér denne klient i forespørgselslog",
|
||||
"ignore_statistics": "Ignorér denne klient i statistik"
|
||||
}
|
||||
|
||||
@@ -257,12 +257,12 @@
|
||||
"query_log_cleared": "Das Abfrageprotokoll wurde erfolgreich gelöscht",
|
||||
"query_log_updated": "Das Abfrageprotokoll wurde erfolgreich aktualisiert",
|
||||
"query_log_clear": "Abfrageprotokolle leeren",
|
||||
"query_log_retention": "Abfrageprotokolle aufbewahren",
|
||||
"query_log_retention": "Rotation der Abfrageprotokolle",
|
||||
"query_log_enable": "Protokoll aktivieren",
|
||||
"query_log_configuration": "Konfiguration der Protokolle",
|
||||
"query_log_disabled": "Das Abfrageprotokoll ist deaktiviert und kann in den <0>Einstellungen</0> konfiguriert werden.",
|
||||
"query_log_strict_search": "Doppelte Anführungszeichen für die strikte Suche verwenden",
|
||||
"query_log_retention_confirm": "Möchten Sie die Aufbewahrung des Abfrageprotokolls wirklich ändern? Wenn Sie den Zeitabstand verringern, gehen einige Daten verloren.",
|
||||
"query_log_retention_confirm": "Möchten Sie die Abfrageprotokollrotation wirklich ändern? Wenn Sie den Intervallwert verringern, gehen einige Daten verloren",
|
||||
"anonymize_client_ip": "Client-IP anonymisieren",
|
||||
"anonymize_client_ip_desc": "Vollständige IP-Adresse des Clients nicht in Protokollen und Statistiken speichern",
|
||||
"dns_config": "DNS-Serverkonfiguration",
|
||||
@@ -478,7 +478,9 @@
|
||||
"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_deleted": "DNS-Umschreibung für „{{key}}“ erfolgreich entfernt",
|
||||
"rewrite_updated": "DNS-Rewrite erfolgreich aktualisiert",
|
||||
"rewrite_add": "DNS-Umschreibung hinzufügen",
|
||||
"rewrite_edit": "DNS-Rewrite bearbeiten",
|
||||
"rewrite_not_found": "Keine DNS-Umschreibungen gefunden",
|
||||
"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.",
|
||||
@@ -668,5 +670,11 @@
|
||||
"disable_notify_for_hours": "Schutz für {{count}} Stunde deaktivieren",
|
||||
"disable_notify_for_hours_plural": "Schutz für {{count}} Stunden deaktivieren",
|
||||
"disable_notify_until_tomorrow": "Schutz bis morgen deaktivieren",
|
||||
"enable_protection_timer": "Der Schutz wird in {{time}} wieder aktiviert"
|
||||
"enable_protection_timer": "Der Schutz wird in {{time}} wieder aktiviert",
|
||||
"custom_retention_input": "Rückhaltezeit in Stunden eingeben",
|
||||
"custom_rotation_input": "Rotation in Stunden eingeben",
|
||||
"protection_section_label": "Schutz",
|
||||
"log_and_stats_section_label": "Abfrageprotokoll und Statistik",
|
||||
"ignore_query_log": "Diesen Client im Abfrageprotokoll ignorieren",
|
||||
"ignore_statistics": "Diesen Client in der Statistik ignorieren"
|
||||
}
|
||||
|
||||
@@ -478,7 +478,9 @@
|
||||
"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_deleted": "DNS rewrite for \"{{key}}\" successfully deleted",
|
||||
"rewrite_updated": "DNS rewrite successfully updated",
|
||||
"rewrite_add": "Add DNS rewrite",
|
||||
"rewrite_edit": "Edit DNS rewrite",
|
||||
"rewrite_not_found": "No DNS rewrites found",
|
||||
"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.",
|
||||
|
||||
@@ -257,12 +257,12 @@
|
||||
"query_log_cleared": "El registro de consultas se ha borrado correctamente",
|
||||
"query_log_updated": "El registro de consultas se ha actualizado correctamente",
|
||||
"query_log_clear": "Borrar registros de consultas",
|
||||
"query_log_retention": "Retención de registros de consultas",
|
||||
"query_log_retention": "Rotanción de registros de consultas",
|
||||
"query_log_enable": "Habilitar registro",
|
||||
"query_log_configuration": "Configuración de registros",
|
||||
"query_log_disabled": "El registro de consultas está deshabilitado y se puede configurar en la <0>configuración</0>",
|
||||
"query_log_strict_search": "Usar comillas dobles para una búsqueda estricta",
|
||||
"query_log_retention_confirm": "¿Estás seguro de que deseas cambiar la retención del registro de consultas? Si disminuye el valor del intervalo, se perderán algunos datos",
|
||||
"query_log_retention_confirm": "¿Está seguro de que deseas cambiar la rotación del registro de consultas? Si reduces el valor del intervalo, se perderán algunos datos",
|
||||
"anonymize_client_ip": "Anonimizar IP del cliente",
|
||||
"anonymize_client_ip_desc": "No guarda la dirección IP completa del cliente en registros o estadísticas",
|
||||
"dns_config": "Configuración del servidor DNS",
|
||||
@@ -478,7 +478,9 @@
|
||||
"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_deleted": "Reescritura DNS para \"{{key}}\" eliminado correctamente",
|
||||
"rewrite_updated": "Reconfiguración de DNS actualizada correctamente",
|
||||
"rewrite_add": "Añadir reescritura DNS",
|
||||
"rewrite_edit": "Editar reconfiguración de 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_desc": "Permite configurar fácilmente la respuesta DNS personalizada para un nombre de dominio específico.",
|
||||
@@ -668,5 +670,11 @@
|
||||
"disable_notify_for_hours": "Desactivar la protección por {{count}} hora",
|
||||
"disable_notify_for_hours_plural": "Desactivar la protección por {{count}} horas",
|
||||
"disable_notify_until_tomorrow": "Desactivar la protección hasta mañana",
|
||||
"enable_protection_timer": "La protección se activará en {{time}}"
|
||||
"enable_protection_timer": "La protección se activará en {{time}}",
|
||||
"custom_retention_input": "Ingresa la retención en horas",
|
||||
"custom_rotation_input": "Ingresa la rotación en horas",
|
||||
"protection_section_label": "Protección",
|
||||
"log_and_stats_section_label": "Registro de consultas y estadísticas",
|
||||
"ignore_query_log": "Ignorar este cliente en el registro de consultas",
|
||||
"ignore_statistics": "Ignorar este cliente en las estadísticas"
|
||||
}
|
||||
|
||||
@@ -268,6 +268,8 @@
|
||||
"blocking_mode_nxdomain": "NXDOMAIN: پاسخ با کُد NXDOMAIN",
|
||||
"blocking_mode_null_ip": "Null IP: پاسخ با آدرس آی پی صفر(0.0.0.0 برای A; :: برای AAAA)",
|
||||
"blocking_mode_custom_ip": "آی پی دستی: پاسخ با آدرس آی پی دستی تنظیم شده",
|
||||
"theme_light": "پوسته روشن",
|
||||
"theme_dark": "پوسته تیره",
|
||||
"upstream_dns_client_desc": "اگر این فیلد را خالی نگه دارید، AdGuard Home از سرور پیکربندی شده در <0> تنظیماتDNS </0> استفاده می کند.",
|
||||
"tracker_source": "منبع ردیاب",
|
||||
"source_label": "منبع",
|
||||
@@ -438,7 +440,9 @@
|
||||
"setup_dns_notice": "به منظور استفاده از <1>DNS-over-HTTPS</1> یا <1>DNS-over-TLS</1>، شما نیاز به <0>پیکربندی رمزگذاری</0> در تنظیمات AdGuard Home دارید.",
|
||||
"rewrite_added": "بازنویسی DNS برای \"{{key}}\" با موفقیت اضافه شد",
|
||||
"rewrite_deleted": "بازنویسی DNS برای \"{{key}}\" با موفقیت حذف شد",
|
||||
"rewrite_updated": "بازنویسی DNS با موفقیت به روز شد",
|
||||
"rewrite_add": "افزودن بازنویسی DNS",
|
||||
"rewrite_edit": "بازنویسی DNS را ویرایش کنید",
|
||||
"rewrite_not_found": "بازنویسی DNS یافت نشد",
|
||||
"rewrite_confirm_delete": "آیا واقعا میخواهید بازنویسی DNS برای \"{{key}}\" را حذف کنید؟",
|
||||
"rewrite_desc": "به آسانی اجازه پیکربندی پاسخ DNS دستی برای یک نام دامنه خاص را می دهد.",
|
||||
@@ -567,5 +571,6 @@
|
||||
"use_saved_key": "از کلید ذخیره شده قبلی استفاده کنید",
|
||||
"parental_control": "نظارت والدین",
|
||||
"safe_browsing": "وب گردی اَمن",
|
||||
"form_error_password_length": "رمزعبور باید حداقل {{value}} کاراکتر باشد."
|
||||
"form_error_password_length": "رمزعبور باید حداقل {{value}} کاراکتر باشد.",
|
||||
"protection_section_label": "حفاظت"
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@
|
||||
"request_details": "Pyynnön tiedot",
|
||||
"client_details": "Päätelaitteen tiedot",
|
||||
"details": "Yksityiskohdat",
|
||||
"back": "Takaisin",
|
||||
"back": "Palaa takaisin",
|
||||
"dashboard": "Tila",
|
||||
"settings": "Asetukset",
|
||||
"filters": "Suodattimet",
|
||||
@@ -146,8 +146,8 @@
|
||||
"no_servers_specified": "Palvelimia ei ole määritetty",
|
||||
"general_settings": "Yleiset asetukset",
|
||||
"dns_settings": "DNS-asetukset",
|
||||
"dns_blocklists": "DNS-estolistat",
|
||||
"dns_allowlists": "DNS-sallittujen listat",
|
||||
"dns_blocklists": "DNS-estot",
|
||||
"dns_allowlists": "DNS-sallinnat",
|
||||
"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.",
|
||||
"custom_filtering_rules": "Omat suodatussäännöt",
|
||||
@@ -222,7 +222,7 @@
|
||||
"all_lists_up_to_date_toast": "Kaikki listat ovat ajan tasalla",
|
||||
"updated_upstream_dns_toast": "Ylävirtojen palvelimet tallennettiin",
|
||||
"dns_test_ok_toast": "Määritetyt DNS-palvelimet toimivat oikein",
|
||||
"dns_test_not_ok_toast": "Palvelin \"{{key}}\": ei voitu käyttää, tarkista sen oikeinkirjoitus",
|
||||
"dns_test_not_ok_toast": "Palvelin \"{{key}}\": Ei voitu käyttää, tarkista oikeinkirjoitus",
|
||||
"dns_test_warning_toast": "Datavuon \"{{key}}\" ei vastaa testipyyntöihin eikä välttämättä toimi kunnolla",
|
||||
"unblock": "Salli",
|
||||
"block": "Estä",
|
||||
@@ -257,12 +257,12 @@
|
||||
"query_log_cleared": "Pyyntöhistorian tyhjennys onnistui",
|
||||
"query_log_updated": "Pyyntöhistorian päivitys onnistui",
|
||||
"query_log_clear": "Tyhjennä pyyntöhistoria",
|
||||
"query_log_retention": "Pyyntöhistorian säilytys",
|
||||
"query_log_retention": "Kyselylokien kierto",
|
||||
"query_log_enable": "Käytä historiaa",
|
||||
"query_log_configuration": "Historian määritys",
|
||||
"query_log_disabled": "Pyyntöhistoria ei ole käytössä. Voit ottaa sen käyttöön <0>asetuksissa</0>",
|
||||
"query_log_strict_search": "Käytä tarkalle haulle lainausmerkkejä",
|
||||
"query_log_retention_confirm": "Haluatko varmasti muuttaa pyyntöhistoriasi säilytysaikaa? Jos lyhennät aikaa, joitakin tietoja menetetään",
|
||||
"query_log_retention_confirm": "Haluatko varmasti muuttaa kyselylokin kiertoa? Jos pienennät intervalliarvoa, osa tiedoista menetetään",
|
||||
"anonymize_client_ip": "Piilota päätelaitteen IP-osoite",
|
||||
"anonymize_client_ip_desc": "Älä tallenna päätelaitteen täydellistä IP-osoitetta historiaan ja tilastoihin.",
|
||||
"dns_config": "DNS-palvelimen määritys",
|
||||
@@ -478,7 +478,9 @@
|
||||
"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_deleted": "Kohteen \"{{key}}\" DNS-uudelleenohjaus poistettiin",
|
||||
"rewrite_updated": "DNS-uudelleenohjaukset päivitettiin",
|
||||
"rewrite_add": "Lisää DNS-uudelleenohjaus",
|
||||
"rewrite_edit": "Muokkaa DNS-uudelleenohjausta",
|
||||
"rewrite_not_found": "DNS-uudelleenohjauksia ei löytynyt",
|
||||
"rewrite_confirm_delete": "Haluatko varmasti poistaa DNS-uudelleenohjauksen kohteelle \"{{key}}\"?",
|
||||
"rewrite_desc": "Mahdollistaa oman DNS-vastauksen helpon määrityksen tietylle verkkotunnukselle.",
|
||||
@@ -627,7 +629,7 @@
|
||||
"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.",
|
||||
"filter_category_general": "Yleiset",
|
||||
"filter_category_security": "Turvallisuus",
|
||||
"filter_category_security": "Tietoturva",
|
||||
"filter_category_regional": "Alueelliset",
|
||||
"filter_category_other": "Muut",
|
||||
"filter_category_general_desc": "Listat, jotka estävät seurannan ja mainokset useimmilla laitteilla",
|
||||
@@ -668,5 +670,11 @@
|
||||
"disable_notify_for_hours": "Poista suojaus käytöstä {{count}} tunniksi",
|
||||
"disable_notify_for_hours_plural": "Poista suojaus käytöstä {{count}} tunniksi",
|
||||
"disable_notify_until_tomorrow": "Poista suojaus käytöstä huomiseen asti",
|
||||
"enable_protection_timer": "Suojaus otetaan käyttöön {{time}} kuluttua"
|
||||
"enable_protection_timer": "Suojaus otetaan käyttöön {{time}} kuluttua",
|
||||
"custom_retention_input": "Syötä säilytysaika tunteina",
|
||||
"custom_rotation_input": "Syötä uudistusaika tunteina",
|
||||
"protection_section_label": "Suojaus",
|
||||
"log_and_stats_section_label": "Kyselyhistoria ja tilastot",
|
||||
"ignore_query_log": "Älä huomioi tätä päätettä kyselyhistoriassa",
|
||||
"ignore_statistics": "Älä huomioi tätä päätettä tilastoissa"
|
||||
}
|
||||
|
||||
@@ -257,12 +257,12 @@
|
||||
"query_log_cleared": "Le journal des requêtes a été effacé",
|
||||
"query_log_updated": "Le journal des requêtes a été mis à jour",
|
||||
"query_log_clear": "Effacer journal des requêtes",
|
||||
"query_log_retention": "Rétention du journal des requêtes",
|
||||
"query_log_retention": "Rotation des journaux de requêtes",
|
||||
"query_log_enable": "Activer le journal",
|
||||
"query_log_configuration": "Configuration du journal",
|
||||
"query_log_disabled": "Le journal des requêtes est désactivé et peut être configuré dans les <0>paramètres</0>",
|
||||
"query_log_strict_search": "Utilisez les doubles guillemets pour une recherche stricte",
|
||||
"query_log_retention_confirm": "Êtes-vous sûr de vouloir modifier la rétention des journaux de requêtes ? Si vous diminuez la valeur de l'intervalle, certaines données seront perdues",
|
||||
"query_log_retention_confirm": "Êtes-vous sûr de souhaiter modifier la rotation des journaux de requêtes ? Si vous diminuez la valeur de l'intervalle, certaines données seront perdues",
|
||||
"anonymize_client_ip": "Anonymiser l’IP du client",
|
||||
"anonymize_client_ip_desc": "Ne pas enregistrer l’adresse IP complète du client dans les journaux et statistiques",
|
||||
"dns_config": "Configuration du serveur DNS",
|
||||
@@ -478,7 +478,9 @@
|
||||
"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_deleted": "Réécriture DNS pour « {{key}} » supprimée",
|
||||
"rewrite_updated": "Réécriture DNS mise à jour",
|
||||
"rewrite_add": "Ajouter une réécriture DNS",
|
||||
"rewrite_edit": "Modifier la réécriture DNS",
|
||||
"rewrite_not_found": "Aucune réécriture DNS trouvée",
|
||||
"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.",
|
||||
@@ -668,5 +670,11 @@
|
||||
"disable_notify_for_hours": "Désactiver la protection pendant {{count}} heure",
|
||||
"disable_notify_for_hours_plural": "Désactiver la protection pendant {{count}} heures",
|
||||
"disable_notify_until_tomorrow": "Désactiver la protection jusqu'à demain",
|
||||
"enable_protection_timer": "La protection sera activée dans {{time}}"
|
||||
"enable_protection_timer": "La protection sera activée dans {{time}}",
|
||||
"custom_retention_input": "Saisir la rétention en heures",
|
||||
"custom_rotation_input": "Saisir la rotation en heures",
|
||||
"protection_section_label": "Protection",
|
||||
"log_and_stats_section_label": "Journal des requêtes et statistiques",
|
||||
"ignore_query_log": "Ignorer ce client dans le journal des requêtes",
|
||||
"ignore_statistics": "Ignorer ce client dans les statistiques"
|
||||
}
|
||||
|
||||
@@ -257,12 +257,12 @@
|
||||
"query_log_cleared": "Zapisnik upita je uspješno uklonjen",
|
||||
"query_log_updated": "Zapisnik upita je uspješno ažuriran",
|
||||
"query_log_clear": "Očisti zapisnik upita",
|
||||
"query_log_retention": "Spremanje zapisnika upita",
|
||||
"query_log_retention": "Rotacija dnevnika upita",
|
||||
"query_log_enable": "Omogući zapise",
|
||||
"query_log_configuration": "Postavke zapisa",
|
||||
"query_log_disabled": "Zapisnik upita je onemogućen i može se postaviti u <0>postavkama</0>",
|
||||
"query_log_strict_search": "Koristite dvostruke navodnike za strogo pretraživanje",
|
||||
"query_log_retention_confirm": "Jeste li sigurni da želite promijeniti zadržavanje zapisnika upita? Ako smanjite vrijednost intervala, neki će podaci biti izgubljeni",
|
||||
"query_log_retention_confirm": "Jeste li sigurni da želite promijeniti rotaciju dnevnika upita? Ako smanjite vrijednost intervala, neki će se podaci izgubiti",
|
||||
"anonymize_client_ip": "Anonimiraj IP klijenta",
|
||||
"anonymize_client_ip_desc": "Ne spremajte cijelu IP adresu klijenta u zapisnike i statistike",
|
||||
"dns_config": "DNS postavke poslužitelja",
|
||||
@@ -478,7 +478,9 @@
|
||||
"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_deleted": "DNS prijepis za \"{{key}}\" je uspješno uklonjen",
|
||||
"rewrite_updated": "Prepisivanje DNS-a uspješno ažurirano",
|
||||
"rewrite_add": "Dodaj DNS prijepis",
|
||||
"rewrite_edit": "Uredite prepisivanje DNS-a",
|
||||
"rewrite_not_found": "Nema DNS prijepisa",
|
||||
"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.",
|
||||
@@ -668,5 +670,11 @@
|
||||
"disable_notify_for_hours": "Isključi zaštitu na {{count}} sati",
|
||||
"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 omogućena u {{time}}"
|
||||
"enable_protection_timer": "Zaštita će biti omogućena u {{time}}",
|
||||
"custom_retention_input": "Unesite zadržavanje u satima",
|
||||
"custom_rotation_input": "Unesite rotaciju u satima",
|
||||
"protection_section_label": "Zaštita",
|
||||
"log_and_stats_section_label": "Zapisnik upita i statistika",
|
||||
"ignore_query_log": "Zanemari ovog klijenta u zapisniku upita",
|
||||
"ignore_statistics": "Ignorirajte ovog klijenta u statistici"
|
||||
}
|
||||
|
||||
@@ -167,6 +167,7 @@
|
||||
"enabled_parental_toast": "Szülői felügyelet engedélyezve",
|
||||
"disabled_safe_search_toast": "Biztonságos keresés letiltva",
|
||||
"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",
|
||||
"name_table_header": "Név",
|
||||
"list_url_table_header": "Lista URL-je",
|
||||
@@ -290,6 +291,8 @@
|
||||
"rate_limit": "Kérések korlátozása",
|
||||
"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_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.",
|
||||
"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",
|
||||
@@ -475,7 +478,9 @@
|
||||
"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_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_edit": "DNS újraírás szerkesztése",
|
||||
"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_desc": "Lehetővé teszi, hogy egyszerűen beállítson egyéni DNS választ egy adott domain névhez.",
|
||||
@@ -523,6 +528,10 @@
|
||||
"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_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_plural": "{{count}} óra",
|
||||
"filters_configuration": "Szűrők beállításai",
|
||||
@@ -642,5 +651,30 @@
|
||||
"anonymizer_notification": "<0>Megjegyzés:</0> Az IP anonimizálás engedélyezve van. Az <1>Általános beállításoknál letilthatja</1> .",
|
||||
"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",
|
||||
"clear_cache": "Gyorsítótár törlése"
|
||||
"clear_cache": "Gyorsítótár törlése",
|
||||
"make_static": "Statikussá tétel",
|
||||
"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"
|
||||
}
|
||||
|
||||
@@ -474,7 +474,9 @@
|
||||
"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_deleted": "DNS rewrite untuk \"{{key}}\" berhasil dihapus",
|
||||
"rewrite_updated": "Penulisan ulang DNS berhasil diperbarui",
|
||||
"rewrite_add": "Tambah DNS rewrite",
|
||||
"rewrite_edit": "Edit penulisan ulang DNS",
|
||||
"rewrite_not_found": "Tidak ada DNS rewrite ditemukan",
|
||||
"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.",
|
||||
@@ -641,5 +643,6 @@
|
||||
"anonymizer_notification": "<0>Catatan:</0> Anonimisasi IP diaktifkan. Anda dapat menonaktifkannya di <1>Pengaturan umum</1> .",
|
||||
"confirm_dns_cache_clear": "Apakah Anda yakin ingin menghapus cache DNS?",
|
||||
"cache_cleared": "Cache DNS berhasil dibersihkan",
|
||||
"clear_cache": "Hapus cache"
|
||||
"clear_cache": "Hapus cache",
|
||||
"protection_section_label": "Perlindungan"
|
||||
}
|
||||
|
||||
@@ -257,12 +257,12 @@
|
||||
"query_log_cleared": "Il registro richieste è stato correttamente cancellato",
|
||||
"query_log_updated": "Il registro richieste è stato correttamente aggiornato",
|
||||
"query_log_clear": "Cancella registri richieste",
|
||||
"query_log_retention": "Conservazione dei registri richieste",
|
||||
"query_log_retention": "Rotazione dei registri richieste",
|
||||
"query_log_enable": "Attiva registro",
|
||||
"query_log_configuration": "Configurazione registri",
|
||||
"query_log_disabled": "Il registro richieste è stato disattivato e può essere configurata dalle <0>impostazioni</0>",
|
||||
"query_log_strict_search": "Utilizzare le doppie virgolette per una ricerca precisa",
|
||||
"query_log_retention_confirm": "Sei sicuro di voler modificare il registro delle richieste? Se il valore di intervallo dovesse diminuire, alcuni dati andranno persi",
|
||||
"query_log_retention_confirm": "Sei sicuro di voler modificare il registro delle richieste? Se si riduce il valore dell'intervallo, alcuni dati andranno persi",
|
||||
"anonymize_client_ip": "Anonimizza client IP",
|
||||
"anonymize_client_ip_desc": "Non salvare l'indirizzo IP completo del client nel registro o nelle statistiche",
|
||||
"dns_config": "Configurazione server DNS",
|
||||
@@ -478,7 +478,9 @@
|
||||
"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_deleted": "La riscrittura DNS per \"{{key}}\" è stata eliminata correttamente",
|
||||
"rewrite_updated": "Riscrittura DNS aggiornata correttamente",
|
||||
"rewrite_add": "Aggiungi la riscrittura DNS",
|
||||
"rewrite_edit": "Modifica della riscrittura DNS",
|
||||
"rewrite_not_found": "Nessuna riscrittura DNS trovata",
|
||||
"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.",
|
||||
@@ -668,5 +670,11 @@
|
||||
"disable_notify_for_hours": "Disattiva la protezione per {{count}} ora",
|
||||
"disable_notify_for_hours_plural": "Disattiva la protezione per {{count}} ore",
|
||||
"disable_notify_until_tomorrow": "Disattiva la protezione fino a domani",
|
||||
"enable_protection_timer": "La protezione verrà attivata in {{time}}"
|
||||
"enable_protection_timer": "La protezione verrà attivata in {{time}}",
|
||||
"custom_retention_input": "Inserisci la conservazione in ore",
|
||||
"custom_rotation_input": "Inserisci la rotazione in ore",
|
||||
"protection_section_label": "Protezione",
|
||||
"log_and_stats_section_label": "Registro richieste e statistiche",
|
||||
"ignore_query_log": "Ignora questo client nel registro delle richieste",
|
||||
"ignore_statistics": "Ignora questo cliente nelle statistiche"
|
||||
}
|
||||
|
||||
@@ -257,12 +257,12 @@
|
||||
"query_log_cleared": "クエリ・ログの消去に成功しました",
|
||||
"query_log_updated": "クエリ・ログの更新が成功しました",
|
||||
"query_log_clear": "クエリ・ログを消去する",
|
||||
"query_log_retention": "クエリ・ログの保持",
|
||||
"query_log_retention": "クエリ・ログのローテーション",
|
||||
"query_log_enable": "ログを有効にする",
|
||||
"query_log_configuration": "ログ設定",
|
||||
"query_log_disabled": "クエリ・ログは無効になっており、<0>設定</0>で構成できます",
|
||||
"query_log_strict_search": "完全一致検索には二重引用符を使用します",
|
||||
"query_log_retention_confirm": "クエリ・ログの保持を変更してもよろしいですか? 期間を短くすると、一部のデータが失われます",
|
||||
"query_log_retention_confirm": "クエリ・ログのローテーションを変更してもよろしいですか? 間隔の値を減らすと、一部のデータが失われます",
|
||||
"anonymize_client_ip": "クライアントIPを匿名化する",
|
||||
"anonymize_client_ip_desc": "ログと統計にクライアントのフルIPアドレスを保存しないようにします。",
|
||||
"dns_config": "DNSサーバ設定",
|
||||
@@ -478,7 +478,9 @@
|
||||
"setup_dns_notice": "<1>DNS-over-HTTPS</1>または<1>DNS-over-TLS</1>を使用するには、AdGuard Home 設定の<0>暗号化設定</0>が必要です。",
|
||||
"rewrite_added": "\"{{key}}\" のDNS書き換え情報を追加完了しました",
|
||||
"rewrite_deleted": "\"{{key}}\" のDNS書き換え情報を削除完了しました",
|
||||
"rewrite_updated": "DNS rewrite を更新完了しました。",
|
||||
"rewrite_add": "DNS書き換え情報を追加する",
|
||||
"rewrite_edit": "DNS rewrite を編集する",
|
||||
"rewrite_not_found": "DNS書き換え情報はありません",
|
||||
"rewrite_confirm_delete": "\"{{key}}\" のDNS書き換え情報を削除してもよろしいですか?",
|
||||
"rewrite_desc": "特定のドメイン名に対するDNS応答を簡単にカスタマイズすることを可能にします。",
|
||||
@@ -668,5 +670,11 @@
|
||||
"disable_notify_for_hours": "保護を {{count}} 時間無効にする",
|
||||
"disable_notify_for_hours_plural": "保護を {{count}} 時間無効にする",
|
||||
"disable_notify_until_tomorrow": "明日まで保護を無効にする",
|
||||
"enable_protection_timer": "保護は後 {{time}} で有効になります"
|
||||
"enable_protection_timer": "保護は後 {{time}} で有効になります",
|
||||
"custom_retention_input": "保持期間を入力してください(時間単位)",
|
||||
"custom_rotation_input": "ローテーションを入力してください(時間単位)",
|
||||
"protection_section_label": "AdGuardによる保護",
|
||||
"log_and_stats_section_label": "クエリ・ログと統計情報",
|
||||
"ignore_query_log": "クエリ・ログでこのクライアントを無視する",
|
||||
"ignore_statistics": "統計でこのクライアントを無視する"
|
||||
}
|
||||
|
||||
@@ -257,12 +257,12 @@
|
||||
"query_log_cleared": "쿼리 로그를 성공적으로 초기화했습니다",
|
||||
"query_log_updated": "질의 로그가 성공적으로 업데이트되었습니다",
|
||||
"query_log_clear": "쿼리 로그 비우기",
|
||||
"query_log_retention": "쿼리 로그 저장 기간",
|
||||
"query_log_retention": "쿼리 로그 로테이션",
|
||||
"query_log_enable": "로그 활성화",
|
||||
"query_log_configuration": "로그 구성",
|
||||
"query_log_disabled": "쿼리 로그가 비활성화되어 있으며 <0>설정</0>에서 설정할 수 있습니다",
|
||||
"query_log_strict_search": "검색을 제한하려면 쌍따옴표를 사용해주세요",
|
||||
"query_log_retention_confirm": "정말로 쿼리 로그 저장 기간을 변경하시겠습니까? 저장 주기를 낮출 경우, 일부 데이터가 손실됩니다",
|
||||
"query_log_retention_confirm": "쿼리 로그 로테이션을 변경하시겠습니까? 간격 값을 줄이면 일부 데이터가 손실됩니다.",
|
||||
"anonymize_client_ip": "클라이언트 IP 익명화",
|
||||
"anonymize_client_ip_desc": "클라이언트의 전체 IP 주소를 로그와 통계에 저장하저장하지 마세요",
|
||||
"dns_config": "DNS 서버 설정",
|
||||
@@ -478,7 +478,9 @@
|
||||
"setup_dns_notice": "<1>DNS-over-HTTPS</1> 또는 <1>DNS-over-TLS를</1> 사용하려면 AdGuard Home 설정에서 <0>암호화를 구성해야 합니다.</0>",
|
||||
"rewrite_added": "'{{key}}'에 대한 DNS 수정 정보를 성공적으로 추가 됩니다",
|
||||
"rewrite_deleted": "'{{key}}'에 대한 DNS 수정 정보를 성공적으로 삭제 됩니다",
|
||||
"rewrite_updated": "DNS 다시 쓰기 업데이트 완료",
|
||||
"rewrite_add": "DNS 변환 정보를 추가합니다",
|
||||
"rewrite_edit": "DNS 다시 쓰기 편집",
|
||||
"rewrite_not_found": "DNS 변경 정보를 찾을 수 없습니다",
|
||||
"rewrite_confirm_delete": "'{{key}}'에 대한 DNS 변경 정보를 삭제하시겠습니까?",
|
||||
"rewrite_desc": "특정 도메인 이름에 대한 사용자 지정 DNS 응답을 쉽게 구성할 수 있습니다.",
|
||||
@@ -668,5 +670,11 @@
|
||||
"disable_notify_for_hours": "{{count}}시간 동안 보호 기능 비활성화",
|
||||
"disable_notify_for_hours_plural": "{{count}}시간 동안 보호 기능 비활성화",
|
||||
"disable_notify_until_tomorrow": "내일까지 보호 기능 비활성화",
|
||||
"enable_protection_timer": "{{time}}에 보호 기능이 활성화됩니다."
|
||||
"enable_protection_timer": "{{time}}에 보호 기능이 활성화됩니다.",
|
||||
"custom_retention_input": "시간 단위로 보존 기간 입력",
|
||||
"custom_rotation_input": "시간 단위로 로테이션 입력",
|
||||
"protection_section_label": "보호",
|
||||
"log_and_stats_section_label": "쿼리 로그 및 통계",
|
||||
"ignore_query_log": "쿼리 로그에서 이 클라이언트 무시",
|
||||
"ignore_statistics": "통계에서 이 클라이언트 무시"
|
||||
}
|
||||
|
||||
@@ -257,12 +257,12 @@
|
||||
"query_log_cleared": "Het query logboek is succesvol geleegd",
|
||||
"query_log_updated": "Het query logboek is succesvol bijgewerkt",
|
||||
"query_log_clear": "Leeg query logs",
|
||||
"query_log_retention": "Query logs bewaartermijn",
|
||||
"query_log_retention": "Query logs rotatie",
|
||||
"query_log_enable": "Log bestanden inschakelen",
|
||||
"query_log_configuration": "Logbestanden instellingen",
|
||||
"query_log_disabled": "Het query logboek is uitgeschakeld en kan worden geconfigureerd in de <0>instellingen</0>",
|
||||
"query_log_strict_search": "Gebruik dubbele aanhalingstekens voor strikt zoeken",
|
||||
"query_log_retention_confirm": "Weet u zeker dat u de bewaartermijn van het query logboek wilt wijzigen? Als u de intervalwaarde verlaagt, gaan sommige gegevens verloren",
|
||||
"query_log_retention_confirm": "Weet u zeker dat u de rotatie van het querylogboek wilt wijzigen? Als u de intervalwaarde verlaagt, gaan sommige gegevens verloren",
|
||||
"anonymize_client_ip": "Cliënt IP anonimiseren",
|
||||
"anonymize_client_ip_desc": "Het volledige IP-adres van de cliënt niet opnemen in logboeken en statistiekbestanden",
|
||||
"dns_config": "DNS-server configuratie",
|
||||
@@ -478,7 +478,9 @@
|
||||
"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_deleted": "DNS-herschrijving voor \"{{key}}\" met succes verwijderd",
|
||||
"rewrite_updated": "DNS-herschrijven succesvol bijgewerkt",
|
||||
"rewrite_add": "DNS-herschrijving toevoegen",
|
||||
"rewrite_edit": "DNS-herschrijven bewerken",
|
||||
"rewrite_not_found": "Geen DNS-herschrijving gevonden",
|
||||
"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.",
|
||||
@@ -668,5 +670,11 @@
|
||||
"disable_notify_for_hours": "Beveiliging uitschakelen voor {{count}} uur",
|
||||
"disable_notify_for_hours_plural": "Beveiliging uitschakelen voor {{count}} uren",
|
||||
"disable_notify_until_tomorrow": "Beveiliging uitschakelen tot morgen",
|
||||
"enable_protection_timer": "Bescherming wordt ingeschakeld over {{time}}"
|
||||
"enable_protection_timer": "Bescherming wordt ingeschakeld over {{time}}",
|
||||
"custom_retention_input": "Voer retentie in uren in",
|
||||
"custom_rotation_input": "Voer rotatie in uren in",
|
||||
"protection_section_label": "Bescherming",
|
||||
"log_and_stats_section_label": "Aanvragenlogboek en statistieken",
|
||||
"ignore_query_log": "Deze client negeren in het aanvragenlogboek",
|
||||
"ignore_statistics": "Deze client negeren in de statistieken"
|
||||
}
|
||||
|
||||
@@ -282,6 +282,8 @@
|
||||
"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",
|
||||
"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>.",
|
||||
"tracker_source": "Sporerkilde",
|
||||
"source_label": "Kilde",
|
||||
@@ -455,7 +457,9 @@
|
||||
"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_deleted": "DNS-omdirigeringen for «{{key}}» ble vellykket slettet",
|
||||
"rewrite_updated": "DNS-omskriving ble oppdatert",
|
||||
"rewrite_add": "Legg til DNS-omdirigering",
|
||||
"rewrite_edit": "Rediger DNS-omskriving",
|
||||
"rewrite_not_found": "Ingen DNS-omdirigeringer ble funnet",
|
||||
"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.",
|
||||
@@ -614,5 +618,6 @@
|
||||
"use_saved_key": "Bruk den tidligere lagrede nøkkelen",
|
||||
"parental_control": "Foreldrekontroll",
|
||||
"safe_browsing": "Sikker surfing",
|
||||
"served_from_cache": "{{value}} <i>(formidlet fra mellomlageret)</i>"
|
||||
"served_from_cache": "{{value}} <i>(formidlet fra mellomlageret)</i>",
|
||||
"protection_section_label": "Beskyttelse"
|
||||
}
|
||||
|
||||
@@ -167,6 +167,7 @@
|
||||
"enabled_parental_toast": "Włączona Kontrola Rodzicielska",
|
||||
"disabled_safe_search_toast": "Wyłączone bezpieczne wyszukiwanie",
|
||||
"enabled_save_search_toast": "Włączone bezpieczne wyszukiwanie",
|
||||
"updated_save_search_toast": "Zaktualizowano ustawienia bezpiecznego wyszukiwania",
|
||||
"enabled_table_header": "Włączone",
|
||||
"name_table_header": "Nazwa",
|
||||
"list_url_table_header": "Adres URL listy",
|
||||
@@ -221,7 +222,7 @@
|
||||
"all_lists_up_to_date_toast": "Wszystkie listy są już aktualne",
|
||||
"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_not_ok_toast": "Serwer \"{{key}}\": nie można go użyć, sprawdź, czy napisałeś go poprawnie",
|
||||
"dns_test_not_ok_toast": "Serwer \"{{key}}\": nie może być użyte, sprawdź, czy zapisano go poprawnie",
|
||||
"dns_test_warning_toast": "Upstream \"{{key}}\" nie odpowiada na zapytania testowe i może nie działać prawidłowo",
|
||||
"unblock": "Odblokuj",
|
||||
"block": "Zablokuj",
|
||||
@@ -256,12 +257,12 @@
|
||||
"query_log_cleared": "Dziennik zapytań został pomyślnie wyczyszczony",
|
||||
"query_log_updated": "Dziennik zapytań został zaktualizowany",
|
||||
"query_log_clear": "Wyczyść dzienniki zapytań",
|
||||
"query_log_retention": "Przechowywanie dzienników zapytań",
|
||||
"query_log_retention": "Rotacja dzienników zapytań",
|
||||
"query_log_enable": "Włącz dziennik",
|
||||
"query_log_configuration": "Konfiguracja dzienników",
|
||||
"query_log_disabled": "Dziennik zapytań jest wyłączony i można go skonfigurować w <0>ustawieniach</0>",
|
||||
"query_log_strict_search": "Używaj podwójnych cudzysłowów do ścisłego wyszukiwania",
|
||||
"query_log_retention_confirm": "Czy na pewno chcesz zmienić sposób przechowywania dziennika zapytań? Jeśli zmniejszysz wartość interwału, niektóre dane zostaną utracone",
|
||||
"query_log_retention_confirm": "Czy na pewno chcesz zmienić rotację dziennika zapytań? Jeśli zmniejszysz wartość interwału, niektóre dane zostaną utracone",
|
||||
"anonymize_client_ip": "Anonimizuj adres IP klienta",
|
||||
"anonymize_client_ip_desc": "Nie zapisuj pełnego adresu IP w dziennikach i statystykach",
|
||||
"dns_config": "Konfiguracja serwera DNS",
|
||||
@@ -290,6 +291,8 @@
|
||||
"rate_limit": "Limit ilościowy",
|
||||
"edns_enable": "Włącz podsieć klienta EDNS",
|
||||
"edns_cs_desc": "Dodaj opcję podsieci klienta EDNS (ECS) do żądań nadrzędnych i rejestruj wartości wysyłane przez klientów w dzienniku zapytań.",
|
||||
"edns_use_custom_ip": "Użyj niestandardowego adresu IP dla EDNS",
|
||||
"edns_use_custom_ip_desc": "Zezwól na użycie niestandardowego adresu IP dla EDNS",
|
||||
"rate_limit_desc": "Liczba żądań na sekundę dozwolona na klienta. Ustawienie wartości 0 oznacza brak ograniczeń.",
|
||||
"blocking_ipv4_desc": "Adres IP, który ma zostać zwrócony w przypadku zablokowanego żądania A",
|
||||
"blocking_ipv6_desc": "Adres IP, który ma zostać zwrócony w przypadku zablokowanego żądania AAAA",
|
||||
@@ -343,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_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_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_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_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_2": "Kliknij Sieć.",
|
||||
@@ -393,7 +396,7 @@
|
||||
"encryption_issuer": "Zgłaszający",
|
||||
"encryption_hostnames": "Nazwy hostów",
|
||||
"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_expired_certificate": "Twój certyfikat SSL wygasł. Zaktualizuj <0>Ustawienia szyfrowania</0>.",
|
||||
"form_error_port_range": "Wpisz numer portu z zakresu 80-65535",
|
||||
@@ -475,7 +478,9 @@
|
||||
"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_deleted": "Przepisanie DNS dla „{{key}}” zostało pomyślnie usunięte",
|
||||
"rewrite_updated": "Pomyślnie zaktualizowano przepisywanie DNS",
|
||||
"rewrite_add": "Dodaj przepisywanie DNS",
|
||||
"rewrite_edit": "Edytuj przepisywanie DNS",
|
||||
"rewrite_not_found": "Nie znaleziono przepisywania DNS",
|
||||
"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.",
|
||||
@@ -523,6 +528,10 @@
|
||||
"statistics_retention_confirm": "Czy chcesz zmienić sposób przechowania statystyk? Jeżeli obniżysz wartość interwału, niektóre dane będą utracone",
|
||||
"statistics_cleared": "Statystyki zostały pomyślnie wyczyszczone",
|
||||
"statistics_enable": "Włącz statystyki",
|
||||
"ignore_domains": "Ignorowane domeny (każda w nowym wierszu)",
|
||||
"ignore_domains_title": "Ignorowane domeny",
|
||||
"ignore_domains_desc_stats": "Zapytania dla tych domen nie są zapisywane do statystyk",
|
||||
"ignore_domains_desc_query": "Zapytania dla tych domen nie są zapisywane do dziennika",
|
||||
"interval_hours": "{{count}} godzina",
|
||||
"interval_hours_plural": "{{count}} godziny",
|
||||
"filters_configuration": "Konfiguracja filtrów",
|
||||
@@ -535,7 +544,7 @@
|
||||
"password_placeholder": "Wpisz hasło",
|
||||
"sign_in": "Zaloguj się",
|
||||
"sign_out": "Wyloguj się",
|
||||
"forgot_password": "Zapomniałeś hasła?",
|
||||
"forgot_password": "Zapomniano hasła?",
|
||||
"forgot_password_desc": "Wykonaj <0>te kroki</0>, aby utworzyć nowe hasło do konta użytkownika.",
|
||||
"location": "Lokalizacja",
|
||||
"orgname": "Nazwa firmy",
|
||||
@@ -642,5 +651,30 @@
|
||||
"anonymizer_notification": "<0>Uwaga:</0> Anonimizacja IP jest włączona. Możesz ją wyłączyć w <1>Ustawieniach ogólnych</1>.",
|
||||
"confirm_dns_cache_clear": "Czy na pewno chcesz wyczyścić pamięć podręczną DNS?",
|
||||
"cache_cleared": "Pamięć podręczna DNS została pomyślnie wyczyszczona",
|
||||
"clear_cache": "Wyczyść pamięć podręczną"
|
||||
"clear_cache": "Wyczyść pamięć podręczną",
|
||||
"make_static": "Ustaw adres statyczny",
|
||||
"theme_auto_desc": "Automatycznie (na podstawie schematu kolorów Twojego urządzenia)",
|
||||
"theme_dark_desc": "Ciemny motyw",
|
||||
"theme_light_desc": "Jasny motyw",
|
||||
"disable_for_seconds": "Na {{count}} sekundę",
|
||||
"disable_for_seconds_plural": "Na {{count}} sekund",
|
||||
"disable_for_minutes": "Na {{count}} minutę",
|
||||
"disable_for_minutes_plural": "Na {{count}} minut",
|
||||
"disable_for_hours": "Na {{count}} godzinę",
|
||||
"disable_for_hours_plural": "Na {{count}} godziny",
|
||||
"disable_until_tomorrow": "Do jutra",
|
||||
"disable_notify_for_seconds": "Wyłącz ochronę na {{count}} sekundę",
|
||||
"disable_notify_for_seconds_plural": "Wyłącz ochronę na {{count}} sekund",
|
||||
"disable_notify_for_minutes": "Wyłącz ochronę na {{count}} minutę",
|
||||
"disable_notify_for_minutes_plural": "Wyłącz ochronę na {{count}} minut",
|
||||
"disable_notify_for_hours": "Wyłącz ochronę na {{count}} godzinę",
|
||||
"disable_notify_for_hours_plural": "Wyłącz ochronę na {{count}} godziny",
|
||||
"disable_notify_until_tomorrow": "Wyłącz ochronę do jutra",
|
||||
"enable_protection_timer": "Ochrona zostanie włączona za {{time}}",
|
||||
"custom_retention_input": "Wprowadź retencję w godzinach",
|
||||
"custom_rotation_input": "Wprowadź rotację w godzinach",
|
||||
"protection_section_label": "Ochrona",
|
||||
"log_and_stats_section_label": "Dziennik zapytań i statystyki",
|
||||
"ignore_query_log": "Zignoruj tego klienta w dzienniku zapytań",
|
||||
"ignore_statistics": "Ignoruj tego klienta w statystykach"
|
||||
}
|
||||
|
||||
@@ -257,12 +257,12 @@
|
||||
"query_log_cleared": "O registro de consulta foi limpo com sucesso",
|
||||
"query_log_updated": "O registro da consulta foi atualizado com sucesso",
|
||||
"query_log_clear": "Limpar registros de consulta",
|
||||
"query_log_retention": "Arquivamento de registros de consultas",
|
||||
"query_log_retention": "Rotação de registros de consulta",
|
||||
"query_log_enable": "Ativar registro",
|
||||
"query_log_configuration": "Configuração de registros",
|
||||
"query_log_disabled": "O registro de consulta está desativado e pode ser configurado em <0>configurações</0>",
|
||||
"query_log_strict_search": "Use aspas duplas para uma pesquisa mais criteriosa",
|
||||
"query_log_retention_confirm": "Você tem certeza de que deseja alterar o arquivamento do registro de consulta? Se diminuir o valor de intervalo, alguns dados serão perdidos",
|
||||
"query_log_retention_confirm": "Tem a certeza de que quer alterar a rotação do registo de consulta? Se diminuir o valor do intervalo, alguns dados serão perdidos",
|
||||
"anonymize_client_ip": "Tornar anônimo o IP do cliente",
|
||||
"anonymize_client_ip_desc": "Não salva o endereço de IP completo do cliente em registros ou estatísticas",
|
||||
"dns_config": "Configuração do servidor DNS",
|
||||
@@ -478,7 +478,9 @@
|
||||
"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_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_edit": "Editar reconfiguração de DNS",
|
||||
"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_desc": "Permite configurar uma resposta personalizada do DNS para um nome de domínio específico.",
|
||||
@@ -529,7 +531,7 @@
|
||||
"ignore_domains": "Domínios ignorados (separados por nova linha)",
|
||||
"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_query": "As consultas para esses domínios não são gravadas no log de consulta",
|
||||
"ignore_domains_desc_query": "As consultas para esses domínios não são gravadas no registro de consulta",
|
||||
"interval_hours": "{{count}} hora",
|
||||
"interval_hours_plural": "{{count}} horas",
|
||||
"filters_configuration": "Configuração de filtros",
|
||||
@@ -668,5 +670,11 @@
|
||||
"disable_notify_for_hours": "Desativar proteção por {{count}} hora",
|
||||
"disable_notify_for_hours_plural": "Desativar proteção por {{count}} horas",
|
||||
"disable_notify_until_tomorrow": "Desativar a proteção até amanhã",
|
||||
"enable_protection_timer": "A proteção será ativada em {{time}}"
|
||||
"enable_protection_timer": "A proteção será ativada em {{time}}",
|
||||
"custom_retention_input": "Insira a retenção em horas",
|
||||
"custom_rotation_input": "Insira a rotação em horas",
|
||||
"protection_section_label": "Proteção",
|
||||
"log_and_stats_section_label": "Registro de consultas e estatísticas",
|
||||
"ignore_query_log": "Ignorar este cliente no registo de consultas",
|
||||
"ignore_statistics": "Ignorar este cliente nas estatísticas"
|
||||
}
|
||||
|
||||
@@ -257,12 +257,12 @@
|
||||
"query_log_cleared": "O registo de consulta foi limpo com sucesso",
|
||||
"query_log_updated": "O registo da consulta foi atualizado com sucesso",
|
||||
"query_log_clear": "Limpar registos de consulta",
|
||||
"query_log_retention": "Retenção de registos de consulta",
|
||||
"query_log_retention": "Rotação de registros de consulta",
|
||||
"query_log_enable": "Ativar registo",
|
||||
"query_log_configuration": "Definições do registo",
|
||||
"query_log_disabled": "O registo de consulta está desativado e pode ser configurado em <0>definições</0>",
|
||||
"query_log_strict_search": "Usar aspas duplas para uma pesquisa rigorosa",
|
||||
"query_log_retention_confirm": "Tem a certeza de que deseja alterar a retenção do registo de consulta? Se diminuir o valor do intervalo, alguns dados serão perdidos",
|
||||
"query_log_retention_confirm": "Tem a certeza de que quer alterar a rotação do registo de consulta? Se diminuir o valor do intervalo, alguns dados serão perdidos",
|
||||
"anonymize_client_ip": "Tornar anónimo o IP do cliente",
|
||||
"anonymize_client_ip_desc": "Não gurda o endereço de IP completo do cliente em registo ou estatísticas",
|
||||
"dns_config": "Definição do servidor DNS",
|
||||
@@ -478,7 +478,9 @@
|
||||
"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_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_edit": "Editar reedição de DNS",
|
||||
"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_desc": "Permite configurar uma resposta personalizada do DNS para um nome de domínio específico.",
|
||||
@@ -529,7 +531,7 @@
|
||||
"ignore_domains": "Domínios ignorados (separados por nova linha)",
|
||||
"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_query": "As consultas para estes domínios nãoaparecem no registo de consultas",
|
||||
"ignore_domains_desc_query": "As consultas para estes domínios não aparecem no registo de consultas",
|
||||
"interval_hours": "{{count}} hora",
|
||||
"interval_hours_plural": "{{count}} horas",
|
||||
"filters_configuration": "Definição dos filtros",
|
||||
@@ -668,5 +670,11 @@
|
||||
"disable_notify_for_hours": "Desativar proteção por {{count}} hora",
|
||||
"disable_notify_for_hours_plural": "Desativar proteção por {{count}} horas",
|
||||
"disable_notify_until_tomorrow": "Desativar a proteção até amanhã",
|
||||
"enable_protection_timer": "A proteção será habilitada em {{time}}"
|
||||
"enable_protection_timer": "A proteção será habilitada em {{time}}",
|
||||
"custom_retention_input": "Insira a retenção em horas",
|
||||
"custom_rotation_input": "Insira a rotação em horas",
|
||||
"protection_section_label": "Proteção",
|
||||
"log_and_stats_section_label": "Log de consulta e estatísticas",
|
||||
"ignore_query_log": "Ignorar este cliente no log de consulta",
|
||||
"ignore_statistics": "Ignorar este cliente nas estatísticas"
|
||||
}
|
||||
|
||||
@@ -167,6 +167,7 @@
|
||||
"enabled_parental_toast": "Control Parental activat",
|
||||
"disabled_safe_search_toast": "Căutare protejată dezactivată",
|
||||
"enabled_save_search_toast": "Căutare protejată activată",
|
||||
"updated_save_search_toast": "Setări Căutare sigură actualizate",
|
||||
"enabled_table_header": "Activat",
|
||||
"name_table_header": "Nume",
|
||||
"list_url_table_header": "Lista URL",
|
||||
@@ -256,12 +257,12 @@
|
||||
"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_clear": "Curăță jurnalele",
|
||||
"query_log_retention": "Retenție jurnale interogare",
|
||||
"query_log_retention": "Interogarea jurnalelor de rotație",
|
||||
"query_log_enable": "Activați jurnal",
|
||||
"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_strict_search": "Utilizați ghilimele duble pentru căutare strictă",
|
||||
"query_log_retention_confirm": "Sunteți sigur că doriți să schimbați retenția jurnalului de interogare? Reducând valoarea intervalului, unele date vor fi pierdute",
|
||||
"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",
|
||||
"anonymize_client_ip": "Anonimizare client IP",
|
||||
"anonymize_client_ip_desc": "Nu salvați adresa IP completă a clientului în jurnale și statistici",
|
||||
"dns_config": "Configurația serverului DNS",
|
||||
@@ -290,6 +291,8 @@
|
||||
"rate_limit": "Limita ratei",
|
||||
"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_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ă.",
|
||||
"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",
|
||||
@@ -475,7 +478,9 @@
|
||||
"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_deleted": "Rescriere DNS pentru \"{{key}}\" ștearsă cu succes",
|
||||
"rewrite_updated": "DNS rescrie actualizat cu succes",
|
||||
"rewrite_add": "Adăugați rescriere DNS",
|
||||
"rewrite_edit": "Editați rescrierea 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_desc": "Permite configurarea cu ușurință a răspunsului personalizat DNS pentru un nume de domeniu specific.",
|
||||
@@ -523,6 +528,10 @@
|
||||
"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_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_plural": "{{count}} ore",
|
||||
"filters_configuration": "Configurația filtrelor",
|
||||
@@ -642,5 +651,30 @@
|
||||
"anonymizer_notification": "<0>Nota:</0> Anonimizarea IP este activată. Puteți să o dezactivați în <1>Setări generale</1>.",
|
||||
"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",
|
||||
"clear_cache": "Goliți memoria cache"
|
||||
"clear_cache": "Goliți memoria cache",
|
||||
"make_static": "Faceți static",
|
||||
"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"
|
||||
}
|
||||
|
||||
@@ -257,12 +257,12 @@
|
||||
"query_log_cleared": "Журнал запросов успешно очищен",
|
||||
"query_log_updated": "Журнал запросов успешно обновлён",
|
||||
"query_log_clear": "Очистить журнал запросов",
|
||||
"query_log_retention": "Сохранение журнала запросов",
|
||||
"query_log_retention": "Частота ротации журнала запросов",
|
||||
"query_log_enable": "Включить журнал",
|
||||
"query_log_configuration": "Настройка журнала",
|
||||
"query_log_disabled": "Журнал запросов выключен, его можно включить в <0>настройках</0>",
|
||||
"query_log_strict_search": "Используйте двойные кавычки для строгого поиска",
|
||||
"query_log_retention_confirm": "Вы уверены, что хотите изменить срок хранения запросов? При сокращении интервала данные могут быть утеряны",
|
||||
"query_log_retention_confirm": "Вы уверены, что хотите изменить частоту ротации журнала запросов? При сокращении срока данные могут быть утеряны",
|
||||
"anonymize_client_ip": "Анонимизировать IP-адрес клиента",
|
||||
"anonymize_client_ip_desc": "Не сохранять полный IP-адрес клиента в журналах и статистике",
|
||||
"dns_config": "Настройки DNS-сервера",
|
||||
@@ -478,7 +478,9 @@
|
||||
"setup_dns_notice": "Чтобы использовать <1>DNS-over-HTTPS</1> или <1>DNS-over-TLS</1>, вам нужно <0>настроить шифрование</0> в настройках AdGuard Home.",
|
||||
"rewrite_added": "Правило перезаписи DNS-запросов для «{{key}}» успешно добавлено",
|
||||
"rewrite_deleted": "Правило перезаписи DNS-запросов для «{{key}}» успешно удалено",
|
||||
"rewrite_updated": "Правило перезаписи DNS-запросов успешно обновлено",
|
||||
"rewrite_add": "Добавить правило перезаписи DNS-запросов",
|
||||
"rewrite_edit": "Редактировать правило перезаписи DNS-запросов",
|
||||
"rewrite_not_found": "Не найдено правил перезаписи DNS-запросов",
|
||||
"rewrite_confirm_delete": "Вы уверены, что хотите удалить правило перезаписи DNS-запросов для «{{key}}»?",
|
||||
"rewrite_desc": "Позволяет легко настроить пользовательский DNS-ответ для определеннного домена.",
|
||||
@@ -668,5 +670,11 @@
|
||||
"disable_notify_for_hours": "Отключить защиту на {{count}} час",
|
||||
"disable_notify_for_hours_plural": "Отключить защиту на {{count}} часов",
|
||||
"disable_notify_until_tomorrow": "Отключить защиту до завтра",
|
||||
"enable_protection_timer": "Защита будет включена в {{time}}"
|
||||
"enable_protection_timer": "Защита будет включена в {{time}}",
|
||||
"custom_retention_input": "Введите срок хранения в часах",
|
||||
"custom_rotation_input": "Введите частоту ротации в часах",
|
||||
"protection_section_label": "Защита",
|
||||
"log_and_stats_section_label": "Журнал запросов и статистика",
|
||||
"ignore_query_log": "Игнорировать этого клиента в журнале запросов",
|
||||
"ignore_statistics": "Игнорировать этого клиента в статистике"
|
||||
}
|
||||
|
||||
@@ -153,6 +153,7 @@
|
||||
"enabled_parental_toast": "දෙමාපිය පාලනය සබල කෙරිණි",
|
||||
"disabled_safe_search_toast": "ආරක්ෂිත සෙවුම අබල කෙරිණි",
|
||||
"enabled_save_search_toast": "ආරක්ෂිත සෙවුම සබල කෙරිණි",
|
||||
"updated_save_search_toast": "ආරක්ෂිත සෙවුමේ සැකසුම් යාවත්කාල විය",
|
||||
"enabled_table_header": "සබලයි",
|
||||
"name_table_header": "නම",
|
||||
"list_url_table_header": "ඒ.ස.නි.(URL) ලැයිස්තුව",
|
||||
@@ -237,12 +238,12 @@
|
||||
"query_log_cleared": "විමසුම් සටහන සාර්ථකව හිස් කර ඇත",
|
||||
"query_log_updated": "විමසුම් සටහන සාර්ථකව යාවත්කාල කෙරිණි",
|
||||
"query_log_clear": "විමසුම් සටහන් හිස් කරන්න",
|
||||
"query_log_retention": "විමසුම් සටහන් රඳවා තබා ගැනීම",
|
||||
"query_log_retention": "විමසුම් සටහන් රැඳවීම",
|
||||
"query_log_enable": "සටහන සබල කරන්න",
|
||||
"query_log_configuration": "සටහන් වින්යාසය",
|
||||
"query_log_disabled": "විමසුම් සටහන අබල කර ඇති අතර එය <0>සැකසුම්</0> තුළ වින්යාසගත කළ හැකිය",
|
||||
"query_log_strict_search": "ඉතා නිවැරදිව සෙවීමට ද්විත්ව උද්ධෘතය භාවිතා කරන්න",
|
||||
"query_log_retention_confirm": "විමසුම් සටහන රඳවා තබා ගැනීම වෙනස් කිරීමට ඇවැසි බව ඔබට විශ්වාසද? ඔබ කාල පරතරයෙහි අගය අඩු කළහොත් සමහර දත්ත නැති වී යනු ඇත",
|
||||
"query_log_retention_confirm": "විමසුම් සටහන රඳවා තබා ගැනීම වෙනස් කිරීමට වුවමනා ද? ඔබ කාල පරතරයෙහි අගය අඩු කළහොත් සමහර දත්ත නැති වී යනු ඇත",
|
||||
"anonymize_client_ip": "අනුග්රාහකයෙහි අ.ජා.කෙ. (IP) නිර්නාමික කරන්න",
|
||||
"anonymize_client_ip_desc": "සටහන් සහ සංඛ්යාලේඛන තුළ අනුග්රාහකයේ පූර්ණ අ.ජා.කෙ. ලිපිනය සුරකින්න එපා",
|
||||
"dns_config": "ව.නා.ප. සේවාදායක වින්යාසය",
|
||||
@@ -270,6 +271,8 @@
|
||||
"form_enter_rate_limit": "අනුපාත සීමාව ඇතුල් කරන්න",
|
||||
"rate_limit": "අනුපාත සීමාව",
|
||||
"edns_enable": "EDNS අනුග්රාහක අනුජාලය සබල කරන්න",
|
||||
"edns_use_custom_ip": "EDNS සඳහා අභිරුචි අ.ජා.කෙ. යොදාගන්න",
|
||||
"edns_use_custom_ip_desc": "EDNS සඳහා අභිරුචි අ.ජා.කෙ. භාවිතයට ඉඩදෙන්න",
|
||||
"rate_limit_desc": "එක් අනුග්රාහකයකට ඉඩ දී ඇති තත්පරයට ඉල්ලීම් ගණන. එය 0 ලෙස සැකසීම යනුවෙන් අදහස් කරන්නේ සීමාවක් නැති බවයි.",
|
||||
"blocking_ipv4_desc": "අවහිර කළ A ඉල්ලීමක් සඳහා ආපසු එවිය යුතු අ.ජා.කෙ. (IP) ලිපිනය",
|
||||
"blocking_ipv6_desc": "අවහිර කළ AAAA ඉල්ලීමක් සඳහා ආපසු එවිය යුතු අ.ජා.කෙ. (IP) ලිපිනය",
|
||||
@@ -278,6 +281,9 @@
|
||||
"blocking_mode_nxdomain": "නොපවතින වසම: NXDOMAIN කේතය සමඟ ප්රතිචාර දක්වයි",
|
||||
"blocking_mode_null_ip": "අභිශූන්යය අ.ජා.කෙ.: ශුන්ය අ.ජා.කෙ. ලිපිනය සමඟ ප්රතිචාර දක්වයි (A සඳහා 0.0.0.0; AAAA සඳහා ::)",
|
||||
"blocking_mode_custom_ip": "අභිරුචි අන්තර්ජාල කෙටුම්පත: අතින් සැකසූ අ.ජා. කෙ. ලිපිනයක් සමඟ ප්රතිචාර දක්වයි",
|
||||
"theme_auto": "ස්වයං",
|
||||
"theme_light": "දීප්ත",
|
||||
"theme_dark": "අඳුරු",
|
||||
"upstream_dns_client_desc": "ඔබ මෙම ක්ෂේත්රය හිස්ව තබා ගන්නේ නම්, ඇඩ්ගාර්ඩ් හෝම් විසින් <0>ව.නා.ප. සැකසුම්</0> හි වින්යාසගත කර ඇති සේවාදායක භාවිතා කරනු ඇත.",
|
||||
"tracker_source": "ලුහුබැඳීම් මූලාශ්රය",
|
||||
"source_label": "මූලාශ්රය",
|
||||
@@ -370,6 +376,7 @@
|
||||
"encryption_issuer": "නිකුත් කරන්නා",
|
||||
"encryption_hostnames": "ධාරක නාම",
|
||||
"encryption_reset": "සංකේතාංකන සැකසුම් යළි පිහිටුවීමට අවශ්ය බව ඔබට විශ්වාස ද?",
|
||||
"encryption_warning": "අවවාදයයි",
|
||||
"topline_expiring_certificate": "ඔබගේ SSL සහතිකය කල් ඉකුත්වීමට ආසන්න වී ඇත. <0>සංකේතන සැකසුම්</0> යාවත්කාල කරන්න.",
|
||||
"topline_expired_certificate": "ඔබගේ SSL සහතිකය කල් ඉකුත් වී ඇත. <0>සංකේතන සැකසුම්</0> යාවත්කාල කරන්න.",
|
||||
"form_error_port_range": "80-65535 පරාසය හි තොටක අගයක් ඇතුල් කරන්න",
|
||||
@@ -490,8 +497,10 @@
|
||||
"statistics_clear": "සංඛ්යාලේඛන හිස් කරන්න",
|
||||
"statistics_clear_confirm": "සංඛ්යාලේඛන ඉවත් කිරීමට වුවමනා ද?",
|
||||
"statistics_retention_confirm": "සංඛ්යාලේඛන රඳවා තබා ගැනීම වෙනස් කිරීමට අවශ්ය බව ඔබට විශ්වාසද? ඔබ කාල පරතරයෙහි අගය අඩු කළහොත් සමහර දත්ත නැති වී යනු ඇත",
|
||||
"statistics_cleared": "සංඛ්යාලේඛන සාර්ථකව ඉවත් කෙරිණි",
|
||||
"statistics_cleared": "සංඛ්යාලේඛන සාර්ථකව හිස් කෙරිණි",
|
||||
"statistics_enable": "සංඛ්යාලේඛන සබල කරන්න",
|
||||
"ignore_domains": "නොසලකන වසම් (පේළියකට එක බැගින්)",
|
||||
"ignore_domains_title": "නොසලකන වසම්",
|
||||
"interval_hours": "පැය {{count}}",
|
||||
"interval_hours_plural": "පැය {{count}}",
|
||||
"filters_configuration": "පෙරහන් වින්යාසය",
|
||||
@@ -601,5 +610,31 @@
|
||||
"parental_control": "දෙමාපිය පාලනය",
|
||||
"safe_browsing": "ආරක්ෂිත පිරික්සුම",
|
||||
"served_from_cache": "{{value}} <i>(නිහිතයෙන් ගැනිණි)</i>",
|
||||
"form_error_password_length": "මුරපදය අවම වශයෙන් අකුරු {{value}} ක් දිගු විය යුතුමයි"
|
||||
"form_error_password_length": "මුරපදය අවම වශයෙන් අකුරු {{value}} ක් දිගු විය යුතුමයි",
|
||||
"cache_cleared": "ව.නා.ප. නිහිතය හිස් කෙරිණි",
|
||||
"clear_cache": "නිහිතය මකන්න",
|
||||
"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}} කට රැකවරණය අබල කරන්න",
|
||||
"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": "සංඛ්යාලේඛනයට අනුග්රාහකය නොසලකන්න"
|
||||
}
|
||||
|
||||
@@ -257,12 +257,12 @@
|
||||
"query_log_cleared": "Denník dopytov bol úspešne vymazaný",
|
||||
"query_log_updated": "Denník dopytov bol úspešne aktualizovaný",
|
||||
"query_log_clear": "Vymazať denníky dopytov",
|
||||
"query_log_retention": "Obdobie záznamu denníka dopytov",
|
||||
"query_log_retention": "Rotácia denníkov dopytov",
|
||||
"query_log_enable": "Zapnúť denník",
|
||||
"query_log_configuration": "Konfigurácia denníka",
|
||||
"query_log_disabled": "Protokol dopytov je vypnutý a možno ho nakonfigurovať v <0>nastaveniach</0>",
|
||||
"query_log_strict_search": "Na prísne vyhľadávanie použite dvojité úvodzovky",
|
||||
"query_log_retention_confirm": "Naozaj chcete zmeniť uchovávanie denníku dopytov? Ak znížite hodnotu intervalu, niektoré údaje sa stratia",
|
||||
"query_log_retention_confirm": "Naozaj chcete zmeniť rotáciu denníka dopytov? Ak znížite hodnotu intervalu, niektoré údaje sa stratia",
|
||||
"anonymize_client_ip": "Anonymizujte IP klienta",
|
||||
"anonymize_client_ip_desc": "Neukladať úplnú IP adresu klienta do protokolov a štatistík",
|
||||
"dns_config": "Konfigurácia DNS servera",
|
||||
@@ -478,7 +478,9 @@
|
||||
"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_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_edit": "Upraviť prepísanie DNS",
|
||||
"rewrite_not_found": "Neboli nájdené žiadne DNS prepísania",
|
||||
"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.",
|
||||
@@ -668,5 +670,11 @@
|
||||
"disable_notify_for_hours": "Vypnite ochranu na {{count}} hodinu",
|
||||
"disable_notify_for_hours_plural": "Vypnite ochranu na {{count}} hodín",
|
||||
"disable_notify_until_tomorrow": "Vypnúť ochranu do zajtra",
|
||||
"enable_protection_timer": "Ochrana bude zapnutá o {{time}}"
|
||||
"enable_protection_timer": "Ochrana bude zapnutá o {{time}}",
|
||||
"custom_retention_input": "Zadajte retenciu v hodinách",
|
||||
"custom_rotation_input": "Zadajte rotáciu v hodinách",
|
||||
"protection_section_label": "Ochrana",
|
||||
"log_and_stats_section_label": "Protokol dopytov a štatistiky",
|
||||
"ignore_query_log": "Ignorovať tohto klienta v denníku dopytov",
|
||||
"ignore_statistics": "Ignorovanie tohto klienta v štatistikách"
|
||||
}
|
||||
|
||||
@@ -257,12 +257,12 @@
|
||||
"query_log_cleared": "Dnevnik poizvedb je uspešno izbrisan",
|
||||
"query_log_updated": "Dnevnik poizvedb je bil uspešno posodobljen",
|
||||
"query_log_clear": "Počisti dnevnike poizvedb",
|
||||
"query_log_retention": "Zadrževanje dnevnikov poizvedb",
|
||||
"query_log_retention": "Rotacija dnevnikov poizvedb",
|
||||
"query_log_enable": "Omogoči dnevni",
|
||||
"query_log_configuration": "Konfiguracija dnevnikov",
|
||||
"query_log_disabled": "Dnevnik poizvedb je onemogočen in ga je mogoče konfigurirati v <0>nastavitvah</0>",
|
||||
"query_log_strict_search": "Za strogo iskanje uporabite dvojne narekovaje",
|
||||
"query_log_retention_confirm": "Ali ste prepričani, da želite spremeniti zadrževanje dnevnika poizvedb? Če zmanjšate vrednost intervala, bodo nekateri podatki izgubljeni",
|
||||
"query_log_retention_confirm": "Ali ste prepričani, da želite spremeniti rotacijo dnevnika poizvedb? Če zmanjšate vrednost intervala, bodo nekateri podatki izgubljeni",
|
||||
"anonymize_client_ip": "Anonimiziraj odjemalca IP",
|
||||
"anonymize_client_ip_desc": "Ne shrani celotnega naslova IP odjemalca v dnevnikih ali statistiki",
|
||||
"dns_config": "Konfiguracija strežnika DNS",
|
||||
@@ -478,7 +478,9 @@
|
||||
"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_deleted": "Uspešno je izbrisano DNS prepisovanje za \"{{key}}\"",
|
||||
"rewrite_updated": "DNS prepisovanje uspešno posodobljen",
|
||||
"rewrite_add": "Dodaj prepisovanje DNS",
|
||||
"rewrite_edit": "Urejanje prepisa DNS",
|
||||
"rewrite_not_found": "Ni bilo najdenih prepisovanj DNS",
|
||||
"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.",
|
||||
@@ -668,5 +670,11 @@
|
||||
"disable_notify_for_hours": "Onemogoči zaščito za {{count}} uro",
|
||||
"disable_notify_for_hours_plural": "Onemogoči zaščito za {{count}} ur",
|
||||
"disable_notify_until_tomorrow": "Onemogoči zaščito do jutri",
|
||||
"enable_protection_timer": "Zaščita bo omogočena ob {{time}}"
|
||||
"enable_protection_timer": "Zaščita bo omogočena ob {{time}}",
|
||||
"custom_retention_input": "Vnesite zadrževanje v urah",
|
||||
"custom_rotation_input": "Vnesite rotacijo v urah",
|
||||
"protection_section_label": "Zaščita",
|
||||
"log_and_stats_section_label": "Dnevnik poizvedb in statistika",
|
||||
"ignore_query_log": "Ignorirajte tega odjemalca v dnevniku poizvedb",
|
||||
"ignore_statistics": "Ignoriranje tega odjemalca v statistiki"
|
||||
}
|
||||
|
||||
@@ -475,7 +475,9 @@
|
||||
"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_deleted": "DNS prepisivanje za \"{{key}}\" uspešno izbrisano",
|
||||
"rewrite_updated": "DNS ponovo napisao uspešno ažuriran",
|
||||
"rewrite_add": "Dodaj DNS prepisivanje",
|
||||
"rewrite_edit": "Uređivanje DNS prepravke",
|
||||
"rewrite_not_found": "DNS prepisivanja nisu pronađena",
|
||||
"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.",
|
||||
@@ -642,5 +644,6 @@
|
||||
"anonymizer_notification": "<0>Nota:</0> IP prepoznavanje je omogućeno. Možete ga onemogućiti u opštim <1>postavkama</1>.",
|
||||
"confirm_dns_cache_clear": "Želite li zaista da obrišite DNS keš?",
|
||||
"cache_cleared": "DNS keš je uspešno očišćen",
|
||||
"clear_cache": "Obriši keš memoriju"
|
||||
"clear_cache": "Obriši keš memoriju",
|
||||
"protection_section_label": "Zaštita"
|
||||
}
|
||||
|
||||
@@ -475,7 +475,9 @@
|
||||
"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_deleted": "DNS-omskrivning för \"{{key}}\" har tagits bort",
|
||||
"rewrite_updated": "DNS-omskrivning har uppdaterats",
|
||||
"rewrite_add": "Lägg till DNS omskrivning",
|
||||
"rewrite_edit": "Redigera DNS-omskrivning",
|
||||
"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_desc": "Gör det enkelt att konfigurera anpassat DNS svar för ett specifikt domännamn.",
|
||||
|
||||
@@ -257,12 +257,12 @@
|
||||
"query_log_cleared": "Sorgu günlüğü başarıyla temizlendi",
|
||||
"query_log_updated": "Sorgu günlüğü başarıyla güncellendi",
|
||||
"query_log_clear": "Sorgu günlüklerini temizle",
|
||||
"query_log_retention": "Sorgu günlüklerini sakla",
|
||||
"query_log_retention": "Sorgu günlükleri rotasyonu",
|
||||
"query_log_enable": "Günlüğü etkinleştir",
|
||||
"query_log_configuration": "Günlük yapılandırması",
|
||||
"query_log_disabled": "Sorgu günlüğü devre dışı bırakıldı, bunu <0>ayarlar</0> kısmından yapılandırılabilirsiniz",
|
||||
"query_log_strict_search": "Tam arama için çift tırnak işareti kullanın",
|
||||
"query_log_retention_confirm": "Sorgu günlüğü saklama süresini değiştirmek istediğinize emin misiniz? Aralık değerini azaltırsanız, bazı veriler kaybolacaktır",
|
||||
"query_log_retention_confirm": "Sorgu günlüğü rotasyonunu değiştirmek istediğinizden emin misiniz? Aralık değerini düşürürseniz, bazı veriler kaybolacaktır.",
|
||||
"anonymize_client_ip": "İstemcinin IP adresini gizle",
|
||||
"anonymize_client_ip_desc": "İstemcinin tam IP adresini günlüklere veya istatistiklere kaydetmeyin",
|
||||
"dns_config": "DNS sunucu yapılandırması",
|
||||
@@ -478,7 +478,9 @@
|
||||
"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_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_edit": "DNS yeniden yazmayı düzenle",
|
||||
"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_desc": "Belirli bir alan adı için özel DNS yanıtını kolayca yapılandırmanızı sağlar.",
|
||||
@@ -668,5 +670,11 @@
|
||||
"disable_notify_for_hours": "Korumayı {{count}} saatliğine devre dışı bırak",
|
||||
"disable_notify_for_hours_plural": "Korumayı {{count}} saatliğine devre dışı bırak",
|
||||
"disable_notify_until_tomorrow": "Korumayı yarına kadar devre dışı bırak",
|
||||
"enable_protection_timer": "Koruma {{time}} içinde etkinleştirilecektir"
|
||||
"enable_protection_timer": "Koruma {{time}} içinde etkinleştirilecektir",
|
||||
"custom_retention_input": "Saklama süresini saat olarak girin",
|
||||
"custom_rotation_input": "Rotasyonu saat cinsinden girin",
|
||||
"protection_section_label": "Koruma",
|
||||
"log_and_stats_section_label": "Sorgu günlüğü ve istatistikler",
|
||||
"ignore_query_log": "Sorgu günlüğünde bu istemciyi yoksay",
|
||||
"ignore_statistics": "İstatistiklerde bu istemciyi yoksay"
|
||||
}
|
||||
|
||||
@@ -167,6 +167,7 @@
|
||||
"enabled_parental_toast": "«Батьківський контроль» увімкнено",
|
||||
"disabled_safe_search_toast": "Безпечний пошук вимкнено",
|
||||
"enabled_save_search_toast": "Безпечний пошук увімкнено",
|
||||
"updated_save_search_toast": "Налаштування Безпечного пошуку оновлено",
|
||||
"enabled_table_header": "Увімкнено",
|
||||
"name_table_header": "Назва",
|
||||
"list_url_table_header": "URL списку",
|
||||
@@ -290,6 +291,8 @@
|
||||
"rate_limit": "Обмеження швидкості",
|
||||
"edns_enable": "Увімкнути відправку EDNS Client Subnet",
|
||||
"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» означатиме необмежену кількість.",
|
||||
"blocking_ipv4_desc": "IP-адреса, яку потрібно видати для заблокованого A запиту",
|
||||
"blocking_ipv6_desc": "IP-адреса, яку потрібно видати для заблокованого АААА запиту",
|
||||
@@ -475,7 +478,9 @@
|
||||
"setup_dns_notice": "Для використання <1>DNS-over-HTTPS</1> або <1>DNS-over-TLS</1>, вам потрібно <0>налаштувати Шифрування</0> в налаштуваннях AdGuard Home.",
|
||||
"rewrite_added": "Перезапис DNS для «{{key}}» успішно додано",
|
||||
"rewrite_deleted": "Перезапис DNS для «{{key}}» успішно видалено",
|
||||
"rewrite_updated": "Перезапис DNS успішно оновлено",
|
||||
"rewrite_add": "Додати перезапис DNS",
|
||||
"rewrite_edit": "Редагувати перезапис DNS",
|
||||
"rewrite_not_found": "Перезаписів DNS не знайдено",
|
||||
"rewrite_confirm_delete": "Ви впевнені, що хочете видалити перезапис DNS для «{{key}}»?",
|
||||
"rewrite_desc": "Дозволяє легко налаштувати власну відповідь DNS для певного доменного імені.",
|
||||
@@ -523,6 +528,10 @@
|
||||
"statistics_retention_confirm": "Ви впевнені, що хочете змінити тривалість статистики? Якщо зменшити значення інтервалу, деякі дані будуть втрачені",
|
||||
"statistics_cleared": "Статистику успішно очищено",
|
||||
"statistics_enable": "Увімкнути статистику",
|
||||
"ignore_domains": "Ігноровані домени (по одному на рядок)",
|
||||
"ignore_domains_title": "Ігноровані домени",
|
||||
"ignore_domains_desc_stats": "Запити для цих доменів в статистику не пишуться",
|
||||
"ignore_domains_desc_query": "Запити для цих доменів не записуються до журналу запитів",
|
||||
"interval_hours": "{{count}} година",
|
||||
"interval_hours_plural": "{{count}} годин(и)",
|
||||
"filters_configuration": "Конфігурація фільтрів",
|
||||
@@ -642,5 +651,30 @@
|
||||
"anonymizer_notification": "<0>Примітка:</0> IP-анонімізацію ввімкнено. Ви можете вимкнути його в <1>Загальні налаштування</1> .",
|
||||
"confirm_dns_cache_clear": "Ви впевнені, що бажаєте очистити кеш DNS?",
|
||||
"cache_cleared": "Кеш DNS успішно очищено",
|
||||
"clear_cache": "Очистити кеш"
|
||||
"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": "Ігноруйте цей клієнт в статистиці"
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"client_settings": "Cài đặt máy khách",
|
||||
"client_settings": "Cài đặt thiết bị",
|
||||
"example_upstream_reserved": "ngược dòng <0>cho các miền cụ thể</0>;",
|
||||
"example_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",
|
||||
@@ -167,6 +167,7 @@
|
||||
"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",
|
||||
"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",
|
||||
"name_table_header": "Tên",
|
||||
"list_url_table_header": "URL bộ lọc",
|
||||
@@ -256,12 +257,12 @@
|
||||
"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_clear": "Xóa nhật ký truy vấn",
|
||||
"query_log_retention": "Lưu giữ nhật ký truy vấn",
|
||||
"query_log_retention": "Xoay vòng nhật ký truy vấn",
|
||||
"query_log_enable": "Bật 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_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 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",
|
||||
"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",
|
||||
"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ê",
|
||||
"dns_config": "Thiết lập máy chủ DNS",
|
||||
@@ -290,6 +291,8 @@
|
||||
"rate_limit": "Giới hạn yêu cầu",
|
||||
"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_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)",
|
||||
"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",
|
||||
@@ -475,7 +478,9 @@
|
||||
"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_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_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_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ể.",
|
||||
@@ -523,6 +528,10 @@
|
||||
"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_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_plural": "{{count}} giờ",
|
||||
"filters_configuration": "Cấu hình bộ lọc",
|
||||
@@ -642,5 +651,30 @@
|
||||
"anonymizer_notification": "<0> Lưu ý:</0> Tính năng ẩn danh IP được bật. Bạn có thể tắt nó trong <1> Cài đặt chung</1>.",
|
||||
"confirm_dns_cache_clear": "Bạn có chắc chắn muốn xóa bộ đệm ẩn DNS không?",
|
||||
"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",
|
||||
"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ê"
|
||||
}
|
||||
|
||||
@@ -257,12 +257,12 @@
|
||||
"query_log_cleared": "查询日志已成功清除",
|
||||
"query_log_updated": "已成功更新查询日志",
|
||||
"query_log_clear": "清除查询日志",
|
||||
"query_log_retention": "查询记录保留时间",
|
||||
"query_log_retention": "查询日志保留时间",
|
||||
"query_log_enable": "启用日志",
|
||||
"query_log_configuration": "日志配置",
|
||||
"query_log_disabled": "查询日志已禁用,在<0>这些设置</0>中能配置它们",
|
||||
"query_log_strict_search": "使用双引号进行严谨搜索",
|
||||
"query_log_retention_confirm": "您确定要更改查询记录保留时间吗? 如果您减少间隔时间的值, 某些数据可能会丢失。",
|
||||
"query_log_retention_confirm": "您确定要更改查询记录保留时间吗?如果减少时间间隔数值,某些数据可能会丢失",
|
||||
"anonymize_client_ip": "匿名化客户端IP",
|
||||
"anonymize_client_ip_desc": "不要在日志和统计信息中保存客户端的完整 IP 地址",
|
||||
"dns_config": "DNS 服务配置",
|
||||
@@ -478,7 +478,9 @@
|
||||
"setup_dns_notice": "为了使用 <1>DNS-over-HTTPS</1> 或者 <1>DNS-over-TLS</1> ,您需要在 AdGuard Home 设置中 <0>配置加密</0> 。",
|
||||
"rewrite_added": "已成功添加 \"{{key}}\" 的 DNS 重写",
|
||||
"rewrite_deleted": "已成功删除 \"{{key}}\" 的 DNS 重写",
|
||||
"rewrite_updated": "DNS 重写已成功更新",
|
||||
"rewrite_add": "添加 DNS 重写",
|
||||
"rewrite_edit": "编辑 DNS 重写",
|
||||
"rewrite_not_found": "未找到 DNS 重写",
|
||||
"rewrite_confirm_delete": "您确定要删除 \"{{key}}\" 的 DNS 重写?",
|
||||
"rewrite_desc": "可以轻松地为特定域名配置自定义 DNS 响应。",
|
||||
@@ -668,5 +670,11 @@
|
||||
"disable_notify_for_hours": "禁用保护 {{count}} 小时",
|
||||
"disable_notify_for_hours_plural": "禁用保护 {{count}} 小时",
|
||||
"disable_notify_until_tomorrow": "禁用保护直到明天",
|
||||
"enable_protection_timer": "保护将于 {{time}} 启用"
|
||||
"enable_protection_timer": "保护将于 {{time}} 启用",
|
||||
"custom_retention_input": "输入保留时间(小时)",
|
||||
"custom_rotation_input": "输入旋转时间(小时)",
|
||||
"protection_section_label": "防护",
|
||||
"log_and_stats_section_label": "查询日志和统计数据",
|
||||
"ignore_query_log": "在查询日志中忽略此客户端",
|
||||
"ignore_statistics": "在统计数据中忽略此客户端"
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
"out_of_range_error": "必須介於 \"{{start}}\" - \"{{end}}\" 範圍之外",
|
||||
"lower_range_start_error": "必須小於起始值",
|
||||
"greater_range_start_error": "必須大於起始值",
|
||||
"gateway_or_subnet_invalid": "無效子網路",
|
||||
"dhcp_form_gateway_input": "閘道 IP 位址",
|
||||
"dhcp_form_subnet_input": "子網路遮罩",
|
||||
"dhcp_form_range_title": "IP 位址範圍",
|
||||
@@ -195,6 +196,7 @@
|
||||
"form_error_url_or_path_format": "列表中含有的 URL 網址或絕對路徑",
|
||||
"custom_filter_rules": "自訂過濾規則",
|
||||
"custom_filter_rules_hint": "一行一條規則。您可以使用「adblock」語法或「hosts檔案」的語法。",
|
||||
"system_host_files": "系統 hosts 檔案",
|
||||
"examples_title": "範例",
|
||||
"example_meaning_filter_block": "封鎖對 example.org 網域及其所有子網域的存取",
|
||||
"example_meaning_filter_whitelist": "解除對 example.org 網域及其所有子網域存取封鎖",
|
||||
@@ -279,6 +281,8 @@
|
||||
"rate_limit": "速率限制",
|
||||
"edns_enable": "啟用 EDNS Client Subnet",
|
||||
"edns_cs_desc": "傳送用戶端的子網路給 DNS 伺服器。",
|
||||
"edns_use_custom_ip": "使用自訂 EDNS IP",
|
||||
"edns_use_custom_ip_desc": "允許使用自訂 EDNS IP",
|
||||
"rate_limit_desc": "限制單一裝置每秒發出的查詢次數(設定為 0 即表示無限制)",
|
||||
"blocking_ipv4_desc": "回覆指定 IPv4 位址給被封鎖的網域的 A 紀錄查詢",
|
||||
"blocking_ipv6_desc": "回覆指定 IPv6 位址給被封鎖的網域的 AAAA 紀錄查詢",
|
||||
@@ -287,6 +291,9 @@
|
||||
"blocking_mode_nxdomain": "NXDOMAIN:回應 NXDOMAIN 狀態碼",
|
||||
"blocking_mode_null_ip": "Null IP:回應零值的 IP 位址(A 紀錄回應 0.0.0.0 ,AAAA 紀錄回應 ::)",
|
||||
"blocking_mode_custom_ip": "自訂 IP 位址:回應一個自訂的 IP 位址",
|
||||
"theme_auto": "自動",
|
||||
"theme_light": "明亮",
|
||||
"theme_dark": "深色",
|
||||
"upstream_dns_client_desc": "如果您將此欄位留白,AdGuard Home 將使用 <0>DNS 設定</0> 內的設定的 DNS 伺服器。",
|
||||
"tracker_source": "追蹤器來源",
|
||||
"source_label": "來源",
|
||||
@@ -397,6 +404,7 @@
|
||||
"dns_providers": "下列為常見的<0> DNS 伺服器</0>。",
|
||||
"update_now": "立即更新",
|
||||
"update_failed": "自動更新發生錯誤。請嘗試依照<a>以下步驟</a> 來手動更新。",
|
||||
"manual_update": "請嘗試依照<a>下列步驟</a>來手動更新。",
|
||||
"processing_update": "請稍候,AdGuard Home 正在更新",
|
||||
"clients_title": "用戶端",
|
||||
"clients_desc": "對已連接到 AdGuard Home 的裝置進行設定",
|
||||
@@ -505,6 +513,7 @@
|
||||
"statistics_clear_confirm": "您確定要清除統計資料嗎?",
|
||||
"statistics_retention_confirm": "您確定要更改統計資料保存時間嗎?如果您縮短期限部分資料可能將會遺失",
|
||||
"statistics_cleared": "已清除統計資料",
|
||||
"statistics_enable": "啟用統計數據",
|
||||
"interval_hours": "{{count}} 小時",
|
||||
"interval_hours_plural": "{{count}} 小時",
|
||||
"filters_configuration": "過濾器設定",
|
||||
@@ -613,5 +622,22 @@
|
||||
"original_response": "原始回應",
|
||||
"click_to_view_queries": "按一下以檢視查詢結果",
|
||||
"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}} 個字元長度",
|
||||
"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}} 小時"
|
||||
}
|
||||
|
||||
@@ -257,12 +257,12 @@
|
||||
"query_log_cleared": "該查詢記錄已被成功地清除",
|
||||
"query_log_updated": "該查詢記錄已被成功地更新",
|
||||
"query_log_clear": "清除查詢記錄",
|
||||
"query_log_retention": "查詢記錄保留",
|
||||
"query_log_retention": "查詢記錄保留時間",
|
||||
"query_log_enable": "啟用記錄",
|
||||
"query_log_configuration": "記錄配置",
|
||||
"query_log_disabled": "查詢記錄被禁用並可在<0>設定</0>中被配置",
|
||||
"query_log_strict_search": "使用雙引號於嚴謹的搜尋",
|
||||
"query_log_retention_confirm": "您確定您想要更改查詢記錄保留嗎?如果您減少該間隔值,某些資料將被丟失",
|
||||
"query_log_retention_confirm": "您確定要更改記錄檔保存期限嗎?如果您縮短期限部分資料可能將會遺失",
|
||||
"anonymize_client_ip": "將用戶端 IP 匿名",
|
||||
"anonymize_client_ip_desc": "不要儲存用戶端之完整的 IP 位址到記錄或統計資料裡",
|
||||
"dns_config": "DNS 伺服器配置",
|
||||
@@ -478,7 +478,9 @@
|
||||
"setup_dns_notice": "為了使用 <1>DNS-over-HTTPS</1> 或 <1>DNS-over-TLS</1>,您需要在 AdGuard Home 設定裡<0>配置加密</0>。",
|
||||
"rewrite_added": "對於 \"{{key}}\" 之 DNS 改寫被成功地加入",
|
||||
"rewrite_deleted": "對於 \"{{key}}\" 之 DNS 改寫被成功地刪除",
|
||||
"rewrite_updated": "DNS 重寫已成功更新",
|
||||
"rewrite_add": "新增 DNS 改寫",
|
||||
"rewrite_edit": "編輯 DNS 重寫",
|
||||
"rewrite_not_found": "無已發現之 DNS 改寫",
|
||||
"rewrite_confirm_delete": "您確定您想要刪除對於 \"{{key}}\" 之 DNS 改寫嗎?",
|
||||
"rewrite_desc": "允許輕易地配置自訂的 DNS 回應供特定的域名。",
|
||||
@@ -668,5 +670,11 @@
|
||||
"disable_notify_for_hours": "計 {{count}} 小時禁用防護",
|
||||
"disable_notify_for_hours_plural": "計 {{count}} 小時禁用防護",
|
||||
"disable_notify_until_tomorrow": "禁用防護直到明天",
|
||||
"enable_protection_timer": "防護將於 {{time}} 被啟用"
|
||||
"enable_protection_timer": "防護將於 {{time}} 被啟用",
|
||||
"custom_retention_input": "輸入保留時間(小時)",
|
||||
"custom_rotation_input": "輸入旋轉時間(小時)",
|
||||
"protection_section_label": "防護",
|
||||
"log_and_stats_section_label": "查詢記錄和統計資料",
|
||||
"ignore_query_log": "在查詢記錄中忽略此用戶端",
|
||||
"ignore_statistics": "在統計資料中忽略此用戶端"
|
||||
}
|
||||
|
||||
@@ -38,6 +38,29 @@ 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 deleteRewriteFailure = createAction('DELETE_REWRITE_FAILURE');
|
||||
export const deleteRewriteSuccess = createAction('DELETE_REWRITE_SUCCESS');
|
||||
|
||||
@@ -455,6 +455,8 @@ class Api {
|
||||
|
||||
REWRITE_ADD = { path: 'rewrite/add', method: 'POST' };
|
||||
|
||||
REWRITE_UPDATE = { path: 'rewrite/update', method: 'PUT' };
|
||||
|
||||
REWRITE_DELETE = { path: 'rewrite/delete', method: 'POST' };
|
||||
|
||||
getRewritesList() {
|
||||
@@ -470,6 +472,14 @@ class Api {
|
||||
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) {
|
||||
const { path, method } = this.REWRITE_DELETE;
|
||||
const parameters = {
|
||||
|
||||
@@ -6,7 +6,7 @@ import { shallowEqual, useSelector } from 'react-redux';
|
||||
import Card from '../ui/Card';
|
||||
import { formatNumber } from '../../helpers/helpers';
|
||||
import LogsSearchLink from '../ui/LogsSearchLink';
|
||||
import { RESPONSE_FILTER } from '../../helpers/constants';
|
||||
import { RESPONSE_FILTER, DAY } from '../../helpers/constants';
|
||||
import Tooltip from '../ui/Tooltip';
|
||||
|
||||
const Row = ({
|
||||
@@ -54,12 +54,12 @@ const Counters = ({ refreshButton, subtitle }) => {
|
||||
avgProcessingTime,
|
||||
} = useSelector((state) => state.stats, shallowEqual);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const days = interval / DAY;
|
||||
const rows = [
|
||||
{
|
||||
label: 'dns_query',
|
||||
count: numDnsQueries,
|
||||
tooltipTitle: interval === 1 ? 'number_of_dns_query_24_hours' : t('number_of_dns_query_days', { count: interval }),
|
||||
tooltipTitle: days === 1 ? 'number_of_dns_query_24_hours' : t('number_of_dns_query_days', { count: days }),
|
||||
response_status: RESPONSE_FILTER.ALL.QUERY,
|
||||
},
|
||||
{
|
||||
|
||||
@@ -105,6 +105,7 @@ Form.propTypes = {
|
||||
submitting: PropTypes.bool.isRequired,
|
||||
processingAdd: PropTypes.bool.isRequired,
|
||||
t: PropTypes.func.isRequired,
|
||||
initialValues: PropTypes.object,
|
||||
};
|
||||
|
||||
export default flow([
|
||||
|
||||
@@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
|
||||
import { Trans, withTranslation } from 'react-i18next';
|
||||
import ReactModal from 'react-modal';
|
||||
|
||||
import { MODAL_TYPE } from '../../../helpers/constants';
|
||||
import Form from './Form';
|
||||
|
||||
const Modal = (props) => {
|
||||
@@ -12,6 +13,8 @@ const Modal = (props) => {
|
||||
toggleRewritesModal,
|
||||
processingAdd,
|
||||
processingDelete,
|
||||
modalType,
|
||||
currentRewrite,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
@@ -24,13 +27,18 @@ const Modal = (props) => {
|
||||
<div className="modal-content">
|
||||
<div className="modal-header">
|
||||
<h4 className="modal-title">
|
||||
<Trans>rewrite_add</Trans>
|
||||
{modalType === MODAL_TYPE.EDIT_REWRITE ? (
|
||||
<Trans>rewrite_edit</Trans>
|
||||
) : (
|
||||
<Trans>rewrite_add</Trans>
|
||||
)}
|
||||
</h4>
|
||||
<button type="button" className="close" onClick={() => toggleRewritesModal()}>
|
||||
<span className="sr-only">Close</span>
|
||||
</button>
|
||||
</div>
|
||||
<Form
|
||||
initialValues={{ ...currentRewrite }}
|
||||
onSubmit={handleSubmit}
|
||||
toggleRewritesModal={toggleRewritesModal}
|
||||
processingAdd={processingAdd}
|
||||
@@ -47,6 +55,8 @@ Modal.propTypes = {
|
||||
toggleRewritesModal: PropTypes.func.isRequired,
|
||||
processingAdd: PropTypes.bool.isRequired,
|
||||
processingDelete: PropTypes.bool.isRequired,
|
||||
modalType: PropTypes.string.isRequired,
|
||||
currentRewrite: PropTypes.object,
|
||||
};
|
||||
|
||||
export default withTranslation()(Modal);
|
||||
|
||||
@@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
|
||||
import ReactTable from 'react-table';
|
||||
import { withTranslation } from 'react-i18next';
|
||||
import { sortIp } from '../../../helpers/helpers';
|
||||
import { MODAL_TYPE } from '../../../helpers/constants';
|
||||
|
||||
class Table extends Component {
|
||||
cellWrap = ({ value }) => (
|
||||
@@ -31,24 +32,44 @@ class Table extends Component {
|
||||
maxWidth: 100,
|
||||
sortable: false,
|
||||
resizable: false,
|
||||
Cell: (value) => (
|
||||
<div className="logs__row logs__row--center">
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-icon btn-icon--green btn-outline-secondary btn-sm"
|
||||
onClick={() => this.props.handleDelete({
|
||||
answer: value.row.answer,
|
||||
domain: value.row.domain,
|
||||
})
|
||||
}
|
||||
title={this.props.t('delete_table_action')}
|
||||
>
|
||||
<svg className="icons">
|
||||
<use xlinkHref="#delete" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
),
|
||||
Cell: (value) => {
|
||||
const currentRewrite = {
|
||||
answer: value.row.answer,
|
||||
domain: value.row.domain,
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="logs__row logs__row--center">
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-icon btn-outline-primary btn-sm mr-2"
|
||||
onClick={() => {
|
||||
this.props.toggleRewritesModal({
|
||||
type: MODAL_TYPE.EDIT_REWRITE,
|
||||
currentRewrite,
|
||||
});
|
||||
}}
|
||||
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>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@@ -84,7 +105,9 @@ Table.propTypes = {
|
||||
processing: PropTypes.bool.isRequired,
|
||||
processingAdd: PropTypes.bool.isRequired,
|
||||
processingDelete: PropTypes.bool.isRequired,
|
||||
processingUpdate: PropTypes.bool.isRequired,
|
||||
handleDelete: PropTypes.func.isRequired,
|
||||
toggleRewritesModal: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default withTranslation()(Table);
|
||||
|
||||
@@ -6,16 +6,13 @@ import Table from './Table';
|
||||
import Modal from './Modal';
|
||||
import Card from '../../ui/Card';
|
||||
import PageTitle from '../../ui/PageTitle';
|
||||
import { MODAL_TYPE } from '../../../helpers/constants';
|
||||
|
||||
class Rewrites extends Component {
|
||||
componentDidMount() {
|
||||
this.props.getRewritesList();
|
||||
}
|
||||
|
||||
handleSubmit = (values) => {
|
||||
this.props.addRewrite(values);
|
||||
};
|
||||
|
||||
handleDelete = (values) => {
|
||||
// eslint-disable-next-line no-alert
|
||||
if (window.confirm(this.props.t('rewrite_confirm_delete', { key: values.domain }))) {
|
||||
@@ -23,6 +20,19 @@ 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() {
|
||||
const {
|
||||
t,
|
||||
@@ -36,6 +46,9 @@ class Rewrites extends Component {
|
||||
processing,
|
||||
processingAdd,
|
||||
processingDelete,
|
||||
processingUpdate,
|
||||
modalType,
|
||||
currentRewrite,
|
||||
} = rewrites;
|
||||
|
||||
return (
|
||||
@@ -54,13 +67,15 @@ class Rewrites extends Component {
|
||||
processing={processing}
|
||||
processingAdd={processingAdd}
|
||||
processingDelete={processingDelete}
|
||||
processingUpdate={processingUpdate}
|
||||
handleDelete={this.handleDelete}
|
||||
toggleRewritesModal={toggleRewritesModal}
|
||||
/>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-success btn-standard mt-3"
|
||||
onClick={() => toggleRewritesModal()}
|
||||
onClick={() => toggleRewritesModal({ type: MODAL_TYPE.ADD_REWRITE })}
|
||||
disabled={processingAdd}
|
||||
>
|
||||
<Trans>rewrite_add</Trans>
|
||||
@@ -68,10 +83,13 @@ class Rewrites extends Component {
|
||||
|
||||
<Modal
|
||||
isModalOpen={isModalOpen}
|
||||
modalType={modalType}
|
||||
toggleRewritesModal={toggleRewritesModal}
|
||||
handleSubmit={this.handleSubmit}
|
||||
processingAdd={processingAdd}
|
||||
processingDelete={processingDelete}
|
||||
processingUpdate={processingUpdate}
|
||||
currentRewrite={currentRewrite}
|
||||
/>
|
||||
</Fragment>
|
||||
</Card>
|
||||
@@ -86,6 +104,7 @@ Rewrites.propTypes = {
|
||||
toggleRewritesModal: PropTypes.func.isRequired,
|
||||
addRewrite: PropTypes.func.isRequired,
|
||||
deleteRewrite: PropTypes.func.isRequired,
|
||||
updateRewrite: PropTypes.func.isRequired,
|
||||
rewrites: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ class Table extends Component {
|
||||
Header: <Trans>list_url_table_header</Trans>,
|
||||
accessor: 'url',
|
||||
minWidth: 180,
|
||||
// eslint-disable-next-line react/prop-types
|
||||
Cell: ({ value }) => (
|
||||
<div className="logs__row">
|
||||
{isValidAbsolutePath(value) ? value
|
||||
|
||||
@@ -32,6 +32,8 @@ const ProtectionTimer = ({
|
||||
};
|
||||
|
||||
ProtectionTimer.propTypes = {
|
||||
protectionDisabledDuration: PropTypes.number,
|
||||
toggleProtectionSuccess: PropTypes.func.isRequired,
|
||||
setProtectionTimerTime: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
|
||||
@@ -27,7 +27,6 @@ import {
|
||||
} from '../../../helpers/constants';
|
||||
import '../FormButton.css';
|
||||
|
||||
|
||||
const getIntervalTitle = (interval, t) => {
|
||||
switch (interval) {
|
||||
case RETENTION_CUSTOM:
|
||||
|
||||
@@ -7,7 +7,6 @@ import { Trans, withTranslation } from 'react-i18next';
|
||||
import flow from 'lodash/flow';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
|
||||
import {
|
||||
renderRadioField,
|
||||
toNumber,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
.card-header {
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0.6rem 1.5rem;
|
||||
padding: 10px 24px;
|
||||
}
|
||||
|
||||
.card-subtitle {
|
||||
@@ -16,11 +16,11 @@
|
||||
|
||||
.card-table-overflow--limited {
|
||||
overflow-y: auto;
|
||||
max-height: 17.5rem;
|
||||
max-height: 280px;
|
||||
}
|
||||
|
||||
.dashboard .card-table-overflow--limited {
|
||||
max-height: 18rem;
|
||||
max-height: 288px;
|
||||
}
|
||||
|
||||
.card-actions {
|
||||
@@ -38,7 +38,7 @@
|
||||
}
|
||||
|
||||
.card-body--status {
|
||||
padding: 2.5rem 1.5rem;
|
||||
padding: 40px 24px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@@ -81,14 +81,14 @@
|
||||
position: relative;
|
||||
flex: 1 1 auto;
|
||||
margin: 0;
|
||||
padding: 1rem 1.5rem;
|
||||
padding: 16px 24px;
|
||||
}
|
||||
|
||||
.card-value-stats {
|
||||
display: block;
|
||||
font-size: 2.1rem;
|
||||
line-height: 2.7rem;
|
||||
height: 2.7rem;
|
||||
height: 44px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
@@ -108,7 +108,7 @@
|
||||
}
|
||||
|
||||
.card--full {
|
||||
height: calc(100% - 1.5rem);
|
||||
height: calc(100% - 22px);
|
||||
}
|
||||
|
||||
.card-wrap {
|
||||
@@ -125,7 +125,7 @@
|
||||
|
||||
@media (min-width: 992px) {
|
||||
.dashboard .card:not(.card--full) {
|
||||
height: 22rem;
|
||||
height: 350px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable react/no-unknown-property */
|
||||
import React from 'react';
|
||||
|
||||
import './Icons.css';
|
||||
|
||||
@@ -13363,7 +13363,7 @@ a.icon:hover {
|
||||
padding: 0.5rem 1.5rem;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
min-height: 3.5rem;
|
||||
min-height: 60px;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
getRewritesList,
|
||||
addRewrite,
|
||||
deleteRewrite,
|
||||
updateRewrite,
|
||||
toggleRewritesModal,
|
||||
} from '../actions/rewrites';
|
||||
import Rewrites from '../components/Filters/Rewrites';
|
||||
@@ -17,6 +18,7 @@ const mapDispatchToProps = {
|
||||
getRewritesList,
|
||||
addRewrite,
|
||||
deleteRewrite,
|
||||
updateRewrite,
|
||||
toggleRewritesModal,
|
||||
};
|
||||
|
||||
|
||||
@@ -173,6 +173,8 @@ export const MODAL_TYPE = {
|
||||
ADD_FILTERS: 'ADD_FILTERS',
|
||||
EDIT_FILTERS: 'EDIT_FILTERS',
|
||||
CHOOSE_FILTERING_LIST: 'CHOOSE_FILTERING_LIST',
|
||||
ADD_REWRITE: 'ADD_REWRITE',
|
||||
EDIT_REWRITE: 'EDIT_REWRITE',
|
||||
};
|
||||
|
||||
export const CLIENT_ID = {
|
||||
|
||||
@@ -100,6 +100,12 @@ export default {
|
||||
"homepage": "https://github.com/DandelionSprout/adfilt",
|
||||
"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": {
|
||||
"name": "POL: Polish filters for Pi-hole",
|
||||
"categoryId": "regional",
|
||||
@@ -118,6 +124,12 @@ export default {
|
||||
"homepage": "https://github.com/bkrucarci/turk-adlist",
|
||||
"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": {
|
||||
"name": "VNM: ABPVN List",
|
||||
"categoryId": "regional",
|
||||
@@ -214,6 +226,12 @@ export default {
|
||||
"homepage": "https://github.com/durablenapkin/scamblocklist",
|
||||
"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": {
|
||||
"name": "Stalkerware Indicators List",
|
||||
"categoryId": "security",
|
||||
|
||||
@@ -845,7 +845,6 @@ export const sortIp = (a, b) => {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {number} filterId
|
||||
* @returns {string}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -30,7 +30,27 @@ const rewrites = handleActions(
|
||||
[actions.deleteRewriteFailure]: (state) => ({ ...state, processingDelete: false }),
|
||||
[actions.deleteRewriteSuccess]: (state) => ({ ...state, processingDelete: false }),
|
||||
|
||||
[actions.toggleRewritesModal]: (state) => {
|
||||
[actions.updateRewriteRequest]: (state) => ({ ...state, processingUpdate: true }),
|
||||
[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 = {
|
||||
...state,
|
||||
isModalOpen: !state.isModalOpen,
|
||||
@@ -42,7 +62,10 @@ const rewrites = handleActions(
|
||||
processing: true,
|
||||
processingAdd: false,
|
||||
processingDelete: false,
|
||||
processingUpdate: false,
|
||||
isModalOpen: false,
|
||||
modalType: '',
|
||||
currentRewrite: {},
|
||||
list: [],
|
||||
},
|
||||
);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# A docker file for scripts/make/build-docker.sh.
|
||||
|
||||
FROM alpine:3.17
|
||||
FROM alpine:3.18
|
||||
|
||||
ARG BUILD_DATE
|
||||
ARG VERSION
|
||||
@@ -25,8 +25,6 @@ RUN apk --no-cache add ca-certificates libcap tzdata && \
|
||||
mkdir -p /opt/adguardhome/conf /opt/adguardhome/work && \
|
||||
chown -R nobody: /opt/adguardhome
|
||||
|
||||
RUN apk --no-cache add tini
|
||||
|
||||
ARG DIST_DIR
|
||||
ARG TARGETARCH
|
||||
ARG TARGETOS
|
||||
@@ -43,45 +41,25 @@ RUN setcap 'cap_net_bind_service=+eip' /opt/adguardhome/AdGuardHome
|
||||
# 68 : UDP : DHCP (client)
|
||||
# 80 : TCP : HTTP (main)
|
||||
# 443 : TCP, UDP : HTTPS, DNS-over-HTTPS (incl. HTTP/3), DNSCrypt (main)
|
||||
# 784 : UDP : DNS-over-QUIC (experimental)
|
||||
# 784 : UDP : DNS-over-QUIC (deprecated; use 853)
|
||||
# 853 : TCP, UDP : DNS-over-TLS, DNS-over-QUIC
|
||||
# 3000 : TCP, UDP : HTTP(S) (alt, incl. HTTP/3)
|
||||
# 3001 : TCP, UDP : HTTP(S) (beta, incl. HTTP/3)
|
||||
# 5443 : TCP, UDP : DNSCrypt (alt)
|
||||
# 6060 : TCP : HTTP (pprof)
|
||||
# 8853 : UDP : DNS-over-QUIC (experimental)
|
||||
# 8853 : UDP : DNS-over-QUIC (deprecated; use 853)
|
||||
#
|
||||
# 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
|
||||
853/tcp 853/udp 3000/tcp 3000/udp 5443/tcp 5443/udp 6060/tcp\
|
||||
8853/udp
|
||||
|
||||
WORKDIR /opt/adguardhome/work
|
||||
|
||||
# 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", "--" ]
|
||||
ENTRYPOINT ["/opt/adguardhome/AdGuardHome"]
|
||||
|
||||
CMD [ \
|
||||
"/opt/adguardhome/AdGuardHome", \
|
||||
"--no-check-update", \
|
||||
"-c", "/opt/adguardhome/conf/AdGuardHome.yaml", \
|
||||
"-h", "0.0.0.0", \
|
||||
"-w", "/opt/adguardhome/work" \
|
||||
]
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
/^[^[: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 == "::") {
|
||||
delete addrs
|
||||
addrs["localhost"] = true
|
||||
|
||||
# Drop all the other addresses.
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
#!/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
|
||||
|
||||
# TODO(e.burkov): Deal with 0 port.
|
||||
case "$( echo "$dns_hosts" | head -n 1 )"
|
||||
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
|
||||
|
||||
echo "$dns_hosts" | while read -r host
|
||||
do
|
||||
nslookup -type=a healthcheck.adguardhome.test. "$host" > /dev/null ||\
|
||||
error_exit "nslookup failed for $host"
|
||||
done
|
||||
@@ -1,13 +0,0 @@
|
||||
# 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
|
||||
}
|
||||
}
|
||||
43
go.mod
43
go.mod
@@ -3,11 +3,13 @@ module github.com/AdguardTeam/AdGuardHome
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/AdguardTeam/dnsproxy v0.48.3
|
||||
github.com/AdguardTeam/golibs v0.13.2
|
||||
// TODO(a.garipov): Update to a tagged version when it's released.
|
||||
github.com/AdguardTeam/dnsproxy v0.50.3-0.20230628054307-31e374065768
|
||||
github.com/AdguardTeam/golibs v0.13.3
|
||||
github.com/AdguardTeam/urlfilter v0.16.1
|
||||
github.com/NYTimes/gziphandler v1.1.1
|
||||
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/dimfeld/httptreemux/v5 v5.5.0
|
||||
github.com/fsnotify/fsnotify v1.6.0
|
||||
@@ -16,24 +18,24 @@ require (
|
||||
github.com/google/gopacket v1.1.19
|
||||
github.com/google/renameio v1.0.1
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/insomniacslk/dhcp v0.0.0-20221215072855-de60144f33f8
|
||||
github.com/insomniacslk/dhcp v0.0.0-20230612134759-b20c9ba983df
|
||||
github.com/josharian/native v1.1.1-0.20230202152459-5c7d0dd6ab86
|
||||
github.com/kardianos/service v1.2.2
|
||||
github.com/mdlayher/ethernet v0.0.0-20220221185849-529eae5b6118
|
||||
github.com/mdlayher/netlink v1.7.1
|
||||
github.com/mdlayher/packet v1.1.1
|
||||
github.com/mdlayher/netlink v1.7.2
|
||||
github.com/mdlayher/packet v1.1.2
|
||||
// TODO(a.garipov): This package is deprecated; find a new one or use our
|
||||
// own code for that. Perhaps, use gopacket.
|
||||
github.com/mdlayher/raw v0.1.0
|
||||
github.com/miekg/dns v1.1.53
|
||||
github.com/quic-go/quic-go v0.33.0
|
||||
github.com/stretchr/testify v1.8.2
|
||||
github.com/miekg/dns v1.1.55
|
||||
github.com/quic-go/quic-go v0.35.1
|
||||
github.com/stretchr/testify v1.8.4
|
||||
github.com/ti-mo/netfilter v0.5.0
|
||||
go.etcd.io/bbolt v1.3.7
|
||||
golang.org/x/crypto v0.8.0
|
||||
golang.org/x/exp v0.0.0-20230321023759-10a507213a29
|
||||
golang.org/x/net v0.9.0
|
||||
golang.org/x/sys v0.7.0
|
||||
golang.org/x/crypto v0.10.0
|
||||
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df
|
||||
golang.org/x/net v0.11.0
|
||||
golang.org/x/sys v0.9.0
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
howett.net/plist v1.0.0
|
||||
@@ -44,23 +46,22 @@ require (
|
||||
github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635 // indirect
|
||||
github.com/ameshkov/dnsstamps v1.0.3 // 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/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
|
||||
github.com/golang/mock v1.6.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20230406165453-00490a63f317 // indirect
|
||||
github.com/mdlayher/socket v0.4.0 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.9.2 // indirect
|
||||
github.com/google/pprof v0.0.0-20230602150820-91b7bce49751 // indirect
|
||||
github.com/mdlayher/socket v0.4.1 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.11.0 // indirect
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.17 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.18 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/quic-go/qpack v0.4.0 // indirect
|
||||
github.com/quic-go/qtls-go1-19 v0.3.2 // indirect
|
||||
github.com/quic-go/qtls-go1-20 v0.2.2 // indirect
|
||||
github.com/u-root/uio v0.0.0-20230305220412-3e8cd9d6bf63 // indirect
|
||||
golang.org/x/mod v0.10.0 // indirect
|
||||
golang.org/x/sync v0.1.0 // indirect
|
||||
golang.org/x/text v0.9.0 // indirect
|
||||
golang.org/x/tools v0.8.0 // indirect
|
||||
golang.org/x/mod v0.11.0 // indirect
|
||||
golang.org/x/sync v0.3.0 // indirect
|
||||
golang.org/x/text v0.10.0 // indirect
|
||||
golang.org/x/tools v0.10.0 // indirect
|
||||
)
|
||||
|
||||
127
go.sum
127
go.sum
@@ -1,9 +1,9 @@
|
||||
github.com/AdguardTeam/dnsproxy v0.48.3 h1:h9xgDSmd1MqsPFNApyaPVXolmSTtzOWOcfWvPeDEP6s=
|
||||
github.com/AdguardTeam/dnsproxy v0.48.3/go.mod h1:Y7g7jRTd/u7+KJ/QvnGI2PCE8vnisp6EsW47/Sz0DZw=
|
||||
github.com/AdguardTeam/dnsproxy v0.50.3-0.20230628054307-31e374065768 h1:5Ia6wA+tqAlTyzuaOVGSlHmb0osLWXeJUs3NxCuC4gA=
|
||||
github.com/AdguardTeam/dnsproxy v0.50.3-0.20230628054307-31e374065768/go.mod h1:CQhZTkqC8X0ID6glrtyaxgqRRdiYfn1gJulC1cZ5Dn8=
|
||||
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.13.2 h1:BPASsyQKmb+b8VnvsNOHp7bKfcZl9Z+Z2UhPjOiupSc=
|
||||
github.com/AdguardTeam/golibs v0.13.2/go.mod h1:7ylQLv2Lqsc3UW3jHoITynYk6Y1tYtgEMkR09ppfsN8=
|
||||
github.com/AdguardTeam/golibs v0.13.3 h1:RT3QbzThtaLiFLkIUDS6/hlGEXrh0zYvdf4bd7UWpGo=
|
||||
github.com/AdguardTeam/golibs v0.13.3/go.mod h1:wkJ6EUsN4np/9Gp7+9QeooY9E2U2WCLJYAioLCzkHsI=
|
||||
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/go.mod h1:46YZDOV1+qtdRDuhZKVPSSp7JWWes0KayqHrKAFBdEI=
|
||||
@@ -31,10 +31,9 @@ github.com/digineo/go-ipset/v2 v2.2.1 h1:k6skY+0fMqeUjjeWO/m5OuWPSZUAn7AucHMnQ1M
|
||||
github.com/digineo/go-ipset/v2 v2.2.1/go.mod h1:wBsNzJlZlABHUITkesrggFnZQtgW5wkqw1uo8Qxe0VU=
|
||||
github.com/dimfeld/httptreemux/v5 v5.5.0 h1:p8jkiMrCuZ0CmhwYLcbNbl7DDo21fozhKHQ2PccwOFQ=
|
||||
github.com/dimfeld/httptreemux/v5 v5.5.0/go.mod h1:QeEylH57C0v3VO0tkKraVz9oD3Uu93CKPnTLbsidvSw=
|
||||
github.com/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/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
||||
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
|
||||
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
|
||||
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-ping/ping v1.1.0 h1:3MCGhVX4fyEUuhsfwPrsEdQw6xspHkv5zHsiSoDFZYw=
|
||||
@@ -45,77 +44,59 @@ 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/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.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.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/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
|
||||
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
|
||||
github.com/google/pprof v0.0.0-20230406165453-00490a63f317 h1:hFhpt7CTmR3DX+b4R19ydQFtofxT0Sv3QsKNMVQYTMQ=
|
||||
github.com/google/pprof v0.0.0-20230406165453-00490a63f317/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk=
|
||||
github.com/google/pprof v0.0.0-20230602150820-91b7bce49751 h1:hR7/MlvK23p6+lIw9SN1TigNLn9ZnF3W4SYRKq2gAHs=
|
||||
github.com/google/pprof v0.0.0-20230602150820-91b7bce49751/go.mod h1:Jh3hGz2jkYak8qXPD19ryItVnUgpgeqzdkY/D0EaeuA=
|
||||
github.com/google/renameio v1.0.1 h1:Lh/jXZmvZxb0BBeSY5VKEfidcbcbenKjZFzM/q0fSeU=
|
||||
github.com/google/renameio v1.0.1/go.mod h1:t/HQoYBZSsWSNK35C6CO/TpPLDVWvxOHboWUAweKUpk=
|
||||
github.com/google/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/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/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis=
|
||||
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/insomniacslk/dhcp v0.0.0-20230612134759-b20c9ba983df h1:pF1MMIzEJzJ/MyI4bXYXVYyN8CJgoQ2PPKT2z3O/Cl4=
|
||||
github.com/insomniacslk/dhcp v0.0.0-20230612134759-b20c9ba983df/go.mod h1:7474bZ1YNCvarT6WFKie4kEET6J0KYRDC4XJqqXzQW4=
|
||||
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.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/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/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM=
|
||||
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.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
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/go.mod h1:ZFUnHIVchZ9lJoWoEGUg8Q3M4U8aNNWA3CVSUTkW4og=
|
||||
github.com/mdlayher/netlink v0.0.0-20190313131330-258ea9dff42c/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA=
|
||||
github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA=
|
||||
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/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g=
|
||||
github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw=
|
||||
github.com/mdlayher/packet v1.0.0/go.mod h1:eE7/ctqDhoiRhQ44ko5JZU2zxB88g+JH/6jmnjzPjOU=
|
||||
github.com/mdlayher/packet v1.1.1 h1:7Fv4OEMYqPl7//uBm04VgPpnSNi8fbBZznppgh6WMr8=
|
||||
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/packet v1.1.2 h1:3Up1NG6LZrsgDVn6X4L9Ge/iyRyxFEFD9o6Pr3Q1nQY=
|
||||
github.com/mdlayher/packet v1.1.2/go.mod h1:GEu1+n9sG5VtiRE4SydOmX5GTwyyYlteZiFU+x0kew4=
|
||||
github.com/mdlayher/raw v0.1.0 h1:K4PFMVy+AFsp0Zdlrts7yNhxc/uXoPVHi9RzRvtZF2Y=
|
||||
github.com/mdlayher/raw v0.1.0/go.mod h1:yXnxvs6c0XoF/aK52/H5PjsVHmWBCFfZUfoh/Y5s9Sg=
|
||||
github.com/mdlayher/socket v0.2.1/go.mod h1:QLlNPkFR88mRUNQIzRBMfXxwKal8H7u1h3bL1CV+f0E=
|
||||
github.com/mdlayher/socket v0.4.0 h1:280wsy40IC9M9q1uPGcLBwXpcTQDtoGwVt+BNoITxIw=
|
||||
github.com/mdlayher/socket v0.4.0/go.mod h1:xxFqz5GRCUN3UEOm9CZqEJsAbe1C8OwSK46NlmWuVoc=
|
||||
github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U=
|
||||
github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA=
|
||||
github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
|
||||
github.com/miekg/dns v1.1.53 h1:ZBkuHr5dxHtB1caEOlZTLPo7D3L3TWckgUUs/RHfDxw=
|
||||
github.com/miekg/dns v1.1.53/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY=
|
||||
github.com/miekg/dns v1.1.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo=
|
||||
github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/onsi/ginkgo/v2 v2.9.2 h1:BA2GMJOtfGAfagzYtrAlufIP0lq6QERkFmHLMLPwFSU=
|
||||
github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts=
|
||||
github.com/onsi/gomega v1.27.4 h1:Z2AnStgsdSayCMDiCU42qIz+HLqEPcgiOCXjAU/w+8E=
|
||||
github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU=
|
||||
github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM=
|
||||
github.com/onsi/gomega v1.27.8 h1:gegWiwZjBsf2DgiSbf5hpokZ98JVDMcWkUiigk6/KXc=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||
github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/pierrec/lz4/v4 v4.1.17 h1:kV4Ip+/hUBC+8T6+2EgburRtkE9ef4nbY3f4dFhGjMc=
|
||||
github.com/pierrec/lz4/v4 v4.1.17/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/pierrec/lz4/v4 v4.1.18 h1:xaKrnTkyoqfh1YItXl56+6KJNVYWlEEPuAQW9xsplYQ=
|
||||
github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
@@ -127,24 +108,18 @@ 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-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/quic-go v0.33.0 h1:ItNoTDN/Fm/zBlq769lLJc8ECe9gYaW40veHCCco7y0=
|
||||
github.com/quic-go/quic-go v0.33.0/go.mod h1:YMuhaAV9/jIu0XclDXwZPAsP/2Kgr5yMYhe9oxhhOFA=
|
||||
github.com/quic-go/quic-go v0.35.1 h1:b0kzj6b/cQAf05cT0CkQubHM31wiA+xH3IBkxP62poo=
|
||||
github.com/quic-go/quic-go v0.35.1/go.mod h1:+4CVgVppm0FNjpG3UcX8Joi/frKOH7/ciD5yGcwOO1g=
|
||||
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/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.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/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
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.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.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
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/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
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/go.mod h1:nt+8B9hx/QpqHr7Hazq+2qMCCA8u2OTkyc/7+U9ARz8=
|
||||
@@ -152,7 +127,6 @@ 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/numcpus v0.3.0 h1:ILuRUQBtssgnxw0XXIjKUC56fgnOrFoQQ/4+DeU2biQ=
|
||||
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/go.mod h1:eLL9Nub3yfAho7qB0MzZizFhTU2QkLeoVsWdHtDW264=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
@@ -160,52 +134,36 @@ go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ=
|
||||
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-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ=
|
||||
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
|
||||
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/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM=
|
||||
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
|
||||
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df h1:UA2aFVmmsIlefxMk29Dp2juaUSth8Pyn3Tq5Y5mJGME=
|
||||
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
|
||||
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.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
|
||||
golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU=
|
||||
golang.org/x/mod v0.11.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-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-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-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-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-20210929193557-e81a3d93ecf6/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
|
||||
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
||||
golang.org/x/net v0.11.0 h1:Gi2tvZIJyBtO9SDr1q9h5hEQCp/4L2RQ+ar0qjx2oNU=
|
||||
golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
|
||||
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.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
|
||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190322080309-f49334f85ddc/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
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-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-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-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-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -219,23 +177,22 @@ 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-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.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
|
||||
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
|
||||
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.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.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.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58=
|
||||
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-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-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.8.0 h1:vSDcovVPld282ceKgDimkRSC8kpaH1dgyc9UMzlt84Y=
|
||||
golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4=
|
||||
golang.org/x/tools v0.10.0 h1:tvDr/iQoUqNdohiYm0LmmKcBk+q86lb9EprIUFhHHGg=
|
||||
golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM=
|
||||
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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
||||
@@ -72,8 +72,8 @@ func WriteJSONResponse(w http.ResponseWriter, r *http.Request, resp any) (err er
|
||||
// WriteJSONResponseCode is like [WriteJSONResponse] but adds the ability to
|
||||
// redefine the status code.
|
||||
func WriteJSONResponseCode(w http.ResponseWriter, r *http.Request, code int, resp any) (err error) {
|
||||
w.WriteHeader(code)
|
||||
w.Header().Set(httphdr.ContentType, HdrValApplicationJSON)
|
||||
w.WriteHeader(code)
|
||||
err = json.NewEncoder(w).Encode(resp)
|
||||
if err != nil {
|
||||
Error(r, w, http.StatusInternalServerError, "encoding resp: %s", err)
|
||||
|
||||
@@ -304,7 +304,7 @@ func tryConn6(req *dhcpv6.Message, c net.PacketConn) (ok, next bool, err error)
|
||||
if !(response.Type() == dhcpv6.MessageTypeAdvertise &&
|
||||
msg.TransactionID == req.TransactionID &&
|
||||
rcid != nil &&
|
||||
cid.Equal(*rcid)) {
|
||||
cid.Equal(rcid)) {
|
||||
|
||||
log.Debug("dhcpv6: received message from server doesn't match our request")
|
||||
|
||||
|
||||
@@ -56,15 +56,20 @@ func (rm *requestMatcher) MatchRequest(
|
||||
) (res *urlfilter.DNSResult, ok bool) {
|
||||
switch req.DNSType {
|
||||
case dns.TypeA, dns.TypeAAAA, dns.TypePTR:
|
||||
log.Debug("%s: handling the request for %s", hostsContainerPrefix, req.Hostname)
|
||||
log.Debug(
|
||||
"%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:
|
||||
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
|
||||
@@ -96,6 +101,8 @@ const hostsContainerPrefix = "hosts container"
|
||||
|
||||
// HostsContainer stores the relevant hosts database provided by the OS and
|
||||
// processes both A/AAAA and PTR DNS requests for those.
|
||||
//
|
||||
// TODO(e.burkov): Improve API and move to golibs.
|
||||
type HostsContainer struct {
|
||||
// requestMatcher matches the requests and translates the rules. It's
|
||||
// embedded to implement MatchRequest and Translate for *HostsContainer.
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
//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")
|
||||
}
|
||||
6
internal/aghos/service.go
Normal file
6
internal/aghos/service.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package aghos
|
||||
|
||||
// PreCheckActionStart performs the service start action pre-check.
|
||||
func PreCheckActionStart() (err error) {
|
||||
return preCheckActionStart()
|
||||
}
|
||||
32
internal/aghos/service_darwin.go
Normal file
32
internal/aghos/service_darwin.go
Normal file
@@ -0,0 +1,32 @@
|
||||
//go:build darwin
|
||||
|
||||
package aghos
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
)
|
||||
|
||||
// preCheckActionStart performs the service start action pre-check. It warns
|
||||
// user that the service should be installed into Applications directory.
|
||||
func preCheckActionStart() (err error) {
|
||||
exe, err := os.Executable()
|
||||
if err != nil {
|
||||
return fmt.Errorf("getting executable path: %v", err)
|
||||
}
|
||||
|
||||
exe, err = filepath.EvalSymlinks(exe)
|
||||
if err != nil {
|
||||
return fmt.Errorf("evaluating executable symlinks: %v", err)
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(exe, "/Applications/") {
|
||||
log.Info("warning: service must be started from within the /Applications directory")
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
8
internal/aghos/service_others.go
Normal file
8
internal/aghos/service_others.go
Normal file
@@ -0,0 +1,8 @@
|
||||
//go:build !darwin
|
||||
|
||||
package aghos
|
||||
|
||||
// preCheckActionStart performs the service start action pre-check.
|
||||
func preCheckActionStart() (err error) {
|
||||
return nil
|
||||
}
|
||||
@@ -2,8 +2,8 @@ package aghtest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"io/fs"
|
||||
"net"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghos"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/next/agh"
|
||||
@@ -19,23 +19,23 @@ import (
|
||||
|
||||
// Package fs
|
||||
|
||||
// type check
|
||||
var _ fs.FS = &FS{}
|
||||
|
||||
// FS is a mock [fs.FS] implementation for tests.
|
||||
// FS is a fake [fs.FS] implementation for tests.
|
||||
type FS struct {
|
||||
OnOpen func(name string) (fs.File, error)
|
||||
}
|
||||
|
||||
// type check
|
||||
var _ fs.FS = (*FS)(nil)
|
||||
|
||||
// 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{}
|
||||
var _ fs.GlobFS = (*GlobFS)(nil)
|
||||
|
||||
// GlobFS is a mock [fs.GlobFS] implementation for tests.
|
||||
// GlobFS is a fake [fs.GlobFS] implementation for tests.
|
||||
type GlobFS struct {
|
||||
// FS is embedded here to avoid implementing all it's methods.
|
||||
FS
|
||||
@@ -48,9 +48,9 @@ func (fsys *GlobFS) Glob(pattern string) ([]string, error) {
|
||||
}
|
||||
|
||||
// type check
|
||||
var _ fs.StatFS = &StatFS{}
|
||||
var _ fs.StatFS = (*StatFS)(nil)
|
||||
|
||||
// StatFS is a mock [fs.StatFS] implementation for tests.
|
||||
// StatFS is a fake [fs.StatFS] implementation for tests.
|
||||
type StatFS struct {
|
||||
// FS is embedded here to avoid implementing all it's methods.
|
||||
FS
|
||||
@@ -62,47 +62,34 @@ func (fsys *StatFS) Stat(name string) (fs.FileInfo, error) {
|
||||
return fsys.OnStat(name)
|
||||
}
|
||||
|
||||
// Package net
|
||||
// Package io
|
||||
|
||||
// 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)
|
||||
// Writer is a fake [io.Writer] implementation for tests.
|
||||
type Writer struct {
|
||||
OnWrite func(b []byte) (n int, err error)
|
||||
}
|
||||
|
||||
// Accept implements the [net.Listener] interface for *Listener.
|
||||
func (l *Listener) Accept() (conn net.Conn, err error) {
|
||||
return l.OnAccept()
|
||||
}
|
||||
var _ io.Writer = (*Writer)(nil)
|
||||
|
||||
// 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()
|
||||
// Write implements the [io.Writer] interface for *Writer.
|
||||
func (w *Writer) Write(b []byte) (n int, err error) {
|
||||
return w.OnWrite(b)
|
||||
}
|
||||
|
||||
// Module adguard-home
|
||||
|
||||
// Package aghos
|
||||
|
||||
// type check
|
||||
var _ aghos.FSWatcher = (*FSWatcher)(nil)
|
||||
|
||||
// FSWatcher is a mock [aghos.FSWatcher] implementation for tests.
|
||||
// FSWatcher is a fake [aghos.FSWatcher] implementation for tests.
|
||||
type FSWatcher struct {
|
||||
OnEvents func() (e <-chan struct{})
|
||||
OnAdd func(name string) (err error)
|
||||
OnClose func() (err error)
|
||||
}
|
||||
|
||||
// type check
|
||||
var _ aghos.FSWatcher = (*FSWatcher)(nil)
|
||||
|
||||
// Events implements the [aghos.FSWatcher] interface for *FSWatcher.
|
||||
func (w *FSWatcher) Events() (e <-chan struct{}) {
|
||||
return w.OnEvents()
|
||||
@@ -120,16 +107,16 @@ func (w *FSWatcher) Close() (err error) {
|
||||
|
||||
// Package agh
|
||||
|
||||
// type check
|
||||
var _ agh.ServiceWithConfig[struct{}] = (*ServiceWithConfig[struct{}])(nil)
|
||||
|
||||
// ServiceWithConfig is a mock [agh.ServiceWithConfig] implementation for tests.
|
||||
// ServiceWithConfig is a fake [agh.ServiceWithConfig] implementation for tests.
|
||||
type ServiceWithConfig[ConfigType any] struct {
|
||||
OnStart func() (err error)
|
||||
OnShutdown func(ctx context.Context) (err error)
|
||||
OnConfig func() (c ConfigType)
|
||||
}
|
||||
|
||||
// type check
|
||||
var _ agh.ServiceWithConfig[struct{}] = (*ServiceWithConfig[struct{}])(nil)
|
||||
|
||||
// Start implements the [agh.ServiceWithConfig] interface for
|
||||
// *ServiceWithConfig.
|
||||
func (s *ServiceWithConfig[_]) Start() (err error) {
|
||||
@@ -152,10 +139,7 @@ func (s *ServiceWithConfig[ConfigType]) Config() (c ConfigType) {
|
||||
|
||||
// Package upstream
|
||||
|
||||
// type check
|
||||
var _ upstream.Upstream = (*UpstreamMock)(nil)
|
||||
|
||||
// UpstreamMock is a mock [upstream.Upstream] implementation for tests.
|
||||
// UpstreamMock is a fake [upstream.Upstream] implementation for tests.
|
||||
//
|
||||
// TODO(a.garipov): Replace with all uses of Upstream with UpstreamMock and
|
||||
// rename it to just Upstream.
|
||||
@@ -165,6 +149,9 @@ type UpstreamMock struct {
|
||||
OnClose func() (err error)
|
||||
}
|
||||
|
||||
// type check
|
||||
var _ upstream.Upstream = (*UpstreamMock)(nil)
|
||||
|
||||
// Address implements the [upstream.Upstream] interface for *UpstreamMock.
|
||||
func (u *UpstreamMock) Address() (addr string) {
|
||||
return u.OnAddress()
|
||||
|
||||
@@ -1,46 +1,60 @@
|
||||
# DHCP server
|
||||
# Testing DHCP Server
|
||||
|
||||
Contents:
|
||||
* [Test setup with Virtual Box](#vbox)
|
||||
* [Test setup with Virtual Box](#vbox)
|
||||
* [Quick test with DHCPTest](#dhcptest)
|
||||
|
||||
<a id="vbox"></a>
|
||||
## Test setup with Virtual Box
|
||||
## <a href="#vbox" id="vbox" name="vbox">Test setup with Virtual Box</a>
|
||||
|
||||
To set up a test environment for DHCP server you need:
|
||||
### Prerequisites
|
||||
|
||||
* Linux host machine
|
||||
* Virtual Box
|
||||
* Virtual machine (guest OS doesn't matter)
|
||||
To set up a test environment for DHCP server you will need:
|
||||
|
||||
### Configure client
|
||||
* Linux AG Home host machine (Virtual).
|
||||
* Virtual Box.
|
||||
* Virtual machine (guest OS doesn't matter).
|
||||
|
||||
1. Install Virtual Box and run the following command to create a Host-Only network:
|
||||
### Configure Virtual Box
|
||||
|
||||
$ VBoxManage hostonlyif create
|
||||
1. Install Virtual Box and run the following command to create a Host-Only
|
||||
network:
|
||||
|
||||
You can check its status by `ip a` command.
|
||||
```sh
|
||||
$ 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...
|
||||
```
|
||||
|
||||
File -> Host Network Manager...
|
||||
2. Create your virtual machine and set up its network:
|
||||
|
||||
2. Create your virtual machine and set up its network:
|
||||
```
|
||||
VM Settings -> Network -> Host-only Adapter
|
||||
```
|
||||
|
||||
VM Settings -> Network -> Host-only Adapter
|
||||
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.
|
||||
|
||||
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.
|
||||
4. To see the current IP addresses on client OS you can use `ip a` command on
|
||||
Linux or `ipconfig` on Windows.
|
||||
|
||||
4. To see the current IP address on client OS you can use `ip a` command on Linux or `ipconfig` on Windows.
|
||||
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.
|
||||
|
||||
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.
|
||||
### Configure server
|
||||
|
||||
### Configure server
|
||||
1. Edit server configuration file `AdGuardHome.yaml`, for example:
|
||||
|
||||
1. Edit server configuration file 'AdGuardHome.yaml', for example:
|
||||
|
||||
dhcp:
|
||||
```yaml
|
||||
dhcp:
|
||||
enabled: true
|
||||
interface_name: vboxnet0
|
||||
local_domain_name: lan
|
||||
dhcpv4:
|
||||
gateway_ip: 192.168.56.1
|
||||
subnet_mask: 255.255.255.0
|
||||
@@ -54,11 +68,29 @@ To set up a test environment for DHCP server you need:
|
||||
lease_duration: 86400
|
||||
ra_slaac_only: false
|
||||
ra_allow_slaac: false
|
||||
```
|
||||
|
||||
2. Start the server
|
||||
2. Start the server
|
||||
|
||||
./AdGuardHome
|
||||
```sh
|
||||
./AdGuardHome -v
|
||||
```
|
||||
|
||||
There should be a message in log which shows that DHCP server is ready:
|
||||
There should be a message in log which shows that DHCP server is ready:
|
||||
|
||||
[info] DHCP: listening on 0.0.0.0:67
|
||||
```
|
||||
[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
|
||||
|
||||
@@ -25,11 +25,8 @@ func (s *bitSet) isSet(n uint64) (ok bool) {
|
||||
|
||||
var word uint64
|
||||
word, ok = s.words[wordIdx]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
return word&(1<<bitIdx) != 0
|
||||
return ok && word&(1<<bitIdx) != 0
|
||||
}
|
||||
|
||||
// set sets or unsets a bit.
|
||||
|
||||
@@ -31,8 +31,16 @@ type ServerConfig struct {
|
||||
Conf4 V4ServerConf `yaml:"dhcpv4"`
|
||||
Conf6 V6ServerConf `yaml:"dhcpv6"`
|
||||
|
||||
WorkDir string `yaml:"-"`
|
||||
DBFilePath string `yaml:"-"`
|
||||
// WorkDir is used to store DHCP leases.
|
||||
//
|
||||
// Deprecated: Remove it when migration of DHCP leases will not be needed.
|
||||
WorkDir string `yaml:"-"`
|
||||
|
||||
// DataDir is used to store DHCP leases.
|
||||
DataDir string `yaml:"-"`
|
||||
|
||||
// dbFilePath is the path to the file with stored DHCP leases.
|
||||
dbFilePath string `yaml:"-"`
|
||||
}
|
||||
|
||||
// DHCPServer - DHCP server interface
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build darwin
|
||||
//go:build darwin || freebsd || openbsd
|
||||
|
||||
package dhcpd
|
||||
|
||||
@@ -249,31 +249,30 @@ func (c *dhcpConn) buildEtherPkt(payload []byte, peer *dhcpUnicastAddr) (pkt []b
|
||||
func (s *v4Server) send(peer net.Addr, conn net.PacketConn, req, resp *dhcpv4.DHCPv4) {
|
||||
switch giaddr, ciaddr, mtype := req.GatewayIPAddr, req.ClientIPAddr, resp.MessageType(); {
|
||||
case giaddr != nil && !giaddr.IsUnspecified():
|
||||
// Send any return messages to the server port on the BOOTP
|
||||
// relay agent whose address appears in giaddr.
|
||||
// Send any return messages to the server port on the BOOTP relay agent
|
||||
// whose address appears in giaddr.
|
||||
peer = &net.UDPAddr{
|
||||
IP: giaddr,
|
||||
Port: dhcpv4.ServerPort,
|
||||
}
|
||||
if mtype == dhcpv4.MessageTypeNak {
|
||||
// Set the broadcast bit in the DHCPNAK, so that the relay agent
|
||||
// broadcasts it to the client, because the client may not have
|
||||
// a correct network address or subnet mask, and the client may not
|
||||
// be answering ARP requests.
|
||||
// broadcasts it to the client, because the client may not have a
|
||||
// correct network address or subnet mask, and the client may not be
|
||||
// answering ARP requests.
|
||||
resp.SetBroadcast()
|
||||
}
|
||||
case mtype == dhcpv4.MessageTypeNak:
|
||||
// Broadcast any DHCPNAK messages to 0xffffffff.
|
||||
case ciaddr != nil && !ciaddr.IsUnspecified():
|
||||
// Unicast DHCPOFFER and DHCPACK messages to the address in
|
||||
// ciaddr.
|
||||
// Unicast DHCPOFFER and DHCPACK messages to the address in ciaddr.
|
||||
peer = &net.UDPAddr{
|
||||
IP: ciaddr,
|
||||
Port: dhcpv4.ClientPort,
|
||||
}
|
||||
case !req.IsBroadcast() && req.ClientHWAddr != nil:
|
||||
// Unicast DHCPOFFER and DHCPACK messages to the client's
|
||||
// hardware address and yiaddr.
|
||||
// Unicast DHCPOFFER and DHCPACK messages to the client's hardware
|
||||
// address and yiaddr.
|
||||
peer = &dhcpUnicastAddr{
|
||||
Addr: raw.Addr{HardwareAddr: req.ClientHWAddr},
|
||||
yiaddr: resp.YourIPAddr,
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build darwin
|
||||
//go:build darwin || freebsd || openbsd
|
||||
|
||||
package dhcpd
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build freebsd || linux || openbsd
|
||||
//go:build linux
|
||||
|
||||
package dhcpd
|
||||
|
||||
@@ -247,31 +247,30 @@ func (c *dhcpConn) buildEtherPkt(payload []byte, peer *dhcpUnicastAddr) (pkt []b
|
||||
func (s *v4Server) send(peer net.Addr, conn net.PacketConn, req, resp *dhcpv4.DHCPv4) {
|
||||
switch giaddr, ciaddr, mtype := req.GatewayIPAddr, req.ClientIPAddr, resp.MessageType(); {
|
||||
case giaddr != nil && !giaddr.IsUnspecified():
|
||||
// Send any return messages to the server port on the BOOTP
|
||||
// relay agent whose address appears in giaddr.
|
||||
// Send any return messages to the server port on the BOOTP relay agent
|
||||
// whose address appears in giaddr.
|
||||
peer = &net.UDPAddr{
|
||||
IP: giaddr,
|
||||
Port: dhcpv4.ServerPort,
|
||||
}
|
||||
if mtype == dhcpv4.MessageTypeNak {
|
||||
// Set the broadcast bit in the DHCPNAK, so that the relay agent
|
||||
// broadcasts it to the client, because the client may not have
|
||||
// a correct network address or subnet mask, and the client may not
|
||||
// be answering ARP requests.
|
||||
// broadcasts it to the client, because the client may not have a
|
||||
// correct network address or subnet mask, and the client may not be
|
||||
// answering ARP requests.
|
||||
resp.SetBroadcast()
|
||||
}
|
||||
case mtype == dhcpv4.MessageTypeNak:
|
||||
// Broadcast any DHCPNAK messages to 0xffffffff.
|
||||
case ciaddr != nil && !ciaddr.IsUnspecified():
|
||||
// Unicast DHCPOFFER and DHCPACK messages to the address in
|
||||
// ciaddr.
|
||||
// Unicast DHCPOFFER and DHCPACK messages to the address in ciaddr.
|
||||
peer = &net.UDPAddr{
|
||||
IP: ciaddr,
|
||||
Port: dhcpv4.ClientPort,
|
||||
}
|
||||
case !req.IsBroadcast() && req.ClientHWAddr != nil:
|
||||
// Unicast DHCPOFFER and DHCPACK messages to the client's
|
||||
// hardware address and yiaddr.
|
||||
// Unicast DHCPOFFER and DHCPACK messages to the client's hardware
|
||||
// address and yiaddr.
|
||||
peer = &dhcpUnicastAddr{
|
||||
Addr: packet.Addr{HardwareAddr: req.ClientHWAddr},
|
||||
yiaddr: resp.YourIPAddr,
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build freebsd || linux || openbsd
|
||||
//go:build linux
|
||||
|
||||
package dhcpd
|
||||
|
||||
@@ -5,43 +5,34 @@ package dhcpd
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
"github.com/google/renameio/maybe"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
const dbFilename = "leases.db"
|
||||
const (
|
||||
// dataFilename contains saved leases.
|
||||
dataFilename = "leases.json"
|
||||
|
||||
type leaseJSON struct {
|
||||
HWAddr []byte `json:"mac"`
|
||||
IP []byte `json:"ip"`
|
||||
Hostname string `json:"host"`
|
||||
Expiry int64 `json:"exp"`
|
||||
// dataVersion is the current version of the stored DHCP leases structure.
|
||||
dataVersion = 1
|
||||
)
|
||||
|
||||
// dataLeases is the structure of the stored DHCP leases.
|
||||
type dataLeases struct {
|
||||
// Version is the current version of the structure.
|
||||
Version int `json:"version"`
|
||||
|
||||
// Leases is the list containing stored DHCP leases.
|
||||
Leases []*Lease `json:"leases"`
|
||||
}
|
||||
|
||||
func normalizeIP(ip net.IP) net.IP {
|
||||
ip4 := ip.To4()
|
||||
if ip4 != nil {
|
||||
return ip4
|
||||
}
|
||||
return ip
|
||||
}
|
||||
|
||||
// Load lease table from DB
|
||||
//
|
||||
// TODO(s.chzhen): Decrease complexity.
|
||||
// dbLoad loads stored leases.
|
||||
func (s *server) dbLoad() (err error) {
|
||||
dynLeases := []*Lease{}
|
||||
staticLeases := []*Lease{}
|
||||
v6StaticLeases := []*Lease{}
|
||||
v6DynLeases := []*Lease{}
|
||||
|
||||
data, err := os.ReadFile(s.conf.DBFilePath)
|
||||
data, err := os.ReadFile(s.conf.dbFilePath)
|
||||
if err != nil {
|
||||
if !errors.Is(err, os.ErrNotExist) {
|
||||
return fmt.Errorf("reading db: %w", err)
|
||||
@@ -50,52 +41,30 @@ func (s *server) dbLoad() (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
obj := []leaseJSON{}
|
||||
err = json.Unmarshal(data, &obj)
|
||||
dl := &dataLeases{}
|
||||
err = json.Unmarshal(data, dl)
|
||||
if err != nil {
|
||||
return fmt.Errorf("decoding db: %w", err)
|
||||
}
|
||||
|
||||
numLeases := len(obj)
|
||||
for i := range obj {
|
||||
obj[i].IP = normalizeIP(obj[i].IP)
|
||||
leases := dl.Leases
|
||||
|
||||
ip, ok := netip.AddrFromSlice(obj[i].IP)
|
||||
if !ok {
|
||||
log.Info("dhcp: invalid IP: %s", obj[i].IP)
|
||||
continue
|
||||
}
|
||||
leases4 := []*Lease{}
|
||||
leases6 := []*Lease{}
|
||||
|
||||
lease := Lease{
|
||||
HWAddr: obj[i].HWAddr,
|
||||
IP: ip,
|
||||
Hostname: obj[i].Hostname,
|
||||
Expiry: time.Unix(obj[i].Expiry, 0),
|
||||
IsStatic: obj[i].Expiry == leaseExpireStatic,
|
||||
}
|
||||
|
||||
if len(obj[i].IP) == 16 {
|
||||
if lease.IsStatic {
|
||||
v6StaticLeases = append(v6StaticLeases, &lease)
|
||||
} else {
|
||||
v6DynLeases = append(v6DynLeases, &lease)
|
||||
}
|
||||
for _, l := range leases {
|
||||
if l.IP.Is4() {
|
||||
leases4 = append(leases4, l)
|
||||
} else {
|
||||
if lease.IsStatic {
|
||||
staticLeases = append(staticLeases, &lease)
|
||||
} else {
|
||||
dynLeases = append(dynLeases, &lease)
|
||||
}
|
||||
leases6 = append(leases6, l)
|
||||
}
|
||||
}
|
||||
|
||||
leases4 := normalizeLeases(staticLeases, dynLeases)
|
||||
err = s.srv4.ResetLeases(leases4)
|
||||
if err != nil {
|
||||
return fmt.Errorf("resetting dhcpv4 leases: %w", err)
|
||||
}
|
||||
|
||||
leases6 := normalizeLeases(v6StaticLeases, v6DynLeases)
|
||||
if s.srv6 != nil {
|
||||
err = s.srv6.ResetLeases(leases6)
|
||||
if err != nil {
|
||||
@@ -104,90 +73,54 @@ func (s *server) dbLoad() (err error) {
|
||||
}
|
||||
|
||||
log.Info("dhcp: loaded leases v4:%d v6:%d total-read:%d from DB",
|
||||
len(leases4), len(leases6), numLeases)
|
||||
len(leases4), len(leases6), len(leases))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Skip duplicate leases
|
||||
// Static leases have a priority over dynamic leases
|
||||
func normalizeLeases(staticLeases, dynLeases []*Lease) []*Lease {
|
||||
leases := []*Lease{}
|
||||
index := map[string]int{}
|
||||
|
||||
for i, lease := range staticLeases {
|
||||
_, ok := index[lease.HWAddr.String()]
|
||||
if ok {
|
||||
continue // skip the lease with the same HW address
|
||||
}
|
||||
index[lease.HWAddr.String()] = i
|
||||
leases = append(leases, lease)
|
||||
}
|
||||
|
||||
for i, lease := range dynLeases {
|
||||
_, ok := index[lease.HWAddr.String()]
|
||||
if ok {
|
||||
continue // skip the lease with the same HW address
|
||||
}
|
||||
index[lease.HWAddr.String()] = i
|
||||
leases = append(leases, lease)
|
||||
}
|
||||
|
||||
return leases
|
||||
}
|
||||
|
||||
// Store lease table in DB
|
||||
// dbStore stores DHCP leases.
|
||||
func (s *server) dbStore() (err error) {
|
||||
// Use an empty slice here as opposed to nil so that it doesn't write
|
||||
// "null" into the database file if leases are empty.
|
||||
leases := []leaseJSON{}
|
||||
leases := []*Lease{}
|
||||
|
||||
leases4 := s.srv4.getLeasesRef()
|
||||
for _, l := range leases4 {
|
||||
if l.Expiry.Unix() == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
lease := leaseJSON{
|
||||
HWAddr: l.HWAddr,
|
||||
IP: l.IP.AsSlice(),
|
||||
Hostname: l.Hostname,
|
||||
Expiry: l.Expiry.Unix(),
|
||||
}
|
||||
|
||||
leases = append(leases, lease)
|
||||
}
|
||||
leases = append(leases, leases4...)
|
||||
|
||||
if s.srv6 != nil {
|
||||
leases6 := s.srv6.getLeasesRef()
|
||||
for _, l := range leases6 {
|
||||
if l.Expiry.Unix() == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
lease := leaseJSON{
|
||||
HWAddr: l.HWAddr,
|
||||
IP: l.IP.AsSlice(),
|
||||
Hostname: l.Hostname,
|
||||
Expiry: l.Expiry.Unix(),
|
||||
}
|
||||
|
||||
leases = append(leases, lease)
|
||||
}
|
||||
leases = append(leases, leases6...)
|
||||
}
|
||||
|
||||
var data []byte
|
||||
data, err = json.Marshal(leases)
|
||||
return writeDB(s.conf.dbFilePath, leases)
|
||||
}
|
||||
|
||||
// writeDB writes leases to file at path.
|
||||
func writeDB(path string, leases []*Lease) (err error) {
|
||||
defer func() { err = errors.Annotate(err, "writing db: %w") }()
|
||||
|
||||
slices.SortFunc(leases, func(a, b *Lease) bool {
|
||||
return a.Hostname < b.Hostname
|
||||
})
|
||||
|
||||
dl := &dataLeases{
|
||||
Version: dataVersion,
|
||||
Leases: leases,
|
||||
}
|
||||
|
||||
buf, err := json.Marshal(dl)
|
||||
if err != nil {
|
||||
return fmt.Errorf("encoding db: %w", err)
|
||||
// Don't wrap the error since it's informative enough as is.
|
||||
return err
|
||||
}
|
||||
|
||||
err = maybe.WriteFile(s.conf.DBFilePath, data, 0o644)
|
||||
err = maybe.WriteFile(path, buf, 0o644)
|
||||
if err != nil {
|
||||
return fmt.Errorf("writing db: %w", err)
|
||||
// Don't wrap the error since it's informative enough as is.
|
||||
return err
|
||||
}
|
||||
|
||||
log.Info("dhcp: stored %d leases in db", len(leases))
|
||||
log.Info("dhcp: stored %d leases in %q", len(leases), path)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -15,13 +15,6 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
// leaseExpireStatic is used to define the Expiry field for static
|
||||
// leases.
|
||||
//
|
||||
// TODO(e.burkov): Remove it when static leases determining mechanism
|
||||
// will be improved.
|
||||
leaseExpireStatic = 1
|
||||
|
||||
// DefaultDHCPLeaseTTL is the default time-to-live for leases.
|
||||
DefaultDHCPLeaseTTL = uint32(timeutil.Day / time.Second)
|
||||
|
||||
@@ -35,10 +28,11 @@ const (
|
||||
defaultBackoff time.Duration = 500 * time.Millisecond
|
||||
)
|
||||
|
||||
// Lease contains the necessary information about a DHCP lease
|
||||
// Lease contains the necessary information about a DHCP lease. It's used as is
|
||||
// in the database, so don't change it until it's absolutely necessary, see
|
||||
// [dataVersion].
|
||||
type Lease struct {
|
||||
// Expiry is the expiration time of the lease. The unix timestamp value
|
||||
// of 1 means that this is a static lease.
|
||||
// Expiry is the expiration time of the lease.
|
||||
Expiry time.Time `json:"expires"`
|
||||
|
||||
// Hostname of the client.
|
||||
@@ -48,8 +42,6 @@ type Lease struct {
|
||||
HWAddr net.HardwareAddr `json:"mac"`
|
||||
|
||||
// IP is the IP address leased to the client.
|
||||
//
|
||||
// TODO(a.garipov): Migrate leases.db.
|
||||
IP netip.Addr `json:"ip"`
|
||||
|
||||
// IsStatic defines if the lease is static.
|
||||
@@ -238,7 +230,7 @@ func Create(conf *ServerConfig) (s *server, err error) {
|
||||
|
||||
LocalDomainName: conf.LocalDomainName,
|
||||
|
||||
DBFilePath: filepath.Join(conf.WorkDir, dbFilename),
|
||||
dbFilePath: filepath.Join(conf.DataDir, dataFilename),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -246,39 +238,26 @@ func Create(conf *ServerConfig) (s *server, err error) {
|
||||
// [aghhttp.RegisterFunc].
|
||||
s.registerHandlers()
|
||||
|
||||
v4conf := conf.Conf4
|
||||
v4conf.InterfaceName = s.conf.InterfaceName
|
||||
v4conf.notify = s.onNotify
|
||||
v4conf.Enabled = s.conf.Enabled && v4conf.RangeStart.IsValid()
|
||||
|
||||
s.srv4, err = v4Create(&v4conf)
|
||||
v4Enabled, v6Enabled, err := s.setServers(conf)
|
||||
if err != nil {
|
||||
if v4conf.Enabled {
|
||||
return nil, fmt.Errorf("creating dhcpv4 srv: %w", err)
|
||||
}
|
||||
|
||||
log.Debug("dhcpd: warning: creating dhcpv4 srv: %s", err)
|
||||
}
|
||||
|
||||
v6conf := conf.Conf6
|
||||
v6conf.Enabled = s.conf.Enabled
|
||||
if len(v6conf.RangeStart) == 0 {
|
||||
v6conf.Enabled = false
|
||||
}
|
||||
v6conf.InterfaceName = s.conf.InterfaceName
|
||||
v6conf.notify = s.onNotify
|
||||
s.srv6, err = v6Create(v6conf)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("creating dhcpv6 srv: %w", err)
|
||||
// Don't wrap the error, because it's informative enough as is.
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.conf.Conf4 = conf.Conf4
|
||||
s.conf.Conf6 = conf.Conf6
|
||||
|
||||
if s.conf.Enabled && !v4conf.Enabled && !v6conf.Enabled {
|
||||
if s.conf.Enabled && !v4Enabled && !v6Enabled {
|
||||
return nil, fmt.Errorf("neither dhcpv4 nor dhcpv6 srv is configured")
|
||||
}
|
||||
|
||||
// Migrate leases db if needed.
|
||||
err = migrateDB(conf)
|
||||
if err != nil {
|
||||
// Don't wrap the error since it's informative enough as is.
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Don't delay database loading until the DHCP server is started,
|
||||
// because we need static leases functionality available beforehand.
|
||||
err = s.dbLoad()
|
||||
@@ -289,6 +268,39 @@ func Create(conf *ServerConfig) (s *server, err error) {
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// setServers updates DHCPv4 and DHCPv6 servers created from the provided
|
||||
// configuration conf.
|
||||
func (s *server) setServers(conf *ServerConfig) (v4Enabled, v6Enabled bool, err error) {
|
||||
v4conf := conf.Conf4
|
||||
v4conf.InterfaceName = s.conf.InterfaceName
|
||||
v4conf.notify = s.onNotify
|
||||
v4conf.Enabled = s.conf.Enabled && v4conf.RangeStart.IsValid()
|
||||
|
||||
s.srv4, err = v4Create(&v4conf)
|
||||
if err != nil {
|
||||
if v4conf.Enabled {
|
||||
return true, false, fmt.Errorf("creating dhcpv4 srv: %w", err)
|
||||
}
|
||||
|
||||
log.Debug("dhcpd: warning: creating dhcpv4 srv: %s", err)
|
||||
}
|
||||
|
||||
v6conf := conf.Conf6
|
||||
v6conf.InterfaceName = s.conf.InterfaceName
|
||||
v6conf.notify = s.onNotify
|
||||
v6conf.Enabled = s.conf.Enabled
|
||||
if len(v6conf.RangeStart) == 0 {
|
||||
v6conf.Enabled = false
|
||||
}
|
||||
|
||||
s.srv6, err = v6Create(v6conf)
|
||||
if err != nil {
|
||||
return v4conf.Enabled, v6conf.Enabled, fmt.Errorf("creating dhcpv6 srv: %w", err)
|
||||
}
|
||||
|
||||
return v4conf.Enabled, v6conf.Enabled, nil
|
||||
}
|
||||
|
||||
// Enabled returns true when the server is enabled.
|
||||
func (s *server) Enabled() (ok bool) {
|
||||
return s.conf.Enabled
|
||||
|
||||
@@ -5,7 +5,7 @@ package dhcpd
|
||||
import (
|
||||
"net"
|
||||
"net/netip"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -27,7 +27,7 @@ func TestDB(t *testing.T) {
|
||||
var err error
|
||||
s := server{
|
||||
conf: &ServerConfig{
|
||||
DBFilePath: dbFilename,
|
||||
dbFilePath: filepath.Join(t.TempDir(), dataFilename),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -67,8 +67,6 @@ func TestDB(t *testing.T) {
|
||||
err = s.dbStore()
|
||||
require.NoError(t, err)
|
||||
|
||||
testutil.CleanupAndRequireSuccess(t, func() (err error) { return os.Remove(dbFilename) })
|
||||
|
||||
err = s.srv4.ResetLeases(nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -78,36 +76,13 @@ func TestDB(t *testing.T) {
|
||||
ll := s.srv4.GetLeases(LeasesAll)
|
||||
require.Len(t, ll, len(leases))
|
||||
|
||||
assert.Equal(t, leases[1].HWAddr, ll[0].HWAddr)
|
||||
assert.Equal(t, leases[1].IP, ll[0].IP)
|
||||
assert.True(t, ll[0].IsStatic)
|
||||
assert.Equal(t, leases[0].HWAddr, ll[0].HWAddr)
|
||||
assert.Equal(t, leases[0].IP, ll[0].IP)
|
||||
assert.Equal(t, leases[0].Expiry.Unix(), ll[0].Expiry.Unix())
|
||||
|
||||
assert.Equal(t, leases[0].HWAddr, ll[1].HWAddr)
|
||||
assert.Equal(t, leases[0].IP, ll[1].IP)
|
||||
assert.Equal(t, leases[0].Expiry.Unix(), ll[1].Expiry.Unix())
|
||||
}
|
||||
|
||||
func TestNormalizeLeases(t *testing.T) {
|
||||
dynLeases := []*Lease{{
|
||||
HWAddr: net.HardwareAddr{1, 2, 3, 4},
|
||||
}, {
|
||||
HWAddr: net.HardwareAddr{1, 2, 3, 5},
|
||||
}}
|
||||
|
||||
staticLeases := []*Lease{{
|
||||
HWAddr: net.HardwareAddr{1, 2, 3, 4},
|
||||
IP: netip.MustParseAddr("0.2.3.4"),
|
||||
}, {
|
||||
HWAddr: net.HardwareAddr{2, 2, 3, 4},
|
||||
}}
|
||||
|
||||
leases := normalizeLeases(staticLeases, dynLeases)
|
||||
require.Len(t, leases, 3)
|
||||
|
||||
assert.Equal(t, leases[0].HWAddr, dynLeases[0].HWAddr)
|
||||
assert.Equal(t, leases[0].IP, staticLeases[0].IP)
|
||||
assert.Equal(t, leases[1].HWAddr, staticLeases[1].HWAddr)
|
||||
assert.Equal(t, leases[2].HWAddr, dynLeases[1].HWAddr)
|
||||
assert.Equal(t, leases[1].HWAddr, ll[1].HWAddr)
|
||||
assert.Equal(t, leases[1].IP, ll[1].IP)
|
||||
assert.True(t, ll[1].IsStatic)
|
||||
}
|
||||
|
||||
func TestV4Server_badRange(t *testing.T) {
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
"github.com/AdguardTeam/golibs/netutil"
|
||||
)
|
||||
|
||||
type v4ServerConfJSON struct {
|
||||
@@ -263,6 +264,28 @@ func (s *server) handleDHCPSetConfigV6(
|
||||
return srv6, enabled, err
|
||||
}
|
||||
|
||||
// createServers returns DHCPv4 and DHCPv6 servers created from the provided
|
||||
// configuration conf.
|
||||
func (s *server) createServers(conf *dhcpServerConfigJSON) (srv4, srv6 DHCPServer, err error) {
|
||||
srv4, v4Enabled, err := s.handleDHCPSetConfigV4(conf)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("bad dhcpv4 configuration: %s", err)
|
||||
}
|
||||
|
||||
srv6, v6Enabled, err := s.handleDHCPSetConfigV6(conf)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("bad dhcpv6 configuration: %s", err)
|
||||
}
|
||||
|
||||
if conf.Enabled == aghalg.NBTrue && !v4Enabled && !v6Enabled {
|
||||
return nil, nil, fmt.Errorf("dhcpv4 or dhcpv6 configuration must be complete")
|
||||
}
|
||||
|
||||
return srv4, srv6, nil
|
||||
}
|
||||
|
||||
// handleDHCPSetConfig is the handler for the POST /control/dhcp/set_config
|
||||
// HTTP API.
|
||||
func (s *server) handleDHCPSetConfig(w http.ResponseWriter, r *http.Request) {
|
||||
conf := &dhcpServerConfigJSON{}
|
||||
conf.Enabled = aghalg.BoolToNullBool(s.conf.Enabled)
|
||||
@@ -275,22 +298,9 @@ func (s *server) handleDHCPSetConfig(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
srv4, v4Enabled, err := s.handleDHCPSetConfigV4(conf)
|
||||
srv4, srv6, err := s.createServers(conf)
|
||||
if err != nil {
|
||||
aghhttp.Error(r, w, http.StatusBadRequest, "bad dhcpv4 configuration: %s", err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
srv6, v6Enabled, err := s.handleDHCPSetConfigV6(conf)
|
||||
if err != nil {
|
||||
aghhttp.Error(r, w, http.StatusBadRequest, "bad dhcpv6 configuration: %s", err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if conf.Enabled == aghalg.NBTrue && !v4Enabled && !v6Enabled {
|
||||
aghhttp.Error(r, w, http.StatusBadRequest, "dhcpv4 or dhcpv6 configuration must be complete")
|
||||
aghhttp.Error(r, w, http.StatusBadRequest, "%s", err)
|
||||
|
||||
return
|
||||
}
|
||||
@@ -350,8 +360,10 @@ type netInterfaceJSON struct {
|
||||
Addrs6 []netip.Addr `json:"ipv6_addresses"`
|
||||
}
|
||||
|
||||
// handleDHCPInterfaces is the handler for the GET /control/dhcp/interfaces
|
||||
// HTTP API.
|
||||
func (s *server) handleDHCPInterfaces(w http.ResponseWriter, r *http.Request) {
|
||||
response := map[string]netInterfaceJSON{}
|
||||
resp := map[string]*netInterfaceJSON{}
|
||||
|
||||
ifaces, err := net.Interfaces()
|
||||
if err != nil {
|
||||
@@ -362,82 +374,86 @@ func (s *server) handleDHCPInterfaces(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
for _, iface := range ifaces {
|
||||
if iface.Flags&net.FlagLoopback != 0 {
|
||||
// it's a loopback, skip it
|
||||
continue
|
||||
}
|
||||
if iface.Flags&net.FlagBroadcast == 0 {
|
||||
// this interface doesn't support broadcast, skip it
|
||||
// It's a loopback, skip it.
|
||||
continue
|
||||
}
|
||||
|
||||
var addrs []net.Addr
|
||||
addrs, err = iface.Addrs()
|
||||
if err != nil {
|
||||
aghhttp.Error(
|
||||
r,
|
||||
w,
|
||||
http.StatusInternalServerError,
|
||||
"Failed to get addresses for interface %s: %s",
|
||||
iface.Name,
|
||||
err,
|
||||
)
|
||||
if iface.Flags&net.FlagBroadcast == 0 {
|
||||
// This interface doesn't support broadcast, skip it.
|
||||
continue
|
||||
}
|
||||
|
||||
jsonIface, iErr := newNetInterfaceJSON(iface)
|
||||
if iErr != nil {
|
||||
aghhttp.Error(r, w, http.StatusInternalServerError, "%s", iErr)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
jsonIface := netInterfaceJSON{
|
||||
Name: iface.Name,
|
||||
HardwareAddr: iface.HardwareAddr.String(),
|
||||
}
|
||||
|
||||
if iface.Flags != 0 {
|
||||
jsonIface.Flags = iface.Flags.String()
|
||||
}
|
||||
// we don't want link-local addresses in json, so skip them
|
||||
for _, addr := range addrs {
|
||||
ipnet, ok := addr.(*net.IPNet)
|
||||
if !ok {
|
||||
// not an IPNet, should not happen
|
||||
aghhttp.Error(
|
||||
r,
|
||||
w,
|
||||
http.StatusInternalServerError,
|
||||
"got iface.Addrs() element %[1]s that is not net.IPNet, it is %[1]T",
|
||||
addr)
|
||||
|
||||
return
|
||||
}
|
||||
// ignore link-local
|
||||
//
|
||||
// TODO(e.burkov): Try to listen DHCP on LLA as well.
|
||||
if ipnet.IP.IsLinkLocalUnicast() {
|
||||
continue
|
||||
}
|
||||
|
||||
if ip4 := ipnet.IP.To4(); ip4 != nil {
|
||||
addr := netip.AddrFrom4(*(*[4]byte)(ip4))
|
||||
jsonIface.Addrs4 = append(jsonIface.Addrs4, addr)
|
||||
} else {
|
||||
addr := netip.AddrFrom16(*(*[16]byte)(ipnet.IP))
|
||||
jsonIface.Addrs6 = append(jsonIface.Addrs6, addr)
|
||||
}
|
||||
}
|
||||
if len(jsonIface.Addrs4)+len(jsonIface.Addrs6) != 0 {
|
||||
jsonIface.GatewayIP = aghnet.GatewayIP(iface.Name)
|
||||
response[iface.Name] = jsonIface
|
||||
if jsonIface != nil {
|
||||
resp[iface.Name] = jsonIface
|
||||
}
|
||||
}
|
||||
|
||||
err = json.NewEncoder(w).Encode(response)
|
||||
_ = aghhttp.WriteJSONResponse(w, r, resp)
|
||||
}
|
||||
|
||||
// newNetInterfaceJSON creates a JSON object from a [net.Interface] iface.
|
||||
func newNetInterfaceJSON(iface net.Interface) (out *netInterfaceJSON, err error) {
|
||||
addrs, err := iface.Addrs()
|
||||
if err != nil {
|
||||
aghhttp.Error(
|
||||
r,
|
||||
w,
|
||||
http.StatusInternalServerError,
|
||||
"Failed to marshal json with available interfaces: %s",
|
||||
return nil, fmt.Errorf(
|
||||
"failed to get addresses for interface %s: %s",
|
||||
iface.Name,
|
||||
err,
|
||||
)
|
||||
}
|
||||
|
||||
out = &netInterfaceJSON{
|
||||
Name: iface.Name,
|
||||
HardwareAddr: iface.HardwareAddr.String(),
|
||||
}
|
||||
|
||||
if iface.Flags != 0 {
|
||||
out.Flags = iface.Flags.String()
|
||||
}
|
||||
|
||||
// We don't want link-local addresses in JSON, so skip them.
|
||||
for _, addr := range addrs {
|
||||
ipNet, ok := addr.(*net.IPNet)
|
||||
if !ok {
|
||||
// Not an IPNet, should not happen.
|
||||
return nil, fmt.Errorf("got iface.Addrs() element %[1]s that is not"+
|
||||
" net.IPNet, it is %[1]T", addr)
|
||||
}
|
||||
|
||||
// Ignore link-local.
|
||||
//
|
||||
// TODO(e.burkov): Try to listen DHCP on LLA as well.
|
||||
if ipNet.IP.IsLinkLocalUnicast() {
|
||||
continue
|
||||
}
|
||||
|
||||
vAddr, iErr := netutil.IPToAddrNoMapped(ipNet.IP)
|
||||
if iErr != nil {
|
||||
// Not an IPNet, should not happen.
|
||||
return nil, fmt.Errorf("failed to convert IP address %[1]s: %w", addr, iErr)
|
||||
}
|
||||
|
||||
if vAddr.Is4() {
|
||||
out.Addrs4 = append(out.Addrs4, vAddr)
|
||||
} else {
|
||||
out.Addrs6 = append(out.Addrs6, vAddr)
|
||||
}
|
||||
}
|
||||
|
||||
if len(out.Addrs4)+len(out.Addrs6) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
out.GatewayIP = aghnet.GatewayIP(iface.Name)
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// dhcpSearchOtherResult contains information about other DHCP server for
|
||||
@@ -639,7 +655,7 @@ func (s *server) handleReset(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
err = os.Remove(s.conf.DBFilePath)
|
||||
err = os.Remove(s.conf.dbFilePath)
|
||||
if err != nil && !errors.Is(err, os.ErrNotExist) {
|
||||
log.Error("dhcp: removing db: %s", err)
|
||||
}
|
||||
@@ -651,8 +667,8 @@ func (s *server) handleReset(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
LocalDomainName: s.conf.LocalDomainName,
|
||||
|
||||
WorkDir: s.conf.WorkDir,
|
||||
DBFilePath: s.conf.DBFilePath,
|
||||
DataDir: s.conf.DataDir,
|
||||
dbFilePath: s.conf.dbFilePath,
|
||||
}
|
||||
|
||||
v4conf := &V4ServerConf{
|
||||
|
||||
@@ -31,8 +31,7 @@ func TestServer_handleDHCPStatus(t *testing.T) {
|
||||
s, err := Create(&ServerConfig{
|
||||
Enabled: true,
|
||||
Conf4: *defaultV4ServerConf(),
|
||||
WorkDir: t.TempDir(),
|
||||
DBFilePath: dbFilename,
|
||||
DataDir: t.TempDir(),
|
||||
ConfigModified: func() {},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
109
internal/dhcpd/migrate.go
Normal file
109
internal/dhcpd/migrate.go
Normal file
@@ -0,0 +1,109 @@
|
||||
package dhcpd
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net"
|
||||
"net/netip"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
)
|
||||
|
||||
const (
|
||||
// leaseExpireStatic is used to define the Expiry field for static
|
||||
// leases.
|
||||
//
|
||||
// Deprecated: Remove it when migration of DHCP leases will be not needed.
|
||||
leaseExpireStatic = 1
|
||||
|
||||
// dbFilename contains saved leases.
|
||||
//
|
||||
// Deprecated: Use dataFilename.
|
||||
dbFilename = "leases.db"
|
||||
)
|
||||
|
||||
// leaseJSON is the structure of stored lease.
|
||||
//
|
||||
// Deprecated: Use [Lease].
|
||||
type leaseJSON struct {
|
||||
HWAddr []byte `json:"mac"`
|
||||
IP []byte `json:"ip"`
|
||||
Hostname string `json:"host"`
|
||||
Expiry int64 `json:"exp"`
|
||||
}
|
||||
|
||||
func normalizeIP(ip net.IP) net.IP {
|
||||
ip4 := ip.To4()
|
||||
if ip4 != nil {
|
||||
return ip4
|
||||
}
|
||||
|
||||
return ip
|
||||
}
|
||||
|
||||
// migrateDB migrates stored leases if necessary.
|
||||
func migrateDB(conf *ServerConfig) (err error) {
|
||||
defer func() { err = errors.Annotate(err, "migrating db: %w") }()
|
||||
|
||||
oldLeasesPath := filepath.Join(conf.WorkDir, dbFilename)
|
||||
dataDirPath := filepath.Join(conf.DataDir, dataFilename)
|
||||
|
||||
// #nosec G304 -- Trust this path, since it's taken from the old file name
|
||||
// relative to the working directory and should generally be considered
|
||||
// safe.
|
||||
file, err := os.Open(oldLeasesPath)
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
// Nothing to migrate.
|
||||
return nil
|
||||
} else if err != nil {
|
||||
// Don't wrap the error since it's informative enough as is.
|
||||
return err
|
||||
}
|
||||
|
||||
ljs := []leaseJSON{}
|
||||
err = json.NewDecoder(file).Decode(&ljs)
|
||||
if err != nil {
|
||||
// Don't wrap the error since it's informative enough as is.
|
||||
return err
|
||||
}
|
||||
|
||||
err = file.Close()
|
||||
if err != nil {
|
||||
// Don't wrap the error since it's informative enough as is.
|
||||
return err
|
||||
}
|
||||
|
||||
leases := []*Lease{}
|
||||
|
||||
for _, lj := range ljs {
|
||||
lj.IP = normalizeIP(lj.IP)
|
||||
|
||||
ip, ok := netip.AddrFromSlice(lj.IP)
|
||||
if !ok {
|
||||
log.Info("dhcp: invalid IP: %s", lj.IP)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
lease := &Lease{
|
||||
Expiry: time.Unix(lj.Expiry, 0),
|
||||
Hostname: lj.Hostname,
|
||||
HWAddr: lj.HWAddr,
|
||||
IP: ip,
|
||||
IsStatic: lj.Expiry == leaseExpireStatic,
|
||||
}
|
||||
|
||||
leases = append(leases, lease)
|
||||
}
|
||||
|
||||
err = writeDB(dataDirPath, leases)
|
||||
if err != nil {
|
||||
// Don't wrap the error since it's informative enough as is.
|
||||
return err
|
||||
}
|
||||
|
||||
return os.Remove(oldLeasesPath)
|
||||
}
|
||||
73
internal/dhcpd/migrate_internal_test.go
Normal file
73
internal/dhcpd/migrate_internal_test.go
Normal file
@@ -0,0 +1,73 @@
|
||||
package dhcpd
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net"
|
||||
"net/netip"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
const testData = `[
|
||||
{"mac":"ESIzRFVm","ip":"AQIDBA==","host":"test1","exp":1},
|
||||
{"mac":"ZlVEMyIR","ip":"BAMCAQ==","host":"test2","exp":1231231231}
|
||||
]`
|
||||
|
||||
func TestMigrateDB(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
|
||||
oldLeasesPath := filepath.Join(dir, dbFilename)
|
||||
dataDirPath := filepath.Join(dir, dataFilename)
|
||||
|
||||
err := os.WriteFile(oldLeasesPath, []byte(testData), 0o644)
|
||||
require.NoError(t, err)
|
||||
|
||||
wantLeases := []*Lease{{
|
||||
Expiry: time.Time{},
|
||||
Hostname: "test1",
|
||||
HWAddr: net.HardwareAddr{0x11, 0x22, 0x33, 0x44, 0x55, 0x66},
|
||||
IP: netip.MustParseAddr("1.2.3.4"),
|
||||
IsStatic: true,
|
||||
}, {
|
||||
Expiry: time.Unix(1231231231, 0),
|
||||
Hostname: "test2",
|
||||
HWAddr: net.HardwareAddr{0x66, 0x55, 0x44, 0x33, 0x22, 0x11},
|
||||
IP: netip.MustParseAddr("4.3.2.1"),
|
||||
IsStatic: false,
|
||||
}}
|
||||
|
||||
conf := &ServerConfig{
|
||||
WorkDir: dir,
|
||||
DataDir: dir,
|
||||
}
|
||||
|
||||
err = migrateDB(conf)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = os.Stat(oldLeasesPath)
|
||||
require.ErrorIs(t, err, os.ErrNotExist)
|
||||
|
||||
var data []byte
|
||||
data, err = os.ReadFile(dataDirPath)
|
||||
require.NoError(t, err)
|
||||
|
||||
dl := &dataLeases{}
|
||||
err = json.Unmarshal(data, dl)
|
||||
require.NoError(t, err)
|
||||
|
||||
leases := dl.Leases
|
||||
|
||||
for i, wl := range wantLeases {
|
||||
assert.Equal(t, wl.Hostname, leases[i].Hostname)
|
||||
assert.Equal(t, wl.HWAddr, leases[i].HWAddr)
|
||||
assert.Equal(t, wl.IP, leases[i].IP)
|
||||
assert.Equal(t, wl.IsStatic, leases[i].IsStatic)
|
||||
|
||||
require.True(t, wl.Expiry.Equal(leases[i].Expiry))
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
//go:build windows
|
||||
|
||||
package dhcpd
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghos"
|
||||
"golang.org/x/net/ipv4"
|
||||
)
|
||||
|
||||
// Create a socket for receiving broadcast packets
|
||||
func newBroadcastPacketConn(_ net.IP, _ int, _ string) (*ipv4.PacketConn, error) {
|
||||
return nil, aghos.Unsupported("newBroadcastPacketConn")
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
"github.com/AdguardTeam/golibs/netutil"
|
||||
"golang.org/x/net/icmp"
|
||||
@@ -195,16 +196,15 @@ func createICMPv6RAPacket(params icmpv6RA) (data []byte, err error) {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// Init - initialize RA module
|
||||
// Init initializes RA module.
|
||||
func (ra *raCtx) Init() (err error) {
|
||||
ra.stop.Store(0)
|
||||
ra.conn = nil
|
||||
if !(ra.raAllowSLAAC || ra.raSLAACOnly) {
|
||||
if !ra.raAllowSLAAC && !ra.raSLAACOnly {
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Debug("dhcpv6 ra: source IP address: %s DNS IP address: %s",
|
||||
ra.ipAddr, ra.dnsIPAddr)
|
||||
log.Debug("dhcpv6 ra: source IP address: %s DNS IP address: %s", ra.ipAddr, ra.dnsIPAddr)
|
||||
|
||||
params := icmpv6RA{
|
||||
managedAddressConfiguration: !ra.raSLAACOnly,
|
||||
@@ -223,18 +223,15 @@ func (ra *raCtx) Init() (err error) {
|
||||
return fmt.Errorf("creating packet: %w", err)
|
||||
}
|
||||
|
||||
success := false
|
||||
ipAndScope := ra.ipAddr.String() + "%" + ra.ifaceName
|
||||
ra.conn, err = icmp.ListenPacket("ip6:ipv6-icmp", ipAndScope)
|
||||
if err != nil {
|
||||
return fmt.Errorf("dhcpv6 ra: icmp.ListenPacket: %w", err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if !success {
|
||||
derr := ra.Close()
|
||||
if derr != nil {
|
||||
log.Error("closing context: %s", derr)
|
||||
}
|
||||
if err != nil {
|
||||
err = errors.WithDeferred(err, ra.Close())
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -269,7 +266,6 @@ func (ra *raCtx) Init() (err error) {
|
||||
log.Debug("dhcpv6 ra: loop exit")
|
||||
}()
|
||||
|
||||
success = true
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -256,6 +256,8 @@ func (s *v4Server) rmLeaseByIndex(i int) {
|
||||
|
||||
// Remove a dynamic lease with the same properties
|
||||
// Return error if a static lease is found
|
||||
//
|
||||
// TODO(s.chzhen): Refactor the code.
|
||||
func (s *v4Server) rmDynamicLease(lease *Lease) (err error) {
|
||||
for i, l := range s.leases {
|
||||
isStatic := l.IsStatic
|
||||
@@ -340,8 +342,8 @@ func (s *v4Server) rmLease(lease *Lease) (err error) {
|
||||
// server to be configured and it's not.
|
||||
const ErrUnconfigured errors.Error = "server is unconfigured"
|
||||
|
||||
// AddStaticLease implements the DHCPServer interface for *v4Server. It is safe
|
||||
// for concurrent use.
|
||||
// AddStaticLease implements the DHCPServer interface for *v4Server. It is
|
||||
// safe for concurrent use.
|
||||
func (s *v4Server) AddStaticLease(l *Lease) (err error) {
|
||||
defer func() { err = errors.Annotate(err, "dhcpv4: adding static lease: %w") }()
|
||||
|
||||
@@ -352,22 +354,23 @@ func (s *v4Server) AddStaticLease(l *Lease) (err error) {
|
||||
l.IP = l.IP.Unmap()
|
||||
|
||||
if !l.IP.Is4() {
|
||||
return fmt.Errorf("invalid ip %q, only ipv4 is supported", l.IP)
|
||||
return fmt.Errorf("invalid IP %q: only IPv4 is supported", l.IP)
|
||||
} else if gwIP := s.conf.GatewayIP; gwIP == l.IP {
|
||||
return fmt.Errorf("can't assign the gateway IP %s to the lease", gwIP)
|
||||
return fmt.Errorf("can't assign the gateway IP %q to the lease", gwIP)
|
||||
}
|
||||
|
||||
l.Expiry = time.Unix(leaseExpireStatic, 0)
|
||||
l.IsStatic = true
|
||||
|
||||
err = netutil.ValidateMAC(l.HWAddr)
|
||||
if err != nil {
|
||||
// Don't wrap the error, because it's informative enough as is.
|
||||
return err
|
||||
}
|
||||
|
||||
if hostname := l.Hostname; hostname != "" {
|
||||
hostname, err = normalizeHostname(hostname)
|
||||
if err != nil {
|
||||
// Don't wrap the error, because it's informative enough as is.
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -385,32 +388,9 @@ func (s *v4Server) AddStaticLease(l *Lease) (err error) {
|
||||
l.Hostname = hostname
|
||||
}
|
||||
|
||||
// Perform the following actions in an anonymous function to make sure
|
||||
// that the lock gets unlocked before the notification step.
|
||||
func() {
|
||||
s.leasesLock.Lock()
|
||||
defer s.leasesLock.Unlock()
|
||||
|
||||
err = s.rmDynamicLease(l)
|
||||
if err != nil {
|
||||
err = fmt.Errorf(
|
||||
"removing dynamic leases for %s (%s): %w",
|
||||
l.IP,
|
||||
l.HWAddr,
|
||||
err,
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
err = s.addLease(l)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("adding static lease for %s (%s): %w", l.IP, l.HWAddr, err)
|
||||
|
||||
return
|
||||
}
|
||||
}()
|
||||
err = s.updateStaticLease(l)
|
||||
if err != nil {
|
||||
// Don't wrap the error, because it's informative enough as is.
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -420,6 +400,25 @@ func (s *v4Server) AddStaticLease(l *Lease) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// updateStaticLease safe removes dynamic lease with the same properties and
|
||||
// then adds a static lease l.
|
||||
func (s *v4Server) updateStaticLease(l *Lease) (err error) {
|
||||
s.leasesLock.Lock()
|
||||
defer s.leasesLock.Unlock()
|
||||
|
||||
err = s.rmDynamicLease(l)
|
||||
if err != nil {
|
||||
return fmt.Errorf("removing dynamic leases for %s (%s): %w", l.IP, l.HWAddr, err)
|
||||
}
|
||||
|
||||
err = s.addLease(l)
|
||||
if err != nil {
|
||||
return fmt.Errorf("adding static lease for %s (%s): %w", l.IP, l.HWAddr, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveStaticLease removes a static lease. It is safe for concurrent use.
|
||||
func (s *v4Server) RemoveStaticLease(l *Lease) (err error) {
|
||||
defer func() { err = errors.Annotate(err, "dhcpv4: %w") }()
|
||||
@@ -893,24 +892,9 @@ func (s *v4Server) handleDecline(req, resp *dhcpv4.DHCPv4) (err error) {
|
||||
reqIP = req.ClientIPAddr
|
||||
}
|
||||
|
||||
netIP, ok := netip.AddrFromSlice(reqIP)
|
||||
if !ok {
|
||||
log.Info("dhcpv4: invalid IP: %s", reqIP)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var oldLease *Lease
|
||||
for _, l := range s.leases {
|
||||
if bytes.Equal(l.HWAddr, mac) && l.IP == netIP {
|
||||
oldLease = l
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
oldLease := s.findLeaseForIP(reqIP, mac)
|
||||
if oldLease == nil {
|
||||
log.Info("dhcpv4: lease with ip %s for %s not found", reqIP, mac)
|
||||
log.Info("dhcpv4: lease with IP %s for %s not found", reqIP, mac)
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -924,7 +908,7 @@ func (s *v4Server) handleDecline(req, resp *dhcpv4.DHCPv4) (err error) {
|
||||
if err != nil {
|
||||
return fmt.Errorf("allocating new lease for %s: %w", mac, err)
|
||||
} else if newLease == nil {
|
||||
log.Info("dhcpv4: allocating new lease for %s: no more ip addresses", mac)
|
||||
log.Info("dhcpv4: allocating new lease for %s: no more IP addresses", mac)
|
||||
|
||||
resp.YourIPAddr = make([]byte, 4)
|
||||
resp.UpdateOption(dhcpv4.OptMessageType(dhcpv4.MessageTypeAck))
|
||||
@@ -940,15 +924,32 @@ func (s *v4Server) handleDecline(req, resp *dhcpv4.DHCPv4) (err error) {
|
||||
return fmt.Errorf("adding new lease for %s: %w", mac, err)
|
||||
}
|
||||
|
||||
log.Info("dhcpv4: changed ip from %s to %s for %s", reqIP, newLease.IP, mac)
|
||||
|
||||
resp.YourIPAddr = net.IP(newLease.IP.AsSlice())
|
||||
log.Info("dhcpv4: changed IP from %s to %s for %s", reqIP, newLease.IP, mac)
|
||||
|
||||
resp.YourIPAddr = newLease.IP.AsSlice()
|
||||
resp.UpdateOption(dhcpv4.OptMessageType(dhcpv4.MessageTypeAck))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// findLeaseForIP returns a lease for provided ip and mac.
|
||||
func (s *v4Server) findLeaseForIP(ip net.IP, mac net.HardwareAddr) (l *Lease) {
|
||||
netIP, ok := netip.AddrFromSlice(ip)
|
||||
if !ok {
|
||||
log.Info("dhcpv4: invalid IP: %s", ip)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, il := range s.leases {
|
||||
if bytes.Equal(il.HWAddr, mac) && il.IP == netIP {
|
||||
return il
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// handleRelease is the handler for the DHCP Release request.
|
||||
func (s *v4Server) handleRelease(req, resp *dhcpv4.DHCPv4) (err error) {
|
||||
mac := req.ClientHWAddr
|
||||
@@ -994,11 +995,80 @@ func (s *v4Server) handleRelease(req, resp *dhcpv4.DHCPv4) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Find a lease associated with MAC and prepare response
|
||||
// Return 1: OK
|
||||
// Return 0: error; reply with Nak
|
||||
// Return -1: error; don't reply
|
||||
func (s *v4Server) handle(req, resp *dhcpv4.DHCPv4) int {
|
||||
// messageHandler describes a DHCPv4 message handler function.
|
||||
type messageHandler func(s *v4Server, req, resp *dhcpv4.DHCPv4) (rCode int, l *Lease, err error)
|
||||
|
||||
// messageHandlers is a map of handlers for various messages with message types
|
||||
// keys.
|
||||
var messageHandlers = map[dhcpv4.MessageType]messageHandler{
|
||||
dhcpv4.MessageTypeDiscover: func(
|
||||
s *v4Server,
|
||||
req *dhcpv4.DHCPv4,
|
||||
resp *dhcpv4.DHCPv4,
|
||||
) (rCode int, l *Lease, err error) {
|
||||
l, err = s.handleDiscover(req, resp)
|
||||
if err != nil {
|
||||
return 0, nil, fmt.Errorf("handling discover: %s", err)
|
||||
}
|
||||
|
||||
if l == nil {
|
||||
return 0, nil, nil
|
||||
}
|
||||
|
||||
return 1, l, nil
|
||||
},
|
||||
dhcpv4.MessageTypeRequest: func(
|
||||
s *v4Server,
|
||||
req *dhcpv4.DHCPv4,
|
||||
resp *dhcpv4.DHCPv4,
|
||||
) (rCode int, l *Lease, err error) {
|
||||
var toReply bool
|
||||
l, toReply = s.handleRequest(req, resp)
|
||||
if l == nil {
|
||||
if toReply {
|
||||
return 0, nil, nil
|
||||
}
|
||||
|
||||
// Drop the packet.
|
||||
return -1, nil, nil
|
||||
}
|
||||
|
||||
return 1, l, nil
|
||||
},
|
||||
dhcpv4.MessageTypeDecline: func(
|
||||
s *v4Server,
|
||||
req *dhcpv4.DHCPv4,
|
||||
resp *dhcpv4.DHCPv4,
|
||||
) (rCode int, l *Lease, err error) {
|
||||
err = s.handleDecline(req, resp)
|
||||
if err != nil {
|
||||
return 0, nil, fmt.Errorf("handling decline: %s", err)
|
||||
}
|
||||
|
||||
return 1, nil, nil
|
||||
},
|
||||
dhcpv4.MessageTypeRelease: func(
|
||||
s *v4Server,
|
||||
req *dhcpv4.DHCPv4,
|
||||
resp *dhcpv4.DHCPv4,
|
||||
) (rCode int, l *Lease, err error) {
|
||||
err = s.handleRelease(req, resp)
|
||||
if err != nil {
|
||||
return 0, nil, fmt.Errorf("handling release: %s", err)
|
||||
}
|
||||
|
||||
return 1, nil, nil
|
||||
},
|
||||
}
|
||||
|
||||
// handle processes request, it finds a lease associated with MAC address and
|
||||
// prepares response.
|
||||
//
|
||||
// Possible return values are:
|
||||
// - "1": OK,
|
||||
// - "0": error, reply with Nak,
|
||||
// - "-1": error, don't reply.
|
||||
func (s *v4Server) handle(req, resp *dhcpv4.DHCPv4) (rCode int) {
|
||||
var err error
|
||||
|
||||
// Include server's identifier option since any reply should contain it.
|
||||
@@ -1006,47 +1076,26 @@ func (s *v4Server) handle(req, resp *dhcpv4.DHCPv4) int {
|
||||
// See https://datatracker.ietf.org/doc/html/rfc2131#page-29.
|
||||
resp.UpdateOption(dhcpv4.OptServerIdentifier(s.conf.dnsIPAddrs[0].AsSlice()))
|
||||
|
||||
// TODO(a.garipov): Refactor this into handlers.
|
||||
var l *Lease
|
||||
switch mt := req.MessageType(); mt {
|
||||
case dhcpv4.MessageTypeDiscover:
|
||||
l, err = s.handleDiscover(req, resp)
|
||||
if err != nil {
|
||||
log.Error("dhcpv4: handling discover: %s", err)
|
||||
handler := messageHandlers[req.MessageType()]
|
||||
if handler == nil {
|
||||
s.updateOptions(req, resp)
|
||||
|
||||
return 0
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
if l == nil {
|
||||
return 0
|
||||
}
|
||||
case dhcpv4.MessageTypeRequest:
|
||||
var toReply bool
|
||||
l, toReply = s.handleRequest(req, resp)
|
||||
if l == nil {
|
||||
if toReply {
|
||||
return 0
|
||||
}
|
||||
return -1 // drop packet
|
||||
}
|
||||
case dhcpv4.MessageTypeDecline:
|
||||
err = s.handleDecline(req, resp)
|
||||
if err != nil {
|
||||
log.Error("dhcpv4: handling decline: %s", err)
|
||||
rCode, l, err := handler(s, req, resp)
|
||||
if err != nil {
|
||||
log.Error("dhcpv4: %s", err)
|
||||
|
||||
return 0
|
||||
}
|
||||
case dhcpv4.MessageTypeRelease:
|
||||
err = s.handleRelease(req, resp)
|
||||
if err != nil {
|
||||
log.Error("dhcpv4: handling release: %s", err)
|
||||
return 0
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
if rCode != 1 {
|
||||
return rCode
|
||||
}
|
||||
|
||||
if l != nil {
|
||||
resp.YourIPAddr = net.IP(l.IP.AsSlice())
|
||||
resp.YourIPAddr = l.IP.AsSlice()
|
||||
}
|
||||
|
||||
s.updateOptions(req, resp)
|
||||
@@ -1161,23 +1210,8 @@ func (s *v4Server) Start() (err error) {
|
||||
// No available IP addresses which may appear later.
|
||||
return nil
|
||||
}
|
||||
// Update the value of Domain Name Server option separately from others if
|
||||
// not assigned yet since its value is available only at server's start.
|
||||
//
|
||||
// TODO(e.burkov): Initialize as implicit option with the rest of default
|
||||
// options when it will be possible to do before the call to Start.
|
||||
if !s.explicitOpts.Has(dhcpv4.OptionDomainNameServer) {
|
||||
s.implicitOpts.Update(dhcpv4.OptDNS(dnsIPAddrs...))
|
||||
}
|
||||
|
||||
for _, ip := range dnsIPAddrs {
|
||||
ip = ip.To4()
|
||||
if ip == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
s.conf.dnsIPAddrs = append(s.conf.dnsIPAddrs, netip.AddrFrom4(*(*[4]byte)(ip)))
|
||||
}
|
||||
s.configureDNSIPAddrs(dnsIPAddrs)
|
||||
|
||||
var c net.PacketConn
|
||||
if c, err = s.newDHCPConn(iface); err != nil {
|
||||
@@ -1198,10 +1232,10 @@ func (s *v4Server) Start() (err error) {
|
||||
log.Info("dhcpv4: listening")
|
||||
|
||||
go func() {
|
||||
if serr := s.srv.Serve(); errors.Is(serr, net.ErrClosed) {
|
||||
if sErr := s.srv.Serve(); errors.Is(sErr, net.ErrClosed) {
|
||||
log.Info("dhcpv4: server is closed")
|
||||
} else if serr != nil {
|
||||
log.Error("dhcpv4: srv.Serve: %s", serr)
|
||||
} else if sErr != nil {
|
||||
log.Error("dhcpv4: srv.Serve: %s", sErr)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -1212,6 +1246,28 @@ func (s *v4Server) Start() (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// configureDNSIPAddrs updates v4Server configuration with provided slice of
|
||||
// dns IP addresses.
|
||||
func (s *v4Server) configureDNSIPAddrs(dnsIPAddrs []net.IP) {
|
||||
// Update the value of Domain Name Server option separately from others if
|
||||
// not assigned yet since its value is available only at server's start.
|
||||
//
|
||||
// TODO(e.burkov): Initialize as implicit option with the rest of default
|
||||
// options when it will be possible to do before the call to Start.
|
||||
if !s.explicitOpts.Has(dhcpv4.OptionDomainNameServer) {
|
||||
s.implicitOpts.Update(dhcpv4.OptDNS(dnsIPAddrs...))
|
||||
}
|
||||
|
||||
for _, ip := range dnsIPAddrs {
|
||||
vAddr, err := netutil.IPToAddr(ip, netutil.AddrFamilyIPv4)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
s.conf.dnsIPAddrs = append(s.conf.dnsIPAddrs, vAddr)
|
||||
}
|
||||
}
|
||||
|
||||
// Stop - stop server
|
||||
func (s *v4Server) Stop() (err error) {
|
||||
if s.srv == nil {
|
||||
|
||||
@@ -68,7 +68,6 @@ func TestV4Server_leasing(t *testing.T) {
|
||||
|
||||
t.Run("add_static", func(t *testing.T) {
|
||||
err := s.AddStaticLease(&Lease{
|
||||
Expiry: time.Unix(leaseExpireStatic, 0),
|
||||
Hostname: staticName,
|
||||
HWAddr: staticMAC,
|
||||
IP: staticIP,
|
||||
@@ -78,7 +77,6 @@ func TestV4Server_leasing(t *testing.T) {
|
||||
|
||||
t.Run("same_name", func(t *testing.T) {
|
||||
err = s.AddStaticLease(&Lease{
|
||||
Expiry: time.Unix(leaseExpireStatic, 0),
|
||||
Hostname: staticName,
|
||||
HWAddr: anotherMAC,
|
||||
IP: anotherIP,
|
||||
@@ -93,7 +91,6 @@ func TestV4Server_leasing(t *testing.T) {
|
||||
" (" + staticMAC.String() + "): static lease already exists"
|
||||
|
||||
err = s.AddStaticLease(&Lease{
|
||||
Expiry: time.Unix(leaseExpireStatic, 0),
|
||||
Hostname: anotherName,
|
||||
HWAddr: staticMAC,
|
||||
IP: anotherIP,
|
||||
@@ -108,7 +105,6 @@ func TestV4Server_leasing(t *testing.T) {
|
||||
" (" + anotherMAC.String() + "): static lease already exists"
|
||||
|
||||
err = s.AddStaticLease(&Lease{
|
||||
Expiry: time.Unix(leaseExpireStatic, 0),
|
||||
Hostname: anotherName,
|
||||
HWAddr: anotherMAC,
|
||||
IP: staticIP,
|
||||
@@ -231,7 +227,7 @@ func TestV4Server_AddRemove_static(t *testing.T) {
|
||||
},
|
||||
name: "with_gateway_ip",
|
||||
wantErrMsg: "dhcpv4: adding static lease: " +
|
||||
"can't assign the gateway IP 192.168.10.1 to the lease",
|
||||
`can't assign the gateway IP "192.168.10.1" to the lease`,
|
||||
}, {
|
||||
lease: &Lease{
|
||||
Hostname: "ip6.local",
|
||||
@@ -240,7 +236,7 @@ func TestV4Server_AddRemove_static(t *testing.T) {
|
||||
},
|
||||
name: "ipv6",
|
||||
wantErrMsg: `dhcpv4: adding static lease: ` +
|
||||
`invalid ip "ffff::1", only ipv4 is supported`,
|
||||
`invalid IP "ffff::1": only IPv4 is supported`,
|
||||
}, {
|
||||
lease: &Lease{
|
||||
Hostname: "bad-mac.local",
|
||||
@@ -784,7 +780,6 @@ func TestV4Server_FindMACbyIP(t *testing.T) {
|
||||
|
||||
s := &v4Server{
|
||||
leases: []*Lease{{
|
||||
Expiry: time.Unix(leaseExpireStatic, 0),
|
||||
Hostname: staticName,
|
||||
HWAddr: staticMAC,
|
||||
IP: staticIP,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user