Merge branch 'master' into 4299-querylog-stats-api
This commit is contained in:
commit
e0cbfc1c40
40
CHANGELOG.md
40
CHANGELOG.md
|
@ -31,6 +31,9 @@ NOTE: Add new changes BELOW THIS COMMENT.
|
||||||
- Two new HTTP APIs, `PUT /control/querylog/config/update` and `GET
|
- Two new HTTP APIs, `PUT /control/querylog/config/update` and `GET
|
||||||
control/querylog/config`, which can be used to set and receive the statistics
|
control/querylog/config`, which can be used to set and receive the statistics
|
||||||
configuration. See openapi/openapi.yaml for the full description.
|
configuration. See openapi/openapi.yaml for the full description.
|
||||||
|
- The ability to set custom IP for EDNS Client Subnet by using the new
|
||||||
|
`dns.edns_client_subnet.use_custom` and `dns.edns_client_subnet.custom_ip`
|
||||||
|
fields ([#1472]). The UI changes are coming in the upcoming releases.
|
||||||
- The ability to use `dnstype` rules in the disallowed domains list ([#5468]).
|
- The ability to use `dnstype` rules in the disallowed domains list ([#5468]).
|
||||||
This allows dropping requests based on their question types.
|
This allows dropping requests based on their question types.
|
||||||
|
|
||||||
|
@ -38,9 +41,9 @@ NOTE: Add new changes BELOW THIS COMMENT.
|
||||||
|
|
||||||
#### Configuration Changes
|
#### Configuration Changes
|
||||||
|
|
||||||
In this release, the schema version has changed from 16 to 17.
|
In this release, the schema version has changed from 16 to 18.
|
||||||
|
|
||||||
- Property `statistics.interval`, which in schema versions 16 and earlier used
|
- Property `statistics.interval`, which in schema versions 17 and earlier used
|
||||||
to be an integer number of days, is now a string with a human-readable
|
to be an integer number of days, is now a string with a human-readable
|
||||||
duration:
|
duration:
|
||||||
|
|
||||||
|
@ -57,7 +60,31 @@ In this release, the schema version has changed from 16 to 17.
|
||||||
```
|
```
|
||||||
|
|
||||||
To rollback this change, convert the property back into days and change the
|
To rollback this change, convert the property back into days and change the
|
||||||
`schema_version` back to `16`.
|
`schema_version` back to `17`.
|
||||||
|
- Property `edns_client_subnet`, which in schema versions 16 and earlier used
|
||||||
|
to be a part of the `dns` object, is now part of the `dns.edns_client_subnet`
|
||||||
|
object:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# BEFORE:
|
||||||
|
'dns':
|
||||||
|
# …
|
||||||
|
'edns_client_subnet': false
|
||||||
|
|
||||||
|
# AFTER:
|
||||||
|
'dns':
|
||||||
|
# …
|
||||||
|
'edns_client_subnet':
|
||||||
|
'enabled': false
|
||||||
|
'use_custom': false
|
||||||
|
'custom_ip': ''
|
||||||
|
```
|
||||||
|
|
||||||
|
To rollback this change, move the value of `dns.edns_client_subnet.enabled`
|
||||||
|
into the `dns.edns_client_subnet`, remove the fields
|
||||||
|
`dns.edns_client_subnet.enabled`, `dns.edns_client_subnet.use_custom`,
|
||||||
|
`dns.edns_client_subnet.custom_ip`, and change the `schema_version` back to
|
||||||
|
`16`.
|
||||||
|
|
||||||
### Deprecated
|
### Deprecated
|
||||||
|
|
||||||
|
@ -78,17 +105,23 @@ In this release, the schema version has changed from 16 to 17.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
- Various dark theme bugs ([#5439], [#5441], [#5442], [#5515]).
|
||||||
- Automatic update on MIPS64 and little-endian 32-bit MIPS architectures
|
- Automatic update on MIPS64 and little-endian 32-bit MIPS architectures
|
||||||
([#5270], [#5373]).
|
([#5270], [#5373]).
|
||||||
- Requirements to domain names in domain-specific upstream configurations have
|
- Requirements to domain names in domain-specific upstream configurations have
|
||||||
been relaxed to meet those from [RFC 3696][rfc3696] ([#4884]).
|
been relaxed to meet those from [RFC 3696][rfc3696] ([#4884]).
|
||||||
- Failing service installation via script on FreeBSD ([#5431]).
|
- Failing service installation via script on FreeBSD ([#5431]).
|
||||||
|
|
||||||
|
[#1472]: https://github.com/AdguardTeam/AdGuardHome/issues/1472
|
||||||
[#4884]: https://github.com/AdguardTeam/AdGuardHome/issues/4884
|
[#4884]: https://github.com/AdguardTeam/AdGuardHome/issues/4884
|
||||||
[#5270]: https://github.com/AdguardTeam/AdGuardHome/issues/5270
|
[#5270]: https://github.com/AdguardTeam/AdGuardHome/issues/5270
|
||||||
[#5373]: https://github.com/AdguardTeam/AdGuardHome/issues/5373
|
[#5373]: https://github.com/AdguardTeam/AdGuardHome/issues/5373
|
||||||
[#5431]: https://github.com/AdguardTeam/AdGuardHome/issues/5431
|
[#5431]: https://github.com/AdguardTeam/AdGuardHome/issues/5431
|
||||||
|
[#5439]: https://github.com/AdguardTeam/AdGuardHome/issues/5439
|
||||||
|
[#5441]: https://github.com/AdguardTeam/AdGuardHome/issues/5441
|
||||||
|
[#5442]: https://github.com/AdguardTeam/AdGuardHome/issues/5442
|
||||||
[#5468]: https://github.com/AdguardTeam/AdGuardHome/issues/5468
|
[#5468]: https://github.com/AdguardTeam/AdGuardHome/issues/5468
|
||||||
|
[#5515]: https://github.com/AdguardTeam/AdGuardHome/issues/5515
|
||||||
|
|
||||||
[rfc3696]: https://datatracker.ietf.org/doc/html/rfc3696
|
[rfc3696]: https://datatracker.ietf.org/doc/html/rfc3696
|
||||||
|
|
||||||
|
@ -172,6 +205,7 @@ In this release, the schema version has changed from 14 to 16.
|
||||||
'file_enabled': true
|
'file_enabled': true
|
||||||
'interval': '2160h'
|
'interval': '2160h'
|
||||||
'size_memory': 1000
|
'size_memory': 1000
|
||||||
|
'ignored': []
|
||||||
```
|
```
|
||||||
|
|
||||||
To rollback this change, rename and move properties back into the `dns`
|
To rollback this change, rename and move properties back into the `dns`
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"timeUpdated": "2023-02-21T12:46:33.324Z",
|
"timeUpdated": "2023-03-01T10:05:51.445Z",
|
||||||
"categories": {
|
"categories": {
|
||||||
"0": "audio_video_player",
|
"0": "audio_video_player",
|
||||||
"1": "comments",
|
"1": "comments",
|
||||||
|
@ -19225,11 +19225,39 @@
|
||||||
"url": "http://www.zypmedia.com/",
|
"url": "http://www.zypmedia.com/",
|
||||||
"companyId": "zypmedia"
|
"companyId": "zypmedia"
|
||||||
},
|
},
|
||||||
"slack": {
|
"adguard_dns": {
|
||||||
"name": "Slack",
|
"name": "AdGuard DNS",
|
||||||
"categoryId": 8,
|
"categoryId": 8,
|
||||||
"url": "https://www.slack.com/",
|
"url": "https://adguard-dns.io/",
|
||||||
"companyId": "salesforce",
|
"companyId": "adguard",
|
||||||
|
"source": "AdGuard"
|
||||||
|
},
|
||||||
|
"adguard_vpn": {
|
||||||
|
"name": "AdGuard VPN",
|
||||||
|
"categoryId": 8,
|
||||||
|
"url": "https://adguard-vpn.com/",
|
||||||
|
"companyId": "adguard",
|
||||||
|
"source": "AdGuard"
|
||||||
|
},
|
||||||
|
"appcenter": {
|
||||||
|
"name": "Microsoft App Center",
|
||||||
|
"categoryId": 5,
|
||||||
|
"url": "https://appcenter.ms/",
|
||||||
|
"companyId": null,
|
||||||
|
"source": "AdGuard"
|
||||||
|
},
|
||||||
|
"alibaba_cloud": {
|
||||||
|
"name": "Alibaba Cloud",
|
||||||
|
"categoryId": 10,
|
||||||
|
"url": "https://www.alibabacloud.com/",
|
||||||
|
"companyId": "alibaba",
|
||||||
|
"source": "AdGuard"
|
||||||
|
},
|
||||||
|
"alibaba_ucbrowser": {
|
||||||
|
"name": "UC Browser",
|
||||||
|
"categoryId": 8,
|
||||||
|
"url": "https://ucweb.com/",
|
||||||
|
"companyId": "alibaba",
|
||||||
"source": "AdGuard"
|
"source": "AdGuard"
|
||||||
},
|
},
|
||||||
"apple": {
|
"apple": {
|
||||||
|
@ -19246,11 +19274,39 @@
|
||||||
"companyId": "apple",
|
"companyId": "apple",
|
||||||
"source": "AdGuard"
|
"source": "AdGuard"
|
||||||
},
|
},
|
||||||
"facebook_audience": {
|
"azure": {
|
||||||
"name": "Facebook Audience Network",
|
"name": "Microsoft Azure",
|
||||||
|
"categoryId": 10,
|
||||||
|
"url": "https://azure.microsoft.com/",
|
||||||
|
"companyId": "microsoft",
|
||||||
|
"source": "AdGuard"
|
||||||
|
},
|
||||||
|
"azure_blob_storage": {
|
||||||
|
"name": "Azure Blob Storage",
|
||||||
|
"categoryId": 8,
|
||||||
|
"url": "https://azure.microsoft.com/en-us/products/storage/blobs",
|
||||||
|
"companyId": "microsoft",
|
||||||
|
"source": "AdGuard"
|
||||||
|
},
|
||||||
|
"bitwarden": {
|
||||||
|
"name": "Bitwarden",
|
||||||
|
"categoryId": 8,
|
||||||
|
"url": "https://bitwarden.com/",
|
||||||
|
"companyId": "bitwarden",
|
||||||
|
"source": "AdGuard"
|
||||||
|
},
|
||||||
|
"branch": {
|
||||||
|
"name": "Branch.io",
|
||||||
|
"categoryId": 101,
|
||||||
|
"url": "https://branch.io/",
|
||||||
|
"companyId": "branch_metrics_inc",
|
||||||
|
"source": "AdGuard"
|
||||||
|
},
|
||||||
|
"button": {
|
||||||
|
"name": "Button",
|
||||||
"categoryId": 4,
|
"categoryId": 4,
|
||||||
"url": "https://www.facebook.com/business/products/audience-network",
|
"url": "https://www.usebutton.com/",
|
||||||
"companyId": "meta",
|
"companyId": null,
|
||||||
"source": "AdGuard"
|
"source": "AdGuard"
|
||||||
},
|
},
|
||||||
"crashlytics": {
|
"crashlytics": {
|
||||||
|
@ -19260,18 +19316,25 @@
|
||||||
"companyId": null,
|
"companyId": null,
|
||||||
"source": "AdGuard"
|
"source": "AdGuard"
|
||||||
},
|
},
|
||||||
"showrss": {
|
"element": {
|
||||||
"name": "showRSS",
|
"name": "Element",
|
||||||
"categoryId": 8,
|
"categoryId": 7,
|
||||||
"url": "https://showrss.info/",
|
"url": "https://element.io/",
|
||||||
"companyId": "showrss",
|
"companyId": "element",
|
||||||
"source": "AdGuard"
|
"source": "AdGuard"
|
||||||
},
|
},
|
||||||
"hockeyapp": {
|
"facebook_audience": {
|
||||||
"name": "HockeyApp",
|
"name": "Facebook Audience Network",
|
||||||
|
"categoryId": 4,
|
||||||
|
"url": "https://www.facebook.com/business/products/audience-network",
|
||||||
|
"companyId": "meta",
|
||||||
|
"source": "AdGuard"
|
||||||
|
},
|
||||||
|
"firebase": {
|
||||||
|
"name": "Firebase",
|
||||||
"categoryId": 101,
|
"categoryId": 101,
|
||||||
"url": "https://hockeyapp.net/",
|
"url": "https://firebase.google.com/",
|
||||||
"companyId": null,
|
"companyId": "google",
|
||||||
"source": "AdGuard"
|
"source": "AdGuard"
|
||||||
},
|
},
|
||||||
"gmail": {
|
"gmail": {
|
||||||
|
@ -19288,32 +19351,32 @@
|
||||||
"companyId": "google",
|
"companyId": "google",
|
||||||
"source": "AdGuard"
|
"source": "AdGuard"
|
||||||
},
|
},
|
||||||
"firebase": {
|
"hockeyapp": {
|
||||||
"name": "Firebase",
|
"name": "HockeyApp",
|
||||||
"categoryId": 101,
|
"categoryId": 101,
|
||||||
"url": "https://firebase.google.com/",
|
"url": "https://hockeyapp.net/",
|
||||||
"companyId": "google",
|
"companyId": null,
|
||||||
"source": "AdGuard"
|
"source": "AdGuard"
|
||||||
},
|
},
|
||||||
"yandex_appmetrica": {
|
"kik": {
|
||||||
"name": "Yandex AppMetrica",
|
"name": "Kik",
|
||||||
"categoryId": 101,
|
"categoryId": 7,
|
||||||
"url": "https://appmetrica.yandex.com/",
|
"url": "https://kik.com/",
|
||||||
"companyId": "yandex",
|
"companyId": "kik",
|
||||||
"source": "AdGuard"
|
"source": "AdGuard"
|
||||||
},
|
},
|
||||||
"branch": {
|
"lets_encrypt": {
|
||||||
"name": "Branch.io",
|
"name": "Let's Encrypt",
|
||||||
"categoryId": 101,
|
"categoryId": 5,
|
||||||
"url": "https://branch.io/",
|
"url": "https://letsencrypt.org/",
|
||||||
"companyId": "branch_metrics_inc",
|
"companyId": "lets_encrypt",
|
||||||
"source": "AdGuard"
|
"source": "AdGuard"
|
||||||
},
|
},
|
||||||
"telstra": {
|
"matrix": {
|
||||||
"name": "Telstra",
|
"name": "Matrix",
|
||||||
"categoryId": 8,
|
"categoryId": 5,
|
||||||
"url": "https://www.telstra.com.au/",
|
"url": "https://matrix.org/",
|
||||||
"companyId": "telstra",
|
"companyId": "matrix",
|
||||||
"source": "AdGuard"
|
"source": "AdGuard"
|
||||||
},
|
},
|
||||||
"medialab": {
|
"medialab": {
|
||||||
|
@ -19323,39 +19386,39 @@
|
||||||
"companyId": "medialab",
|
"companyId": "medialab",
|
||||||
"source": "AdGuard"
|
"source": "AdGuard"
|
||||||
},
|
},
|
||||||
"qualcomm": {
|
"meganz": {
|
||||||
"name": "Qualcomm",
|
"name": "Mega Ltd.",
|
||||||
"categoryId": 8,
|
"categoryId": 8,
|
||||||
"url": "https://www.qualcomm.com/",
|
"url": "https://mega.io/",
|
||||||
"companyId": "qualcomm",
|
"companyId": "meganz",
|
||||||
"source": "AdGuard"
|
"source": "AdGuard"
|
||||||
},
|
},
|
||||||
"solaredge": {
|
"msedge": {
|
||||||
"name": "SolarEdge Technologies, Inc.",
|
"name": "Microsoft Edge",
|
||||||
"categoryId": 8,
|
"categoryId": 8,
|
||||||
"url": "https://www.solaredge.com/",
|
"url": "https://www.microsoft.com/en-us/edge",
|
||||||
"companyId": "solaredge",
|
"companyId": "microsoft",
|
||||||
"source": "AdGuard"
|
"source": "AdGuard"
|
||||||
},
|
},
|
||||||
"sectigo": {
|
"mozilla": {
|
||||||
"name": "Sectigo Limited",
|
"name": "Mozilla Foundation",
|
||||||
|
"categoryId": 8,
|
||||||
|
"url": "https://www.mozilla.org/",
|
||||||
|
"companyId": "mozilla",
|
||||||
|
"source": "AdGuard"
|
||||||
|
},
|
||||||
|
"notion": {
|
||||||
|
"name": "Notion",
|
||||||
|
"categoryId": 8,
|
||||||
|
"url": "https://www.notion.so/",
|
||||||
|
"companyId": "notion",
|
||||||
|
"source": "AdGuard"
|
||||||
|
},
|
||||||
|
"ntppool": {
|
||||||
|
"name": "Network Time Protocol",
|
||||||
"categoryId": 5,
|
"categoryId": 5,
|
||||||
"url": "https://www.solaredge.com/",
|
"url": "https://ntp.org/",
|
||||||
"companyId": "sectigo",
|
"companyId": "ntppool",
|
||||||
"source": "AdGuard"
|
|
||||||
},
|
|
||||||
"element": {
|
|
||||||
"name": "Element",
|
|
||||||
"categoryId": 7,
|
|
||||||
"url": "https://element.io/",
|
|
||||||
"companyId": "element",
|
|
||||||
"source": "AdGuard"
|
|
||||||
},
|
|
||||||
"oztam": {
|
|
||||||
"name": "OzTAM",
|
|
||||||
"categoryId": 8,
|
|
||||||
"url": "https://oztam.com.au/",
|
|
||||||
"companyId": "oztam",
|
|
||||||
"source": "AdGuard"
|
"source": "AdGuard"
|
||||||
},
|
},
|
||||||
"oppo": {
|
"oppo": {
|
||||||
|
@ -19372,46 +19435,11 @@
|
||||||
"companyId": "microsoft",
|
"companyId": "microsoft",
|
||||||
"source": "AdGuard"
|
"source": "AdGuard"
|
||||||
},
|
},
|
||||||
"appcenter": {
|
"oztam": {
|
||||||
"name": "Microsoft App Center",
|
"name": "OzTAM",
|
||||||
"categoryId": 5,
|
"categoryId": 8,
|
||||||
"url": "https://appcenter.ms/",
|
"url": "https://oztam.com.au/",
|
||||||
"companyId": null,
|
"companyId": "oztam",
|
||||||
"source": "AdGuard"
|
|
||||||
},
|
|
||||||
"unity_ads": {
|
|
||||||
"name": "Unity Ads",
|
|
||||||
"categoryId": 4,
|
|
||||||
"url": "https://unity.com/solutions/mobile-business/monetize-your-game",
|
|
||||||
"companyId": null,
|
|
||||||
"source": "AdGuard"
|
|
||||||
},
|
|
||||||
"azure": {
|
|
||||||
"name": "Microsoft Azure",
|
|
||||||
"categoryId": 10,
|
|
||||||
"url": "https://azure.microsoft.com/",
|
|
||||||
"companyId": "microsoft",
|
|
||||||
"source": "AdGuard"
|
|
||||||
},
|
|
||||||
"button": {
|
|
||||||
"name": "Button",
|
|
||||||
"categoryId": 4,
|
|
||||||
"url": "https://www.usebutton.com/",
|
|
||||||
"companyId": null,
|
|
||||||
"source": "AdGuard"
|
|
||||||
},
|
|
||||||
"lets_encrypt": {
|
|
||||||
"name": "Let's Encrypt",
|
|
||||||
"categoryId": 5,
|
|
||||||
"url": "https://letsencrypt.org/",
|
|
||||||
"companyId": "lets_encrypt",
|
|
||||||
"source": "AdGuard"
|
|
||||||
},
|
|
||||||
"kik": {
|
|
||||||
"name": "Kik",
|
|
||||||
"categoryId": 7,
|
|
||||||
"url": "https://kik.com/",
|
|
||||||
"companyId": "kik",
|
|
||||||
"source": "AdGuard"
|
"source": "AdGuard"
|
||||||
},
|
},
|
||||||
"plex": {
|
"plex": {
|
||||||
|
@ -19421,25 +19449,60 @@
|
||||||
"companyId": "plex",
|
"companyId": "plex",
|
||||||
"source": "AdGuard"
|
"source": "AdGuard"
|
||||||
},
|
},
|
||||||
"matrix": {
|
"qualcomm": {
|
||||||
"name": "Matrix",
|
"name": "Qualcomm",
|
||||||
"categoryId": 5,
|
|
||||||
"url": "https://matrix.org/",
|
|
||||||
"companyId": "matrix",
|
|
||||||
"source": "AdGuard"
|
|
||||||
},
|
|
||||||
"ntppool": {
|
|
||||||
"name": "Network Time Protocol",
|
|
||||||
"categoryId": 5,
|
|
||||||
"url": "https://ntp.org/",
|
|
||||||
"companyId": "ntppool",
|
|
||||||
"source": "AdGuard"
|
|
||||||
},
|
|
||||||
"whatsapp": {
|
|
||||||
"name": "WhatsApp",
|
|
||||||
"categoryId": 8,
|
"categoryId": 8,
|
||||||
"url": "https://www.whatsapp.com/",
|
"url": "https://www.qualcomm.com/",
|
||||||
"companyId": "meta",
|
"companyId": "qualcomm",
|
||||||
|
"source": "AdGuard"
|
||||||
|
},
|
||||||
|
"sectigo": {
|
||||||
|
"name": "Sectigo Limited",
|
||||||
|
"categoryId": 5,
|
||||||
|
"url": "https://www.solaredge.com/",
|
||||||
|
"companyId": "sectigo",
|
||||||
|
"source": "AdGuard"
|
||||||
|
},
|
||||||
|
"showrss": {
|
||||||
|
"name": "showRSS",
|
||||||
|
"categoryId": 8,
|
||||||
|
"url": "https://showrss.info/",
|
||||||
|
"companyId": "showrss",
|
||||||
|
"source": "AdGuard"
|
||||||
|
},
|
||||||
|
"similarweb": {
|
||||||
|
"name": "SimilarWeb",
|
||||||
|
"categoryId": 6,
|
||||||
|
"url": "https://www.similarweb.com/",
|
||||||
|
"companyId": "similarweb",
|
||||||
|
"source": "AdGuard"
|
||||||
|
},
|
||||||
|
"slack": {
|
||||||
|
"name": "Slack",
|
||||||
|
"categoryId": 8,
|
||||||
|
"url": "https://www.slack.com/",
|
||||||
|
"companyId": "salesforce",
|
||||||
|
"source": "AdGuard"
|
||||||
|
},
|
||||||
|
"solaredge": {
|
||||||
|
"name": "SolarEdge Technologies, Inc.",
|
||||||
|
"categoryId": 8,
|
||||||
|
"url": "https://www.solaredge.com/",
|
||||||
|
"companyId": "solaredge",
|
||||||
|
"source": "AdGuard"
|
||||||
|
},
|
||||||
|
"telstra": {
|
||||||
|
"name": "Telstra",
|
||||||
|
"categoryId": 8,
|
||||||
|
"url": "https://www.telstra.com.au/",
|
||||||
|
"companyId": "telstra",
|
||||||
|
"source": "AdGuard"
|
||||||
|
},
|
||||||
|
"unity_ads": {
|
||||||
|
"name": "Unity Ads",
|
||||||
|
"categoryId": 4,
|
||||||
|
"url": "https://unity.com/solutions/mobile-business/monetize-your-game",
|
||||||
|
"companyId": null,
|
||||||
"source": "AdGuard"
|
"source": "AdGuard"
|
||||||
},
|
},
|
||||||
"vscode": {
|
"vscode": {
|
||||||
|
@ -19449,12 +19512,47 @@
|
||||||
"companyId": "microsoft",
|
"companyId": "microsoft",
|
||||||
"source": "AdGuard"
|
"source": "AdGuard"
|
||||||
},
|
},
|
||||||
"msedge": {
|
"whatsapp": {
|
||||||
"name": "Microsoft Edge",
|
"name": "WhatsApp",
|
||||||
"categoryId": 8,
|
"categoryId": 8,
|
||||||
"url": "https://www.microsoft.com/en-us/edge",
|
"url": "https://www.whatsapp.com/",
|
||||||
|
"companyId": "meta",
|
||||||
|
"source": "AdGuard"
|
||||||
|
},
|
||||||
|
"windows_maps": {
|
||||||
|
"name": "Windows Maps",
|
||||||
|
"categoryId": 8,
|
||||||
|
"url": "https://www.microsoft.com/store/apps/9wzdncrdtbvb",
|
||||||
"companyId": "microsoft",
|
"companyId": "microsoft",
|
||||||
"source": "AdGuard"
|
"source": "AdGuard"
|
||||||
|
},
|
||||||
|
"windows_notifications": {
|
||||||
|
"name": "The Windows Push Notification Services",
|
||||||
|
"categoryId": 8,
|
||||||
|
"url": "https://learn.microsoft.com/en-us/windows/apps/design/shell/tiles-and-notifications/windows-push-notification-services--wns--overview",
|
||||||
|
"companyId": "microsoft",
|
||||||
|
"source": "AdGuard"
|
||||||
|
},
|
||||||
|
"windows_time": {
|
||||||
|
"name": "Windows Time Service",
|
||||||
|
"categoryId": 8,
|
||||||
|
"url": "https://learn.microsoft.com/en-us/windows-server/networking/windows-time-service/how-the-windows-time-service-works",
|
||||||
|
"companyId": "microsoft",
|
||||||
|
"source": "AdGuard"
|
||||||
|
},
|
||||||
|
"windowsupdate": {
|
||||||
|
"name": "Windows Update",
|
||||||
|
"categoryId": 9,
|
||||||
|
"url": "https://support.microsoft.com/en-us/windows/windows-update-faq-8a903416-6f45-0718-f5c7-375e92dddeb2",
|
||||||
|
"companyId": "microsoft",
|
||||||
|
"source": "AdGuard"
|
||||||
|
},
|
||||||
|
"yandex_appmetrica": {
|
||||||
|
"name": "Yandex AppMetrica",
|
||||||
|
"categoryId": 101,
|
||||||
|
"url": "https://appmetrica.yandex.com/",
|
||||||
|
"companyId": "yandex",
|
||||||
|
"source": "AdGuard"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"trackerDomains": {
|
"trackerDomains": {
|
||||||
|
@ -23785,10 +23883,111 @@
|
||||||
"zwaar.net": "zwaar",
|
"zwaar.net": "zwaar",
|
||||||
"zwaar.org": "zwaar",
|
"zwaar.org": "zwaar",
|
||||||
"extend.tv": "zypmedia",
|
"extend.tv": "zypmedia",
|
||||||
"whatsapp.net": "whatsapp",
|
"adtidy.org": "adguard",
|
||||||
"whatsapp.com": "whatsapp",
|
"agrd.io": "adguard",
|
||||||
"telstra.com.au": "telstra",
|
"adguard.app": "adguard",
|
||||||
"telstra.com": "telstra",
|
"adguard.io": "adguard",
|
||||||
|
"adguard.org": "adguard",
|
||||||
|
"adguard-dns.com": "adguard_dns",
|
||||||
|
"adguard-dns.io": "adguard_dns",
|
||||||
|
"adguardvpn.com": "adguard_vpn",
|
||||||
|
"adguard-vpn.com": "adguard_vpn",
|
||||||
|
"adguard-vpn.online": "adguard_vpn",
|
||||||
|
"akadns.net": "akamai_technologies",
|
||||||
|
"akamaiedge.net": "akamai_technologies",
|
||||||
|
"akaquill.net": "akamai_technologies",
|
||||||
|
"aliapp.org": "alibaba.com",
|
||||||
|
"alibabachengdun.com": "alibaba.com",
|
||||||
|
"alibabausercontent.com": "alibaba.com",
|
||||||
|
"aliexpress.com": "alibaba.com",
|
||||||
|
"alikunlun.com": "alibaba.com",
|
||||||
|
"aliyuncs.com": "alibaba.com",
|
||||||
|
"alibabacloud.com": "alibaba_cloud",
|
||||||
|
"alibabadns.com": "alibaba_cloud",
|
||||||
|
"aliyun.com": "alibaba_cloud",
|
||||||
|
"ucweb.com": "alibaba_ucbrowser",
|
||||||
|
"alipayobjects.com": "alipay.com",
|
||||||
|
"taobao.com": "taobao",
|
||||||
|
"appcenter.ms": "appcenter",
|
||||||
|
"iadsdk.apple.com": "apple_ads",
|
||||||
|
"me.com": "apple",
|
||||||
|
"apple.news": "apple",
|
||||||
|
"apple-dns.net": "apple",
|
||||||
|
"aaplimg.com": "apple",
|
||||||
|
"icloud.com": "apple",
|
||||||
|
"itunes.com": "apple",
|
||||||
|
"icloud-content.com": "apple",
|
||||||
|
"mzstatic.com": "apple",
|
||||||
|
"cdn-apple.com": "apple",
|
||||||
|
"apple-mapkit.com": "apple",
|
||||||
|
"icons.axm-usercontent-apple.com": "apple",
|
||||||
|
"apple-cloudkit.com": "apple",
|
||||||
|
"apzones.com": "apple",
|
||||||
|
"apple-livephotoskit.com": "apple",
|
||||||
|
"safebrowsing.apple": "apple",
|
||||||
|
"safebrowsing.g.applimg.com": "apple",
|
||||||
|
"blob.core.windows.net": "azure_blob_storage",
|
||||||
|
"azure.com": "azure",
|
||||||
|
"trafficmanager.net": "azure",
|
||||||
|
"bitwarden.com": "bitwarden",
|
||||||
|
"mobileapptracking.com": "branch",
|
||||||
|
"bttn.io": "button",
|
||||||
|
"cloudflare-dns.com": "cloudflare",
|
||||||
|
"crashlytics.com": "crashlytics",
|
||||||
|
"phicdn.net": "digicert_trust_seal",
|
||||||
|
"element.io": "element",
|
||||||
|
"riot.im": "element",
|
||||||
|
"app-measurement.com": "firebase",
|
||||||
|
"flipboard.com": "flipboard",
|
||||||
|
"flurry.com": "flurry",
|
||||||
|
"gmail.com": "gmail",
|
||||||
|
"gvt1.com": "google_servers",
|
||||||
|
"gvt2.com": "google_servers",
|
||||||
|
"gvt3.com": "google_servers",
|
||||||
|
"pki.goog": "google_trust_services",
|
||||||
|
"hockeyapp.net": "hockeyapp",
|
||||||
|
"kik.com": "kik",
|
||||||
|
"apikik.com": "kik",
|
||||||
|
"kik-live.com": "kik",
|
||||||
|
"letsencrypt.org": "lets_encrypt",
|
||||||
|
"slatic.net": "lazada",
|
||||||
|
"lencr.org": "lets_encrypt",
|
||||||
|
"edgecastcdn.net": "markmonitor",
|
||||||
|
"matrix.org": "matrix",
|
||||||
|
"medialab.la": "medialab",
|
||||||
|
"media-lab.ai": "medialab",
|
||||||
|
"mega.co.nz": "meganz",
|
||||||
|
"mega.io": "meganz",
|
||||||
|
"mega.nz": "meganz",
|
||||||
|
"e-msedge.net": "msedge",
|
||||||
|
"l-msedge.net": "msedge",
|
||||||
|
"firefox.com": "mozilla",
|
||||||
|
"mozaws.net": "mozilla",
|
||||||
|
"mozgcp.net": "mozilla",
|
||||||
|
"mozilla.com": "mozilla",
|
||||||
|
"mozilla.net": "mozilla",
|
||||||
|
"mozilla.org": "mozilla",
|
||||||
|
"nflximg.com": "netflix",
|
||||||
|
"notion.so": "notion",
|
||||||
|
"ntp.org": "ntppool",
|
||||||
|
"ntppool.org": "ntppool",
|
||||||
|
"oppomobile.com": "oppo",
|
||||||
|
"heytapmobi.com": "oppo",
|
||||||
|
"heytapmobile.com": "oppo",
|
||||||
|
"heytapdl.com": "oppo",
|
||||||
|
"allawnos.com": "oppo",
|
||||||
|
"allawntech.com": "oppo",
|
||||||
|
"hotmail.com": "outlook",
|
||||||
|
"outlook.com": "outlook",
|
||||||
|
"oztam.com.au": "oztam",
|
||||||
|
"plex.tv": "plex",
|
||||||
|
"plex.direct": "plex",
|
||||||
|
"xtracloud.net": "qualcomm",
|
||||||
|
"qualcomm.com": "qualcomm",
|
||||||
|
"sectigo.com": "sectigo",
|
||||||
|
"showrss.info": "showrss",
|
||||||
|
"similarweb.io": "similarweb",
|
||||||
|
"similarweb.com": "similarweb",
|
||||||
"slack.com": "slack",
|
"slack.com": "slack",
|
||||||
"slackb.com": "slack",
|
"slackb.com": "slack",
|
||||||
"slack-edge.com": "slack",
|
"slack-edge.com": "slack",
|
||||||
|
@ -23803,88 +24002,27 @@
|
||||||
"snap-dev.net": "snap",
|
"snap-dev.net": "snap",
|
||||||
"snapads.com": "snap",
|
"snapads.com": "snap",
|
||||||
"snapkit.com": "snap",
|
"snapkit.com": "snap",
|
||||||
"adguard.app": "adguard",
|
"solaredge.com": "solaredge",
|
||||||
"adguard.io": "adguard",
|
"telstra.com.au": "telstra",
|
||||||
"adguard.org": "adguard",
|
"telstra.com": "telstra",
|
||||||
"adguard-dns.com": "adguard",
|
"usertrust.com": "trustlogo",
|
||||||
"adguard-dns.io": "adguard",
|
"unityads.unity3d.com": "unity_ads",
|
||||||
"adguard-vpn.com": "adguard",
|
|
||||||
"adguardvpn.com": "adguard",
|
|
||||||
"adguard-vpn.online": "adguard",
|
|
||||||
"oppomobile.com": "oppo",
|
|
||||||
"heytapmobi.com": "oppo",
|
|
||||||
"heytapmobile.com": "oppo",
|
|
||||||
"heytapdl.com": "oppo",
|
|
||||||
"allawnos.com": "oppo",
|
|
||||||
"allawntech.com": "oppo",
|
|
||||||
"nflximg.com": "netflix",
|
|
||||||
"element.io": "element",
|
|
||||||
"riot.im": "element",
|
|
||||||
"gvt1.com": "google_servers",
|
|
||||||
"gvt2.com": "google_servers",
|
|
||||||
"gvt3.com": "google_servers",
|
|
||||||
"akadns.net": "akamai_technologies",
|
|
||||||
"akamaiedge.net": "akamai_technologies",
|
|
||||||
"akaquill.net": "akamai_technologies",
|
|
||||||
"me.com": "apple",
|
|
||||||
"apple.news": "apple",
|
|
||||||
"apple-dns.net": "apple",
|
|
||||||
"aaplimg.com": "apple",
|
|
||||||
"icloud.com": "apple",
|
|
||||||
"itunes.com": "apple",
|
|
||||||
"icloud-content.com": "apple",
|
|
||||||
"kik.com": "kik",
|
|
||||||
"apikik.com": "kik",
|
|
||||||
"kik-live.com": "kik",
|
|
||||||
"mzstatic.com": "apple",
|
|
||||||
"cdn-apple.com": "apple",
|
|
||||||
"apple-mapkit.com": "apple",
|
|
||||||
"icons.axm-usercontent-apple.com": "apple",
|
|
||||||
"apple-cloudkit.com": "apple",
|
|
||||||
"apzones.com": "apple",
|
|
||||||
"apple-livephotoskit.com": "apple",
|
|
||||||
"safebrowsing.apple": "apple",
|
|
||||||
"safebrowsing.g.applimg.com": "apple",
|
|
||||||
"matrix.org": "matrix",
|
|
||||||
"medialab.la": "medialab",
|
|
||||||
"media-lab.ai": "medialab",
|
|
||||||
"phicdn.net": "digicert_trust_seal",
|
|
||||||
"e-msedge.net": "msedge",
|
|
||||||
"l-msedge.net": "msedge",
|
|
||||||
"exp-tas.com": "vscode",
|
"exp-tas.com": "vscode",
|
||||||
"vscode-unpkg.net": "vscode",
|
"vscode-unpkg.net": "vscode",
|
||||||
"v0cdn.net": "vscode",
|
"v0cdn.net": "vscode",
|
||||||
"vscode-cdn.net": "vscode",
|
"vscode-cdn.net": "vscode",
|
||||||
"iadsdk.apple.com": "apple_ads",
|
"whatsapp.net": "whatsapp",
|
||||||
"showrss.info": "showrss",
|
"whatsapp.com": "whatsapp",
|
||||||
"sectigo.com": "sectigo",
|
"maps.windows.com": "windows_maps",
|
||||||
"solaredge.com": "solaredge",
|
"client.wns.windows.com": "windows_notifications",
|
||||||
"crashlytics.com": "crashlytics",
|
"time.windows.com": "windows_time",
|
||||||
"cloudflare-dns.com": "cloudflare",
|
"windowsupdate.com": "windowsupdate",
|
||||||
"flurry.com": "flurry",
|
"ya.ru": "yandex",
|
||||||
"hockeyapp.net": "hockeyapp",
|
"yandex.by": "yandex",
|
||||||
"app-measurement.com": "firebase",
|
"yandex.com": "yandex",
|
||||||
"appmetrica.yandex.com": "yandex_appmetrica",
|
"yandex.com.tr": "yandex",
|
||||||
"letsencrypt.org": "lets_encrypt",
|
"yandex.fr": "yandex",
|
||||||
"lencr.org": "lets_encrypt",
|
"yandex.kz": "yandex",
|
||||||
"oztam.com.au": "oztam",
|
"appmetrica.yandex.com": "yandex_appmetrica"
|
||||||
"mobileapptracking.com": "branch",
|
|
||||||
"ntp.org": "ntppool",
|
|
||||||
"ntppool.org": "ntppool",
|
|
||||||
"plex.tv": "plex",
|
|
||||||
"plex.direct": "plex",
|
|
||||||
"edgecastcdn.net": "markmonitor",
|
|
||||||
"appcenter.ms": "appcenter",
|
|
||||||
"unityads.unity3d.com": "unity_ads",
|
|
||||||
"usertrust.com": "trustlogo",
|
|
||||||
"azure.com": "azure",
|
|
||||||
"trafficmanager.net": "azure",
|
|
||||||
"hotmail.com": "outlook",
|
|
||||||
"outlook.com": "outlook",
|
|
||||||
"bttn.io": "button",
|
|
||||||
"pki.goog": "google_trust_services",
|
|
||||||
"xtracloud.net": "qualcomm",
|
|
||||||
"qualcomm.com": "qualcomm",
|
|
||||||
"gmail.com": "gmail"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -45,8 +45,10 @@ type DHCPServer interface {
|
||||||
AddStaticLease(l *Lease) (err error)
|
AddStaticLease(l *Lease) (err error)
|
||||||
// RemoveStaticLease - remove a static lease
|
// RemoveStaticLease - remove a static lease
|
||||||
RemoveStaticLease(l *Lease) (err error)
|
RemoveStaticLease(l *Lease) (err error)
|
||||||
// FindMACbyIP - find a MAC address by IP address in the currently active DHCP leases
|
|
||||||
FindMACbyIP(ip net.IP) net.HardwareAddr
|
// FindMACbyIP returns a MAC address by the IP address of its lease, if
|
||||||
|
// there is one.
|
||||||
|
FindMACbyIP(ip netip.Addr) (mac net.HardwareAddr)
|
||||||
|
|
||||||
// WriteDiskConfig4 - copy disk configuration
|
// WriteDiskConfig4 - copy disk configuration
|
||||||
WriteDiskConfig4(c *V4ServerConf)
|
WriteDiskConfig4(c *V4ServerConf)
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
"net/netip"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -42,6 +43,10 @@ type Lease struct {
|
||||||
|
|
||||||
Hostname string `json:"hostname"`
|
Hostname string `json:"hostname"`
|
||||||
HWAddr net.HardwareAddr `json:"mac"`
|
HWAddr net.HardwareAddr `json:"mac"`
|
||||||
|
|
||||||
|
// IP is the IP address leased to the client.
|
||||||
|
//
|
||||||
|
// TODO(a.garipov): Migrate leases.db and use netip.Addr.
|
||||||
IP net.IP `json:"ip"`
|
IP net.IP `json:"ip"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,7 +165,7 @@ type Interface interface {
|
||||||
|
|
||||||
Leases(flags GetLeasesFlags) (leases []*Lease)
|
Leases(flags GetLeasesFlags) (leases []*Lease)
|
||||||
SetOnLeaseChanged(onLeaseChanged OnLeaseChangedT)
|
SetOnLeaseChanged(onLeaseChanged OnLeaseChangedT)
|
||||||
FindMACbyIP(ip net.IP) (mac net.HardwareAddr)
|
FindMACbyIP(ip netip.Addr) (mac net.HardwareAddr)
|
||||||
|
|
||||||
WriteDiskConfig(c *ServerConfig)
|
WriteDiskConfig(c *ServerConfig)
|
||||||
}
|
}
|
||||||
|
@ -174,7 +179,7 @@ type MockInterface struct {
|
||||||
OnEnabled func() (ok bool)
|
OnEnabled func() (ok bool)
|
||||||
OnLeases func(flags GetLeasesFlags) (leases []*Lease)
|
OnLeases func(flags GetLeasesFlags) (leases []*Lease)
|
||||||
OnSetOnLeaseChanged func(f OnLeaseChangedT)
|
OnSetOnLeaseChanged func(f OnLeaseChangedT)
|
||||||
OnFindMACbyIP func(ip net.IP) (mac net.HardwareAddr)
|
OnFindMACbyIP func(ip netip.Addr) (mac net.HardwareAddr)
|
||||||
OnWriteDiskConfig func(c *ServerConfig)
|
OnWriteDiskConfig func(c *ServerConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,8 +200,10 @@ func (s *MockInterface) Leases(flags GetLeasesFlags) (ls []*Lease) { return s.On
|
||||||
// SetOnLeaseChanged implements the Interface for *MockInterface.
|
// SetOnLeaseChanged implements the Interface for *MockInterface.
|
||||||
func (s *MockInterface) SetOnLeaseChanged(f OnLeaseChangedT) { s.OnSetOnLeaseChanged(f) }
|
func (s *MockInterface) SetOnLeaseChanged(f OnLeaseChangedT) { s.OnSetOnLeaseChanged(f) }
|
||||||
|
|
||||||
// FindMACbyIP implements the Interface for *MockInterface.
|
// FindMACbyIP implements the [Interface] for *MockInterface.
|
||||||
func (s *MockInterface) FindMACbyIP(ip net.IP) (mac net.HardwareAddr) { return s.OnFindMACbyIP(ip) }
|
func (s *MockInterface) FindMACbyIP(ip netip.Addr) (mac net.HardwareAddr) {
|
||||||
|
return s.OnFindMACbyIP(ip)
|
||||||
|
}
|
||||||
|
|
||||||
// WriteDiskConfig implements the Interface for *MockInterface.
|
// WriteDiskConfig implements the Interface for *MockInterface.
|
||||||
func (s *MockInterface) WriteDiskConfig(c *ServerConfig) { s.OnWriteDiskConfig(c) }
|
func (s *MockInterface) WriteDiskConfig(c *ServerConfig) { s.OnWriteDiskConfig(c) }
|
||||||
|
@ -375,11 +382,13 @@ func (s *server) Leases(flags GetLeasesFlags) (leases []*Lease) {
|
||||||
return append(s.srv4.GetLeases(flags), s.srv6.GetLeases(flags)...)
|
return append(s.srv4.GetLeases(flags), s.srv6.GetLeases(flags)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindMACbyIP - find a MAC address by IP address in the currently active DHCP leases
|
// FindMACbyIP returns a MAC address by the IP address of its lease, if there is
|
||||||
func (s *server) FindMACbyIP(ip net.IP) net.HardwareAddr {
|
// one.
|
||||||
if ip.To4() != nil {
|
func (s *server) FindMACbyIP(ip netip.Addr) (mac net.HardwareAddr) {
|
||||||
|
if ip.Is4() {
|
||||||
return s.srv4.FindMACbyIP(ip)
|
return s.srv4.FindMACbyIP(ip)
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.srv6.FindMACbyIP(ip)
|
return s.srv6.FindMACbyIP(ip)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,10 @@ package dhcpd
|
||||||
|
|
||||||
// 'u-root/u-root' package, a dependency of 'insomniacslk/dhcp' package, doesn't build on Windows
|
// 'u-root/u-root' package, a dependency of 'insomniacslk/dhcp' package, doesn't build on Windows
|
||||||
|
|
||||||
import "net"
|
import (
|
||||||
|
"net"
|
||||||
|
"net/netip"
|
||||||
|
)
|
||||||
|
|
||||||
type winServer struct{}
|
type winServer struct{}
|
||||||
|
|
||||||
|
@ -16,7 +19,7 @@ func (winServer) GetLeases(_ GetLeasesFlags) (leases []*Lease) { return nil }
|
||||||
func (winServer) getLeasesRef() []*Lease { return nil }
|
func (winServer) getLeasesRef() []*Lease { return nil }
|
||||||
func (winServer) AddStaticLease(_ *Lease) (err error) { return nil }
|
func (winServer) AddStaticLease(_ *Lease) (err error) { return nil }
|
||||||
func (winServer) RemoveStaticLease(_ *Lease) (err error) { return nil }
|
func (winServer) RemoveStaticLease(_ *Lease) (err error) { return nil }
|
||||||
func (winServer) FindMACbyIP(_ net.IP) (mac net.HardwareAddr) { return nil }
|
func (winServer) FindMACbyIP(_ netip.Addr) (mac net.HardwareAddr) { return nil }
|
||||||
func (winServer) WriteDiskConfig4(_ *V4ServerConf) {}
|
func (winServer) WriteDiskConfig4(_ *V4ServerConf) {}
|
||||||
func (winServer) WriteDiskConfig6(_ *V6ServerConf) {}
|
func (winServer) WriteDiskConfig6(_ *V6ServerConf) {}
|
||||||
func (winServer) Start() (err error) { return nil }
|
func (winServer) Start() (err error) { return nil }
|
||||||
|
|
|
@ -200,20 +200,20 @@ func (s *v4Server) GetLeases(flags GetLeasesFlags) (leases []*Lease) {
|
||||||
return leases
|
return leases
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindMACbyIP - find a MAC address by IP address in the currently active DHCP leases
|
// FindMACbyIP implements the [Interface] for *v4Server.
|
||||||
func (s *v4Server) FindMACbyIP(ip net.IP) net.HardwareAddr {
|
func (s *v4Server) FindMACbyIP(ip netip.Addr) (mac net.HardwareAddr) {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
|
|
||||||
s.leasesLock.Lock()
|
s.leasesLock.Lock()
|
||||||
defer s.leasesLock.Unlock()
|
defer s.leasesLock.Unlock()
|
||||||
|
|
||||||
ip4 := ip.To4()
|
if !ip.Is4() {
|
||||||
if ip4 == nil {
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
netIP := ip.AsSlice()
|
||||||
for _, l := range s.leases {
|
for _, l := range s.leases {
|
||||||
if l.IP.Equal(ip4) {
|
if l.IP.Equal(netIP) {
|
||||||
if l.Expiry.After(now) || l.IsStatic() {
|
if l.Expiry.After(now) || l.IsStatic() {
|
||||||
return l.HWAddr
|
return l.HWAddr
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
"net/netip"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -107,21 +108,26 @@ func (s *v6Server) getLeasesRef() []*Lease {
|
||||||
return s.leases
|
return s.leases
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindMACbyIP - find a MAC address by IP address in the currently active DHCP leases
|
// FindMACbyIP implements the [Interface] for *v6Server.
|
||||||
func (s *v6Server) FindMACbyIP(ip net.IP) net.HardwareAddr {
|
func (s *v6Server) FindMACbyIP(ip netip.Addr) (mac net.HardwareAddr) {
|
||||||
now := time.Now().Unix()
|
now := time.Now()
|
||||||
|
|
||||||
s.leasesLock.Lock()
|
s.leasesLock.Lock()
|
||||||
defer s.leasesLock.Unlock()
|
defer s.leasesLock.Unlock()
|
||||||
|
|
||||||
|
if !ip.Is6() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
netIP := ip.AsSlice()
|
||||||
for _, l := range s.leases {
|
for _, l := range s.leases {
|
||||||
if l.IP.Equal(ip) {
|
if l.IP.Equal(netIP) {
|
||||||
unix := l.Expiry.Unix()
|
if l.Expiry.After(now) || l.IsStatic() {
|
||||||
if unix > now || unix == leaseExpireStatic {
|
|
||||||
return l.HWAddr
|
return l.HWAddr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,6 @@ const (
|
||||||
// The zero FilteringConfig is empty and ready for use.
|
// The zero FilteringConfig is empty and ready for use.
|
||||||
type FilteringConfig struct {
|
type FilteringConfig struct {
|
||||||
// Callbacks for other modules
|
// Callbacks for other modules
|
||||||
// --
|
|
||||||
|
|
||||||
// FilterHandler is an optional additional filtering callback.
|
// FilterHandler is an optional additional filtering callback.
|
||||||
FilterHandler func(clientAddr net.IP, clientID string, settings *filtering.Settings) `yaml:"-"`
|
FilterHandler func(clientAddr net.IP, clientID string, settings *filtering.Settings) `yaml:"-"`
|
||||||
|
@ -64,50 +63,82 @@ type FilteringConfig struct {
|
||||||
GetCustomUpstreamByClient func(id string) (conf *proxy.UpstreamConfig, err error) `yaml:"-"`
|
GetCustomUpstreamByClient func(id string) (conf *proxy.UpstreamConfig, err error) `yaml:"-"`
|
||||||
|
|
||||||
// Protection configuration
|
// Protection configuration
|
||||||
// --
|
|
||||||
|
|
||||||
ProtectionEnabled bool `yaml:"protection_enabled"` // whether or not use any of filtering features
|
// ProtectionEnabled defines whether or not use any of filtering features.
|
||||||
BlockingMode BlockingMode `yaml:"blocking_mode"` // mode how to answer filtered requests
|
ProtectionEnabled bool `yaml:"protection_enabled"`
|
||||||
BlockingIPv4 net.IP `yaml:"blocking_ipv4"` // IP address to be returned for a blocked A request
|
|
||||||
BlockingIPv6 net.IP `yaml:"blocking_ipv6"` // IP address to be returned for a blocked AAAA request
|
|
||||||
BlockedResponseTTL uint32 `yaml:"blocked_response_ttl"` // if 0, then default is used (3600)
|
|
||||||
|
|
||||||
// IP (or domain name) which is used to respond to DNS requests blocked by parental control or safe-browsing
|
// BlockingMode defines the way how blocked responses are constructed.
|
||||||
|
BlockingMode BlockingMode `yaml:"blocking_mode"`
|
||||||
|
|
||||||
|
// BlockingIPv4 is the IP address to be returned for a blocked A request.
|
||||||
|
BlockingIPv4 net.IP `yaml:"blocking_ipv4"`
|
||||||
|
|
||||||
|
// BlockingIPv6 is the IP address to be returned for a blocked AAAA
|
||||||
|
// request.
|
||||||
|
BlockingIPv6 net.IP `yaml:"blocking_ipv6"`
|
||||||
|
|
||||||
|
// BlockedResponseTTL is the time-to-live value for blocked responses. If
|
||||||
|
// 0, then default value is used (3600).
|
||||||
|
BlockedResponseTTL uint32 `yaml:"blocked_response_ttl"`
|
||||||
|
|
||||||
|
// ParentalBlockHost is the IP (or domain name) which is used to respond to
|
||||||
|
// DNS requests blocked by parental control.
|
||||||
ParentalBlockHost string `yaml:"parental_block_host"`
|
ParentalBlockHost string `yaml:"parental_block_host"`
|
||||||
|
|
||||||
|
// SafeBrowsingBlockHost is the IP (or domain name) which is used to
|
||||||
|
// respond to DNS requests blocked by safe-browsing.
|
||||||
SafeBrowsingBlockHost string `yaml:"safebrowsing_block_host"`
|
SafeBrowsingBlockHost string `yaml:"safebrowsing_block_host"`
|
||||||
|
|
||||||
// Anti-DNS amplification
|
// Anti-DNS amplification
|
||||||
// --
|
|
||||||
|
|
||||||
Ratelimit uint32 `yaml:"ratelimit"` // max number of requests per second from a given IP (0 to disable)
|
// Ratelimit is the maximum number of requests per second from a given IP
|
||||||
RatelimitWhitelist []string `yaml:"ratelimit_whitelist"` // a list of whitelisted client IP addresses
|
// (0 to disable).
|
||||||
RefuseAny bool `yaml:"refuse_any"` // if true, refuse ANY requests
|
Ratelimit uint32 `yaml:"ratelimit"`
|
||||||
|
|
||||||
|
// RatelimitWhitelist is the list of whitelisted client IP addresses.
|
||||||
|
RatelimitWhitelist []string `yaml:"ratelimit_whitelist"`
|
||||||
|
|
||||||
|
// RefuseAny, if true, refuse ANY requests.
|
||||||
|
RefuseAny bool `yaml:"refuse_any"`
|
||||||
|
|
||||||
// Upstream DNS servers configuration
|
// Upstream DNS servers configuration
|
||||||
// --
|
|
||||||
|
|
||||||
|
// UpstreamDNS is the list of upstream DNS servers.
|
||||||
UpstreamDNS []string `yaml:"upstream_dns"`
|
UpstreamDNS []string `yaml:"upstream_dns"`
|
||||||
|
|
||||||
|
// UpstreamDNSFileName, if set, points to the file which contains upstream
|
||||||
|
// DNS servers.
|
||||||
UpstreamDNSFileName string `yaml:"upstream_dns_file"`
|
UpstreamDNSFileName string `yaml:"upstream_dns_file"`
|
||||||
BootstrapDNS []string `yaml:"bootstrap_dns"` // a list of bootstrap DNS for DoH and DoT (plain DNS only)
|
|
||||||
AllServers bool `yaml:"all_servers"` // if true, parallel queries to all configured upstream servers are enabled
|
// BootstrapDNS is the list of bootstrap DNS servers for DoH and DoT
|
||||||
FastestAddr bool `yaml:"fastest_addr"` // use Fastest Address algorithm
|
// resolvers (plain DNS only).
|
||||||
|
BootstrapDNS []string `yaml:"bootstrap_dns"`
|
||||||
|
|
||||||
|
// AllServers, if true, parallel queries to all configured upstream servers
|
||||||
|
// are enabled.
|
||||||
|
AllServers bool `yaml:"all_servers"`
|
||||||
|
|
||||||
|
// FastestAddr, if true, use Fastest Address algorithm.
|
||||||
|
FastestAddr bool `yaml:"fastest_addr"`
|
||||||
|
|
||||||
// FastestTimeout replaces the default timeout for dialing IP addresses
|
// FastestTimeout replaces the default timeout for dialing IP addresses
|
||||||
// when FastestAddr is true.
|
// when FastestAddr is true.
|
||||||
FastestTimeout timeutil.Duration `yaml:"fastest_timeout"`
|
FastestTimeout timeutil.Duration `yaml:"fastest_timeout"`
|
||||||
|
|
||||||
// Access settings
|
// Access settings
|
||||||
// --
|
|
||||||
|
|
||||||
// AllowedClients is the slice of IP addresses, CIDR networks, and ClientIDs
|
// AllowedClients is the slice of IP addresses, CIDR networks, and
|
||||||
// of allowed clients. If not empty, only these clients are allowed, and
|
// ClientIDs of allowed clients. If not empty, only these clients are
|
||||||
// [FilteringConfig.DisallowedClients] are ignored.
|
// allowed, and [FilteringConfig.DisallowedClients] are ignored.
|
||||||
AllowedClients []string `yaml:"allowed_clients"`
|
AllowedClients []string `yaml:"allowed_clients"`
|
||||||
|
|
||||||
// DisallowedClients is the slice of IP addresses, CIDR networks, and
|
// DisallowedClients is the slice of IP addresses, CIDR networks, and
|
||||||
// ClientIDs of disallowed clients.
|
// ClientIDs of disallowed clients.
|
||||||
DisallowedClients []string `yaml:"disallowed_clients"`
|
DisallowedClients []string `yaml:"disallowed_clients"`
|
||||||
|
|
||||||
BlockedHosts []string `yaml:"blocked_hosts"` // hosts that should be blocked
|
// BlockedHosts is the list of hosts that should be blocked.
|
||||||
|
BlockedHosts []string `yaml:"blocked_hosts"`
|
||||||
|
|
||||||
// TrustedProxies is the list of IP addresses and CIDR networks to detect
|
// TrustedProxies is the list of IP addresses and CIDR networks to detect
|
||||||
// proxy servers addresses the DoH requests from which should be handled.
|
// proxy servers addresses the DoH requests from which should be handled.
|
||||||
// The value of nil or an empty slice for this field makes Proxy not trust
|
// The value of nil or an empty slice for this field makes Proxy not trust
|
||||||
|
@ -115,26 +146,46 @@ type FilteringConfig struct {
|
||||||
TrustedProxies []string `yaml:"trusted_proxies"`
|
TrustedProxies []string `yaml:"trusted_proxies"`
|
||||||
|
|
||||||
// DNS cache settings
|
// DNS cache settings
|
||||||
// --
|
|
||||||
|
|
||||||
CacheSize uint32 `yaml:"cache_size"` // DNS cache size (in bytes)
|
// CacheSize is the DNS cache size (in bytes).
|
||||||
CacheMinTTL uint32 `yaml:"cache_ttl_min"` // override TTL value (minimum) received from upstream server
|
CacheSize uint32 `yaml:"cache_size"`
|
||||||
CacheMaxTTL uint32 `yaml:"cache_ttl_max"` // override TTL value (maximum) received from upstream server
|
|
||||||
|
// CacheMinTTL is the override TTL value (minimum) received from upstream
|
||||||
|
// server.
|
||||||
|
CacheMinTTL uint32 `yaml:"cache_ttl_min"`
|
||||||
|
|
||||||
|
// CacheMaxTTL is the override TTL value (maximum) received from upstream
|
||||||
|
// server.
|
||||||
|
CacheMaxTTL uint32 `yaml:"cache_ttl_max"`
|
||||||
|
|
||||||
// CacheOptimistic defines if optimistic cache mechanism should be used.
|
// CacheOptimistic defines if optimistic cache mechanism should be used.
|
||||||
CacheOptimistic bool `yaml:"cache_optimistic"`
|
CacheOptimistic bool `yaml:"cache_optimistic"`
|
||||||
|
|
||||||
// Other settings
|
// Other settings
|
||||||
// --
|
|
||||||
|
|
||||||
BogusNXDomain []string `yaml:"bogus_nxdomain"` // transform responses with these IP addresses to NXDOMAIN
|
// BogusNXDomain is the list of IP addresses, responses with them will be
|
||||||
AAAADisabled bool `yaml:"aaaa_disabled"` // Respond with an empty answer to all AAAA requests
|
// transformed to NXDOMAIN.
|
||||||
EnableDNSSEC bool `yaml:"enable_dnssec"` // Set AD flag in outcoming DNS request
|
BogusNXDomain []string `yaml:"bogus_nxdomain"`
|
||||||
EnableEDNSClientSubnet bool `yaml:"edns_client_subnet"` // Enable EDNS Client Subnet option
|
|
||||||
MaxGoroutines uint32 `yaml:"max_goroutines"` // Max. number of parallel goroutines for processing incoming requests
|
|
||||||
HandleDDR bool `yaml:"handle_ddr"` // Handle DDR requests
|
|
||||||
|
|
||||||
// IpsetList is the ipset configuration that allows AdGuard Home to add
|
// AAAADisabled, if true, respond with an empty answer to all AAAA
|
||||||
// IP addresses of the specified domain names to an ipset list. Syntax:
|
// requests.
|
||||||
|
AAAADisabled bool `yaml:"aaaa_disabled"`
|
||||||
|
|
||||||
|
// EnableDNSSEC, if true, set AD flag in outcoming DNS request.
|
||||||
|
EnableDNSSEC bool `yaml:"enable_dnssec"`
|
||||||
|
|
||||||
|
// EDNSClientSubnet is the settings list for EDNS Client Subnet.
|
||||||
|
EDNSClientSubnet *EDNSClientSubnet `yaml:"edns_client_subnet"`
|
||||||
|
|
||||||
|
// MaxGoroutines is the max number of parallel goroutines for processing
|
||||||
|
// incoming requests.
|
||||||
|
MaxGoroutines uint32 `yaml:"max_goroutines"`
|
||||||
|
|
||||||
|
// HandleDDR, if true, handle DDR requests
|
||||||
|
HandleDDR bool `yaml:"handle_ddr"`
|
||||||
|
|
||||||
|
// IpsetList is the ipset configuration that allows AdGuard Home to add IP
|
||||||
|
// addresses of the specified domain names to an ipset list. Syntax:
|
||||||
//
|
//
|
||||||
// DOMAIN[,DOMAIN].../IPSET_NAME
|
// DOMAIN[,DOMAIN].../IPSET_NAME
|
||||||
//
|
//
|
||||||
|
@ -146,6 +197,18 @@ type FilteringConfig struct {
|
||||||
IpsetListFileName string `yaml:"ipset_file"`
|
IpsetListFileName string `yaml:"ipset_file"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EDNSClientSubnet is the settings list for EDNS Client Subnet.
|
||||||
|
type EDNSClientSubnet struct {
|
||||||
|
// CustomIP for EDNS Client Subnet.
|
||||||
|
CustomIP string `yaml:"custom_ip"`
|
||||||
|
|
||||||
|
// Enabled defines if EDNS Client Subnet is enabled.
|
||||||
|
Enabled bool `yaml:"enabled"`
|
||||||
|
|
||||||
|
// UseCustom defines if CustomIP should be used.
|
||||||
|
UseCustom bool `yaml:"use_custom"`
|
||||||
|
}
|
||||||
|
|
||||||
// TLSConfig is the TLS configuration for HTTPS, DNS-over-HTTPS, and DNS-over-TLS
|
// TLSConfig is the TLS configuration for HTTPS, DNS-over-HTTPS, and DNS-over-TLS
|
||||||
type TLSConfig struct {
|
type TLSConfig struct {
|
||||||
cert tls.Certificate
|
cert tls.Certificate
|
||||||
|
@ -270,12 +333,24 @@ func (s *Server) createProxyConfig() (conf proxy.Config, err error) {
|
||||||
UpstreamConfig: srvConf.UpstreamConfig,
|
UpstreamConfig: srvConf.UpstreamConfig,
|
||||||
BeforeRequestHandler: s.beforeRequestHandler,
|
BeforeRequestHandler: s.beforeRequestHandler,
|
||||||
RequestHandler: s.handleDNSRequest,
|
RequestHandler: s.handleDNSRequest,
|
||||||
EnableEDNSClientSubnet: srvConf.EnableEDNSClientSubnet,
|
EnableEDNSClientSubnet: srvConf.EDNSClientSubnet.Enabled,
|
||||||
MaxGoroutines: int(srvConf.MaxGoroutines),
|
MaxGoroutines: int(srvConf.MaxGoroutines),
|
||||||
UseDNS64: srvConf.UseDNS64,
|
UseDNS64: srvConf.UseDNS64,
|
||||||
DNS64Prefs: srvConf.DNS64Prefixes,
|
DNS64Prefs: srvConf.DNS64Prefixes,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if srvConf.EDNSClientSubnet.UseCustom {
|
||||||
|
// TODO(s.chzhen): Add wrapper around netip.Addr.
|
||||||
|
var ip net.IP
|
||||||
|
ip, err = netutil.ParseIP(srvConf.EDNSClientSubnet.CustomIP)
|
||||||
|
if err != nil {
|
||||||
|
return conf, fmt.Errorf("edns: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(s.chzhen): Use netip.Addr instead of net.IP inside dnsproxy.
|
||||||
|
conf.EDNSAddr = ip
|
||||||
|
}
|
||||||
|
|
||||||
if srvConf.CacheSize != 0 {
|
if srvConf.CacheSize != 0 {
|
||||||
conf.CacheEnabled = true
|
conf.CacheEnabled = true
|
||||||
conf.CacheSizeBytes = int(srvConf.CacheSize)
|
conf.CacheSizeBytes = int(srvConf.CacheSize)
|
||||||
|
|
|
@ -287,6 +287,9 @@ func TestServer_HandleDNSRequest_dns64(t *testing.T) {
|
||||||
UDPListenAddrs: []*net.UDPAddr{{}},
|
UDPListenAddrs: []*net.UDPAddr{{}},
|
||||||
TCPListenAddrs: []*net.TCPAddr{{}},
|
TCPListenAddrs: []*net.TCPAddr{{}},
|
||||||
UseDNS64: true,
|
UseDNS64: true,
|
||||||
|
FilteringConfig: FilteringConfig{
|
||||||
|
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},
|
||||||
|
},
|
||||||
}, localUps)
|
}, localUps)
|
||||||
|
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
|
|
@ -467,6 +467,11 @@ func TestServer_ProcessRestrictLocal(t *testing.T) {
|
||||||
s := createTestServer(t, &filtering.Config{}, ServerConfig{
|
s := createTestServer(t, &filtering.Config{}, ServerConfig{
|
||||||
UDPListenAddrs: []*net.UDPAddr{{}},
|
UDPListenAddrs: []*net.UDPAddr{{}},
|
||||||
TCPListenAddrs: []*net.TCPAddr{{}},
|
TCPListenAddrs: []*net.TCPAddr{{}},
|
||||||
|
// TODO(s.chzhen): Add tests where EDNSClientSubnet.Enabled is true.
|
||||||
|
// Improve FilteringConfig declaration for tests.
|
||||||
|
FilteringConfig: FilteringConfig{
|
||||||
|
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},
|
||||||
|
},
|
||||||
}, ups)
|
}, ups)
|
||||||
s.conf.UpstreamConfig.Upstreams = []upstream.Upstream{ups}
|
s.conf.UpstreamConfig.Upstreams = []upstream.Upstream{ups}
|
||||||
startDeferStop(t, s)
|
startDeferStop(t, s)
|
||||||
|
@ -539,6 +544,9 @@ func TestServer_ProcessLocalPTR_usingResolvers(t *testing.T) {
|
||||||
ServerConfig{
|
ServerConfig{
|
||||||
UDPListenAddrs: []*net.UDPAddr{{}},
|
UDPListenAddrs: []*net.UDPAddr{{}},
|
||||||
TCPListenAddrs: []*net.TCPAddr{{}},
|
TCPListenAddrs: []*net.TCPAddr{{}},
|
||||||
|
FilteringConfig: FilteringConfig{
|
||||||
|
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
aghtest.NewUpstreamMock(func(req *dns.Msg) (resp *dns.Msg, err error) {
|
aghtest.NewUpstreamMock(func(req *dns.Msg) (resp *dns.Msg, err error) {
|
||||||
return aghalg.Coalesce(
|
return aghalg.Coalesce(
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"net"
|
"net"
|
||||||
|
"net/netip"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -155,6 +156,9 @@ func createTestTLS(t *testing.T, tlsConf TLSConfig) (s *Server, certPem []byte)
|
||||||
s = createTestServer(t, &filtering.Config{}, ServerConfig{
|
s = createTestServer(t, &filtering.Config{}, ServerConfig{
|
||||||
UDPListenAddrs: []*net.UDPAddr{{}},
|
UDPListenAddrs: []*net.UDPAddr{{}},
|
||||||
TCPListenAddrs: []*net.TCPAddr{{}},
|
TCPListenAddrs: []*net.TCPAddr{{}},
|
||||||
|
FilteringConfig: FilteringConfig{
|
||||||
|
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},
|
||||||
|
},
|
||||||
}, nil)
|
}, nil)
|
||||||
|
|
||||||
tlsConf.CertificateChainData, tlsConf.PrivateKeyData = certPem, keyPem
|
tlsConf.CertificateChainData, tlsConf.PrivateKeyData = certPem, keyPem
|
||||||
|
@ -266,6 +270,9 @@ func TestServer(t *testing.T) {
|
||||||
s := createTestServer(t, &filtering.Config{}, ServerConfig{
|
s := createTestServer(t, &filtering.Config{}, ServerConfig{
|
||||||
UDPListenAddrs: []*net.UDPAddr{{}},
|
UDPListenAddrs: []*net.UDPAddr{{}},
|
||||||
TCPListenAddrs: []*net.TCPAddr{{}},
|
TCPListenAddrs: []*net.TCPAddr{{}},
|
||||||
|
FilteringConfig: FilteringConfig{
|
||||||
|
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},
|
||||||
|
},
|
||||||
}, nil)
|
}, nil)
|
||||||
s.conf.UpstreamConfig.Upstreams = []upstream.Upstream{newGoogleUpstream()}
|
s.conf.UpstreamConfig.Upstreams = []upstream.Upstream{newGoogleUpstream()}
|
||||||
startDeferStop(t, s)
|
startDeferStop(t, s)
|
||||||
|
@ -305,6 +312,7 @@ func TestServer_timeout(t *testing.T) {
|
||||||
UpstreamTimeout: timeout,
|
UpstreamTimeout: timeout,
|
||||||
FilteringConfig: FilteringConfig{
|
FilteringConfig: FilteringConfig{
|
||||||
BlockingMode: BlockingModeDefault,
|
BlockingMode: BlockingModeDefault,
|
||||||
|
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -322,6 +330,9 @@ func TestServer_timeout(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
s.conf.FilteringConfig.BlockingMode = BlockingModeDefault
|
s.conf.FilteringConfig.BlockingMode = BlockingModeDefault
|
||||||
|
s.conf.FilteringConfig.EDNSClientSubnet = &EDNSClientSubnet{
|
||||||
|
Enabled: false,
|
||||||
|
}
|
||||||
err = s.Prepare(&s.conf)
|
err = s.Prepare(&s.conf)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
@ -333,6 +344,9 @@ func TestServerWithProtectionDisabled(t *testing.T) {
|
||||||
s := createTestServer(t, &filtering.Config{}, ServerConfig{
|
s := createTestServer(t, &filtering.Config{}, ServerConfig{
|
||||||
UDPListenAddrs: []*net.UDPAddr{{}},
|
UDPListenAddrs: []*net.UDPAddr{{}},
|
||||||
TCPListenAddrs: []*net.TCPAddr{{}},
|
TCPListenAddrs: []*net.TCPAddr{{}},
|
||||||
|
FilteringConfig: FilteringConfig{
|
||||||
|
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},
|
||||||
|
},
|
||||||
}, nil)
|
}, nil)
|
||||||
s.conf.UpstreamConfig.Upstreams = []upstream.Upstream{newGoogleUpstream()}
|
s.conf.UpstreamConfig.Upstreams = []upstream.Upstream{newGoogleUpstream()}
|
||||||
startDeferStop(t, s)
|
startDeferStop(t, s)
|
||||||
|
@ -437,6 +451,9 @@ func TestSafeSearch(t *testing.T) {
|
||||||
TCPListenAddrs: []*net.TCPAddr{{}},
|
TCPListenAddrs: []*net.TCPAddr{{}},
|
||||||
FilteringConfig: FilteringConfig{
|
FilteringConfig: FilteringConfig{
|
||||||
ProtectionEnabled: true,
|
ProtectionEnabled: true,
|
||||||
|
EDNSClientSubnet: &EDNSClientSubnet{
|
||||||
|
Enabled: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
s := createTestServer(t, filterConf, forwardConf, nil)
|
s := createTestServer(t, filterConf, forwardConf, nil)
|
||||||
|
@ -492,6 +509,11 @@ func TestInvalidRequest(t *testing.T) {
|
||||||
s := createTestServer(t, &filtering.Config{}, ServerConfig{
|
s := createTestServer(t, &filtering.Config{}, ServerConfig{
|
||||||
UDPListenAddrs: []*net.UDPAddr{{}},
|
UDPListenAddrs: []*net.UDPAddr{{}},
|
||||||
TCPListenAddrs: []*net.TCPAddr{{}},
|
TCPListenAddrs: []*net.TCPAddr{{}},
|
||||||
|
FilteringConfig: FilteringConfig{
|
||||||
|
EDNSClientSubnet: &EDNSClientSubnet{
|
||||||
|
Enabled: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
}, nil)
|
}, nil)
|
||||||
startDeferStop(t, s)
|
startDeferStop(t, s)
|
||||||
|
|
||||||
|
@ -518,6 +540,9 @@ func TestBlockedRequest(t *testing.T) {
|
||||||
FilteringConfig: FilteringConfig{
|
FilteringConfig: FilteringConfig{
|
||||||
ProtectionEnabled: true,
|
ProtectionEnabled: true,
|
||||||
BlockingMode: BlockingModeDefault,
|
BlockingMode: BlockingModeDefault,
|
||||||
|
EDNSClientSubnet: &EDNSClientSubnet{
|
||||||
|
Enabled: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
s := createTestServer(t, &filtering.Config{}, forwardConf, nil)
|
s := createTestServer(t, &filtering.Config{}, forwardConf, nil)
|
||||||
|
@ -543,6 +568,9 @@ func TestServerCustomClientUpstream(t *testing.T) {
|
||||||
TCPListenAddrs: []*net.TCPAddr{{}},
|
TCPListenAddrs: []*net.TCPAddr{{}},
|
||||||
FilteringConfig: FilteringConfig{
|
FilteringConfig: FilteringConfig{
|
||||||
ProtectionEnabled: true,
|
ProtectionEnabled: true,
|
||||||
|
EDNSClientSubnet: &EDNSClientSubnet{
|
||||||
|
Enabled: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
s := createTestServer(t, &filtering.Config{}, forwardConf, nil)
|
s := createTestServer(t, &filtering.Config{}, forwardConf, nil)
|
||||||
|
@ -591,6 +619,11 @@ func TestBlockCNAMEProtectionEnabled(t *testing.T) {
|
||||||
s := createTestServer(t, &filtering.Config{}, ServerConfig{
|
s := createTestServer(t, &filtering.Config{}, ServerConfig{
|
||||||
UDPListenAddrs: []*net.UDPAddr{{}},
|
UDPListenAddrs: []*net.UDPAddr{{}},
|
||||||
TCPListenAddrs: []*net.TCPAddr{{}},
|
TCPListenAddrs: []*net.TCPAddr{{}},
|
||||||
|
FilteringConfig: FilteringConfig{
|
||||||
|
EDNSClientSubnet: &EDNSClientSubnet{
|
||||||
|
Enabled: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
}, nil)
|
}, nil)
|
||||||
testUpstm := &aghtest.Upstream{
|
testUpstm := &aghtest.Upstream{
|
||||||
CName: testCNAMEs,
|
CName: testCNAMEs,
|
||||||
|
@ -621,6 +654,9 @@ func TestBlockCNAME(t *testing.T) {
|
||||||
FilteringConfig: FilteringConfig{
|
FilteringConfig: FilteringConfig{
|
||||||
ProtectionEnabled: true,
|
ProtectionEnabled: true,
|
||||||
BlockingMode: BlockingModeDefault,
|
BlockingMode: BlockingModeDefault,
|
||||||
|
EDNSClientSubnet: &EDNSClientSubnet{
|
||||||
|
Enabled: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
s := createTestServer(t, &filtering.Config{}, forwardConf, nil)
|
s := createTestServer(t, &filtering.Config{}, forwardConf, nil)
|
||||||
|
@ -690,6 +726,9 @@ func TestClientRulesForCNAMEMatching(t *testing.T) {
|
||||||
FilterHandler: func(_ net.IP, _ string, settings *filtering.Settings) {
|
FilterHandler: func(_ net.IP, _ string, settings *filtering.Settings) {
|
||||||
settings.FilteringEnabled = false
|
settings.FilteringEnabled = false
|
||||||
},
|
},
|
||||||
|
EDNSClientSubnet: &EDNSClientSubnet{
|
||||||
|
Enabled: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
s := createTestServer(t, &filtering.Config{}, forwardConf, nil)
|
s := createTestServer(t, &filtering.Config{}, forwardConf, nil)
|
||||||
|
@ -731,6 +770,9 @@ func TestNullBlockedRequest(t *testing.T) {
|
||||||
FilteringConfig: FilteringConfig{
|
FilteringConfig: FilteringConfig{
|
||||||
ProtectionEnabled: true,
|
ProtectionEnabled: true,
|
||||||
BlockingMode: BlockingModeNullIP,
|
BlockingMode: BlockingModeNullIP,
|
||||||
|
EDNSClientSubnet: &EDNSClientSubnet{
|
||||||
|
Enabled: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
s := createTestServer(t, &filtering.Config{}, forwardConf, nil)
|
s := createTestServer(t, &filtering.Config{}, forwardConf, nil)
|
||||||
|
@ -783,6 +825,9 @@ func TestBlockedCustomIP(t *testing.T) {
|
||||||
BlockingMode: BlockingModeCustomIP,
|
BlockingMode: BlockingModeCustomIP,
|
||||||
BlockingIPv4: nil,
|
BlockingIPv4: nil,
|
||||||
UpstreamDNS: []string{"8.8.8.8:53", "8.8.4.4:53"},
|
UpstreamDNS: []string{"8.8.8.8:53", "8.8.4.4:53"},
|
||||||
|
EDNSClientSubnet: &EDNSClientSubnet{
|
||||||
|
Enabled: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -831,6 +876,9 @@ func TestBlockedByHosts(t *testing.T) {
|
||||||
FilteringConfig: FilteringConfig{
|
FilteringConfig: FilteringConfig{
|
||||||
ProtectionEnabled: true,
|
ProtectionEnabled: true,
|
||||||
BlockingMode: BlockingModeDefault,
|
BlockingMode: BlockingModeDefault,
|
||||||
|
EDNSClientSubnet: &EDNSClientSubnet{
|
||||||
|
Enabled: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -864,6 +912,9 @@ func TestBlockedBySafeBrowsing(t *testing.T) {
|
||||||
FilteringConfig: FilteringConfig{
|
FilteringConfig: FilteringConfig{
|
||||||
SafeBrowsingBlockHost: ans4.String(),
|
SafeBrowsingBlockHost: ans4.String(),
|
||||||
ProtectionEnabled: true,
|
ProtectionEnabled: true,
|
||||||
|
EDNSClientSubnet: &EDNSClientSubnet{
|
||||||
|
Enabled: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
s := createTestServer(t, filterConf, forwardConf, nil)
|
s := createTestServer(t, filterConf, forwardConf, nil)
|
||||||
|
@ -918,6 +969,9 @@ func TestRewrite(t *testing.T) {
|
||||||
ProtectionEnabled: true,
|
ProtectionEnabled: true,
|
||||||
BlockingMode: BlockingModeDefault,
|
BlockingMode: BlockingModeDefault,
|
||||||
UpstreamDNS: []string{"8.8.8.8:53"},
|
UpstreamDNS: []string{"8.8.8.8:53"},
|
||||||
|
EDNSClientSubnet: &EDNSClientSubnet{
|
||||||
|
Enabled: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
@ -1009,7 +1063,7 @@ var testDHCP = &dhcpd.MockInterface{
|
||||||
}}
|
}}
|
||||||
},
|
},
|
||||||
OnSetOnLeaseChanged: func(olct dhcpd.OnLeaseChangedT) {},
|
OnSetOnLeaseChanged: func(olct dhcpd.OnLeaseChangedT) {},
|
||||||
OnFindMACbyIP: func(ip net.IP) (mac net.HardwareAddr) { panic("not implemented") },
|
OnFindMACbyIP: func(ip netip.Addr) (mac net.HardwareAddr) { panic("not implemented") },
|
||||||
OnWriteDiskConfig: func(c *dhcpd.ServerConfig) { panic("not implemented") },
|
OnWriteDiskConfig: func(c *dhcpd.ServerConfig) { panic("not implemented") },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1032,6 +1086,7 @@ func TestPTRResponseFromDHCPLeases(t *testing.T) {
|
||||||
s.conf.UpstreamDNS = []string{"127.0.0.1:53"}
|
s.conf.UpstreamDNS = []string{"127.0.0.1:53"}
|
||||||
s.conf.FilteringConfig.ProtectionEnabled = true
|
s.conf.FilteringConfig.ProtectionEnabled = true
|
||||||
s.conf.FilteringConfig.BlockingMode = BlockingModeDefault
|
s.conf.FilteringConfig.BlockingMode = BlockingModeDefault
|
||||||
|
s.conf.FilteringConfig.EDNSClientSubnet = &EDNSClientSubnet{Enabled: false}
|
||||||
|
|
||||||
err = s.Prepare(&s.conf)
|
err = s.Prepare(&s.conf)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -1107,6 +1162,7 @@ func TestPTRResponseFromHosts(t *testing.T) {
|
||||||
s.conf.TCPListenAddrs = []*net.TCPAddr{{}}
|
s.conf.TCPListenAddrs = []*net.TCPAddr{{}}
|
||||||
s.conf.UpstreamDNS = []string{"127.0.0.1:53"}
|
s.conf.UpstreamDNS = []string{"127.0.0.1:53"}
|
||||||
s.conf.FilteringConfig.BlockingMode = BlockingModeDefault
|
s.conf.FilteringConfig.BlockingMode = BlockingModeDefault
|
||||||
|
s.conf.FilteringConfig.EDNSClientSubnet = &EDNSClientSubnet{Enabled: false}
|
||||||
|
|
||||||
err = s.Prepare(&s.conf)
|
err = s.Prepare(&s.conf)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
|
@ -29,6 +29,9 @@ func TestHandleDNSRequest_filterDNSResponse(t *testing.T) {
|
||||||
FilteringConfig: FilteringConfig{
|
FilteringConfig: FilteringConfig{
|
||||||
ProtectionEnabled: true,
|
ProtectionEnabled: true,
|
||||||
BlockingMode: BlockingModeDefault,
|
BlockingMode: BlockingModeDefault,
|
||||||
|
EDNSClientSubnet: &EDNSClientSubnet{
|
||||||
|
Enabled: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
filters := []filtering.Filter{{
|
filters := []filtering.Filter{{
|
||||||
|
|
|
@ -57,7 +57,7 @@ func (s *Server) getDNSConfig() (c *jsonDNSConfig) {
|
||||||
blockingIPv4 := s.conf.BlockingIPv4
|
blockingIPv4 := s.conf.BlockingIPv4
|
||||||
blockingIPv6 := s.conf.BlockingIPv6
|
blockingIPv6 := s.conf.BlockingIPv6
|
||||||
ratelimit := s.conf.Ratelimit
|
ratelimit := s.conf.Ratelimit
|
||||||
enableEDNSClientSubnet := s.conf.EnableEDNSClientSubnet
|
enableEDNSClientSubnet := s.conf.EDNSClientSubnet.Enabled
|
||||||
enableDNSSEC := s.conf.EnableDNSSEC
|
enableDNSSEC := s.conf.EnableDNSSEC
|
||||||
aaaaDisabled := s.conf.AAAADisabled
|
aaaaDisabled := s.conf.AAAADisabled
|
||||||
cacheSize := s.conf.CacheSize
|
cacheSize := s.conf.CacheSize
|
||||||
|
@ -280,7 +280,7 @@ func (s *Server) setConfigRestartable(dc *jsonDNSConfig) (shouldRestart bool) {
|
||||||
setIfNotNil(&s.conf.LocalPTRResolvers, dc.LocalPTRUpstreams),
|
setIfNotNil(&s.conf.LocalPTRResolvers, dc.LocalPTRUpstreams),
|
||||||
setIfNotNil(&s.conf.UpstreamDNSFileName, dc.UpstreamsFile),
|
setIfNotNil(&s.conf.UpstreamDNSFileName, dc.UpstreamsFile),
|
||||||
setIfNotNil(&s.conf.BootstrapDNS, dc.Bootstraps),
|
setIfNotNil(&s.conf.BootstrapDNS, dc.Bootstraps),
|
||||||
setIfNotNil(&s.conf.EnableEDNSClientSubnet, dc.EDNSCSEnabled),
|
setIfNotNil(&s.conf.EDNSClientSubnet.Enabled, dc.EDNSCSEnabled),
|
||||||
setIfNotNil(&s.conf.CacheSize, dc.CacheSize),
|
setIfNotNil(&s.conf.CacheSize, dc.CacheSize),
|
||||||
setIfNotNil(&s.conf.CacheMinTTL, dc.CacheMinTTL),
|
setIfNotNil(&s.conf.CacheMinTTL, dc.CacheMinTTL),
|
||||||
setIfNotNil(&s.conf.CacheMaxTTL, dc.CacheMaxTTL),
|
setIfNotNil(&s.conf.CacheMaxTTL, dc.CacheMaxTTL),
|
||||||
|
|
|
@ -69,6 +69,7 @@ func TestDNSForwardHTTP_handleGetConfig(t *testing.T) {
|
||||||
ProtectionEnabled: true,
|
ProtectionEnabled: true,
|
||||||
BlockingMode: BlockingModeDefault,
|
BlockingMode: BlockingModeDefault,
|
||||||
UpstreamDNS: []string{"8.8.8.8:53", "8.8.4.4:53"},
|
UpstreamDNS: []string{"8.8.8.8:53", "8.8.4.4:53"},
|
||||||
|
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},
|
||||||
},
|
},
|
||||||
ConfigModified: func() {},
|
ConfigModified: func() {},
|
||||||
}
|
}
|
||||||
|
@ -144,6 +145,7 @@ func TestDNSForwardHTTP_handleSetConfig(t *testing.T) {
|
||||||
ProtectionEnabled: true,
|
ProtectionEnabled: true,
|
||||||
BlockingMode: BlockingModeDefault,
|
BlockingMode: BlockingModeDefault,
|
||||||
UpstreamDNS: []string{"8.8.8.8:53", "8.8.4.4:53"},
|
UpstreamDNS: []string{"8.8.8.8:53", "8.8.4.4:53"},
|
||||||
|
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},
|
||||||
},
|
},
|
||||||
ConfigModified: func() {},
|
ConfigModified: func() {},
|
||||||
}
|
}
|
||||||
|
@ -227,7 +229,10 @@ func TestDNSForwardHTTP_handleSetConfig(t *testing.T) {
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
|
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
t.Cleanup(func() { s.conf = defaultConf })
|
t.Cleanup(func() {
|
||||||
|
s.conf = defaultConf
|
||||||
|
s.conf.FilteringConfig.EDNSClientSubnet.Enabled = false
|
||||||
|
})
|
||||||
|
|
||||||
rBody := io.NopCloser(bytes.NewReader(caseData.Req))
|
rBody := io.NopCloser(bytes.NewReader(caseData.Req))
|
||||||
var r *http.Request
|
var r *http.Request
|
||||||
|
@ -443,6 +448,9 @@ func TestServer_handleTestUpstreaDNS(t *testing.T) {
|
||||||
UDPListenAddrs: []*net.UDPAddr{{}},
|
UDPListenAddrs: []*net.UDPAddr{{}},
|
||||||
TCPListenAddrs: []*net.TCPAddr{{}},
|
TCPListenAddrs: []*net.TCPAddr{{}},
|
||||||
UpstreamTimeout: upsTimeout,
|
UpstreamTimeout: upsTimeout,
|
||||||
|
FilteringConfig: FilteringConfig{
|
||||||
|
EDNSClientSubnet: &EDNSClientSubnet{Enabled: false},
|
||||||
|
},
|
||||||
}, nil)
|
}, nil)
|
||||||
startDeferStop(t, srv)
|
startDeferStop(t, srv)
|
||||||
|
|
||||||
|
|
|
@ -71,6 +71,7 @@ var blockedServices = []blockedService{{
|
||||||
"||amazon.jp^",
|
"||amazon.jp^",
|
||||||
"||amazon.nl^",
|
"||amazon.nl^",
|
||||||
"||amazon.red^",
|
"||amazon.red^",
|
||||||
|
"||amazon.se^",
|
||||||
"||amazon.sg^",
|
"||amazon.sg^",
|
||||||
"||amazon^",
|
"||amazon^",
|
||||||
"||amazonalexavoxcon.com^",
|
"||amazonalexavoxcon.com^",
|
||||||
|
@ -1290,6 +1291,14 @@ var blockedServices = []blockedService{{
|
||||||
"||iq.com^",
|
"||iq.com^",
|
||||||
"||iqiyi.com^",
|
"||iqiyi.com^",
|
||||||
},
|
},
|
||||||
|
}, {
|
||||||
|
ID: "kakaotalk",
|
||||||
|
Name: "KakaoTalk",
|
||||||
|
IconSVG: []byte("<svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"currentColor\" viewBox=\"0 0 24 24\" ><path d=\"M22.125 0H1.875C.839 0 0 .84 0 1.875v20.25C0 23.161.84 24 1.875 24h20.25C23.161 24 24 23.16 24 22.125V1.875C24 .839 23.16 0 22.125 0zM12 18.75c-.591 0-1.17-.041-1.732-.12-.562.396-3.813 2.679-4.12 2.722 0 0-.125.049-.232-.014s-.088-.229-.088-.229c.032-.22.843-3.018.992-3.533-2.745-1.36-4.57-3.769-4.57-6.513 0-4.246 4.365-7.688 9.75-7.688s9.75 3.442 9.75 7.688c0 4.245-4.365 7.687-9.75 7.687zM8.05 9.867h-.878v3.342c0 .296-.252.537-.563.537s-.562-.24-.562-.537V9.867h-.878a.552.552 0 0 1 0-1.101h2.88a.552.552 0 0 1 0 1.101zm10.987 2.957a.558.558 0 0 1 .109.417.559.559 0 0 1-.219.37.557.557 0 0 1-.338.114.558.558 0 0 1-.45-.224l-1.319-1.747-.195.195v1.227a.564.564 0 0 1-.562.563.563.563 0 0 1-.563-.563V9.328a.563.563 0 0 1 1.125 0v1.21l1.57-1.57a.437.437 0 0 1 .311-.126c.14 0 .282.061.388.167a.555.555 0 0 1 .165.356.438.438 0 0 1-.124.343l-1.282 1.281 1.385 1.835zm-8.35-3.502c-.095-.27-.383-.548-.75-.556-.366.008-.654.286-.749.555l-1.345 3.541c-.171.53-.022.728.133.8a.857.857 0 0 0 .357.077c.235 0 .414-.095.468-.248l.279-.73h1.715l.279.73c.054.153.233.248.468.248a.86.86 0 0 0 .357-.078c.155-.071.304-.268.133-.8l-1.345-3.54zm-1.311 2.443.562-1.596.561 1.596H9.376zm5.905 1.383a.528.528 0 0 1-.539.516h-1.804a.528.528 0 0 1-.54-.516v-3.82c0-.31.258-.562.575-.562s.574.252.574.562v3.305h1.195c.297 0 .54.231.54.515z\"/></svg>"),
|
||||||
|
Rules: []string{
|
||||||
|
"||kakao.com^",
|
||||||
|
"||kgslb.com^",
|
||||||
|
},
|
||||||
}, {
|
}, {
|
||||||
ID: "leagueoflegends",
|
ID: "leagueoflegends",
|
||||||
Name: "League of Legends",
|
Name: "League of Legends",
|
||||||
|
@ -1336,13 +1345,13 @@ var blockedServices = []blockedService{{
|
||||||
"||aus.social^",
|
"||aus.social^",
|
||||||
"||awscommunity.social^",
|
"||awscommunity.social^",
|
||||||
"||cyberplace.social^",
|
"||cyberplace.social^",
|
||||||
|
"||defcon.social^",
|
||||||
"||det.social^",
|
"||det.social^",
|
||||||
"||fosstodon.org^",
|
"||fosstodon.org^",
|
||||||
"||glasgow.social^",
|
"||glasgow.social^",
|
||||||
"||h4.io^",
|
"||h4.io^",
|
||||||
"||hachyderm.io^",
|
"||hachyderm.io^",
|
||||||
"||hessen.social^",
|
"||hessen.social^",
|
||||||
"||home.social^",
|
|
||||||
"||hostux.social^",
|
"||hostux.social^",
|
||||||
"||ieji.de^",
|
"||ieji.de^",
|
||||||
"||indieweb.social^",
|
"||indieweb.social^",
|
||||||
|
|
|
@ -0,0 +1,102 @@
|
||||||
|
package home
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/AdguardTeam/dnsproxy/proxy"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Client contains information about persistent clients.
|
||||||
|
type Client struct {
|
||||||
|
// upstreamConfig is the custom upstream config for this client. If
|
||||||
|
// it's nil, it has not been initialized yet. If it's non-nil and
|
||||||
|
// empty, there are no valid upstreams. If it's non-nil and non-empty,
|
||||||
|
// these upstream must be used.
|
||||||
|
upstreamConfig *proxy.UpstreamConfig
|
||||||
|
|
||||||
|
Name string
|
||||||
|
|
||||||
|
IDs []string
|
||||||
|
Tags []string
|
||||||
|
BlockedServices []string
|
||||||
|
Upstreams []string
|
||||||
|
|
||||||
|
UseOwnSettings bool
|
||||||
|
FilteringEnabled bool
|
||||||
|
SafeSearchEnabled bool
|
||||||
|
SafeBrowsingEnabled bool
|
||||||
|
ParentalEnabled bool
|
||||||
|
UseOwnBlockedServices bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// closeUpstreams closes the client-specific upstream config of c if any.
|
||||||
|
func (c *Client) closeUpstreams() (err error) {
|
||||||
|
if c.upstreamConfig != nil {
|
||||||
|
err = c.upstreamConfig.Close()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("closing upstreams of client %q: %w", c.Name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// clientSource represents the source from which the information about the
|
||||||
|
// client has been obtained.
|
||||||
|
type clientSource uint
|
||||||
|
|
||||||
|
// Clients information sources. The order determines the priority.
|
||||||
|
const (
|
||||||
|
ClientSourceNone clientSource = iota
|
||||||
|
ClientSourceWHOIS
|
||||||
|
ClientSourceARP
|
||||||
|
ClientSourceRDNS
|
||||||
|
ClientSourceDHCP
|
||||||
|
ClientSourceHostsFile
|
||||||
|
ClientSourcePersistent
|
||||||
|
)
|
||||||
|
|
||||||
|
// type check
|
||||||
|
var _ fmt.Stringer = clientSource(0)
|
||||||
|
|
||||||
|
// String returns a human-readable name of cs.
|
||||||
|
func (cs clientSource) String() (s string) {
|
||||||
|
switch cs {
|
||||||
|
case ClientSourceWHOIS:
|
||||||
|
return "WHOIS"
|
||||||
|
case ClientSourceARP:
|
||||||
|
return "ARP"
|
||||||
|
case ClientSourceRDNS:
|
||||||
|
return "rDNS"
|
||||||
|
case ClientSourceDHCP:
|
||||||
|
return "DHCP"
|
||||||
|
case ClientSourceHostsFile:
|
||||||
|
return "etc/hosts"
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// type check
|
||||||
|
var _ encoding.TextMarshaler = clientSource(0)
|
||||||
|
|
||||||
|
// MarshalText implements encoding.TextMarshaler for the clientSource.
|
||||||
|
func (cs clientSource) MarshalText() (text []byte, err error) {
|
||||||
|
return []byte(cs.String()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RuntimeClient is a client information about which has been obtained using the
|
||||||
|
// source described in the Source field.
|
||||||
|
type RuntimeClient struct {
|
||||||
|
WHOISInfo *RuntimeClientWHOISInfo
|
||||||
|
Host string
|
||||||
|
Source clientSource
|
||||||
|
}
|
||||||
|
|
||||||
|
// RuntimeClientWHOISInfo is the filtered WHOIS data for a runtime client.
|
||||||
|
type RuntimeClientWHOISInfo struct {
|
||||||
|
City string `json:"city,omitempty"`
|
||||||
|
Country string `json:"country,omitempty"`
|
||||||
|
Orgname string `json:"orgname,omitempty"`
|
||||||
|
}
|
|
@ -2,7 +2,6 @@ package home
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
|
@ -25,122 +24,16 @@ import (
|
||||||
"golang.org/x/exp/slices"
|
"golang.org/x/exp/slices"
|
||||||
)
|
)
|
||||||
|
|
||||||
const clientsUpdatePeriod = 10 * time.Minute
|
// clientsContainer is the storage of all runtime and persistent clients.
|
||||||
|
|
||||||
var webHandlersRegistered = false
|
|
||||||
|
|
||||||
// Client contains information about persistent clients.
|
|
||||||
type Client struct {
|
|
||||||
// upstreamConfig is the custom upstream config for this client. If
|
|
||||||
// it's nil, it has not been initialized yet. If it's non-nil and
|
|
||||||
// empty, there are no valid upstreams. If it's non-nil and non-empty,
|
|
||||||
// these upstream must be used.
|
|
||||||
upstreamConfig *proxy.UpstreamConfig
|
|
||||||
|
|
||||||
Name string
|
|
||||||
|
|
||||||
IDs []string
|
|
||||||
Tags []string
|
|
||||||
BlockedServices []string
|
|
||||||
Upstreams []string
|
|
||||||
|
|
||||||
UseOwnSettings bool
|
|
||||||
FilteringEnabled bool
|
|
||||||
SafeSearchEnabled bool
|
|
||||||
SafeBrowsingEnabled bool
|
|
||||||
ParentalEnabled bool
|
|
||||||
UseOwnBlockedServices bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// closeUpstreams closes the client-specific upstream config of c if any.
|
|
||||||
func (c *Client) closeUpstreams() (err error) {
|
|
||||||
if c.upstreamConfig != nil {
|
|
||||||
err = c.upstreamConfig.Close()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("closing upstreams of client %q: %w", c.Name, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type clientSource uint
|
|
||||||
|
|
||||||
// Clients information sources. The order determines the priority.
|
|
||||||
const (
|
|
||||||
ClientSourceNone clientSource = iota
|
|
||||||
ClientSourceWHOIS
|
|
||||||
ClientSourceARP
|
|
||||||
ClientSourceRDNS
|
|
||||||
ClientSourceDHCP
|
|
||||||
ClientSourceHostsFile
|
|
||||||
ClientSourcePersistent
|
|
||||||
)
|
|
||||||
|
|
||||||
// type check
|
|
||||||
var _ fmt.Stringer = clientSource(0)
|
|
||||||
|
|
||||||
// String returns a human-readable name of cs.
|
|
||||||
func (cs clientSource) String() (s string) {
|
|
||||||
switch cs {
|
|
||||||
case ClientSourceWHOIS:
|
|
||||||
return "WHOIS"
|
|
||||||
case ClientSourceARP:
|
|
||||||
return "ARP"
|
|
||||||
case ClientSourceRDNS:
|
|
||||||
return "rDNS"
|
|
||||||
case ClientSourceDHCP:
|
|
||||||
return "DHCP"
|
|
||||||
case ClientSourceHostsFile:
|
|
||||||
return "etc/hosts"
|
|
||||||
default:
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// type check
|
|
||||||
var _ encoding.TextMarshaler = clientSource(0)
|
|
||||||
|
|
||||||
// MarshalText implements encoding.TextMarshaler for the clientSource.
|
|
||||||
func (cs clientSource) MarshalText() (text []byte, err error) {
|
|
||||||
return []byte(cs.String()), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// clientSourceConf is used to configure where the runtime clients will be
|
|
||||||
// obtained from.
|
|
||||||
type clientSourcesConf struct {
|
|
||||||
WHOIS bool `yaml:"whois"`
|
|
||||||
ARP bool `yaml:"arp"`
|
|
||||||
RDNS bool `yaml:"rdns"`
|
|
||||||
DHCP bool `yaml:"dhcp"`
|
|
||||||
HostsFile bool `yaml:"hosts"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// RuntimeClient information
|
|
||||||
type RuntimeClient struct {
|
|
||||||
WHOISInfo *RuntimeClientWHOISInfo
|
|
||||||
Host string
|
|
||||||
Source clientSource
|
|
||||||
}
|
|
||||||
|
|
||||||
// RuntimeClientWHOISInfo is the filtered WHOIS data for a runtime client.
|
|
||||||
type RuntimeClientWHOISInfo struct {
|
|
||||||
City string `json:"city,omitempty"`
|
|
||||||
Country string `json:"country,omitempty"`
|
|
||||||
Orgname string `json:"orgname,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type clientsContainer struct {
|
type clientsContainer struct {
|
||||||
// TODO(a.garipov): Perhaps use a number of separate indices for
|
// TODO(a.garipov): Perhaps use a number of separate indices for different
|
||||||
// different types (string, netip.Addr, and so on).
|
// types (string, netip.Addr, and so on).
|
||||||
list map[string]*Client // name -> client
|
list map[string]*Client // name -> client
|
||||||
idIndex map[string]*Client // ID -> client
|
idIndex map[string]*Client // ID -> client
|
||||||
|
|
||||||
// ipToRC is the IP address to *RuntimeClient map.
|
// ipToRC is the IP address to *RuntimeClient map.
|
||||||
ipToRC map[netip.Addr]*RuntimeClient
|
ipToRC map[netip.Addr]*RuntimeClient
|
||||||
|
|
||||||
lock sync.Mutex
|
|
||||||
|
|
||||||
allTags *stringutil.Set
|
allTags *stringutil.Set
|
||||||
|
|
||||||
// dhcpServer is used for looking up clients IP addresses by MAC addresses
|
// dhcpServer is used for looking up clients IP addresses by MAC addresses
|
||||||
|
@ -156,7 +49,16 @@ type clientsContainer struct {
|
||||||
// arpdb stores the neighbors retrieved from ARP.
|
// arpdb stores the neighbors retrieved from ARP.
|
||||||
arpdb aghnet.ARPDB
|
arpdb aghnet.ARPDB
|
||||||
|
|
||||||
testing bool // if TRUE, this object is used for internal tests
|
// lock protects all fields.
|
||||||
|
//
|
||||||
|
// TODO(a.garipov): Use a pointer and describe which fields are protected in
|
||||||
|
// more detail.
|
||||||
|
lock sync.Mutex
|
||||||
|
|
||||||
|
// testing is a flag that disables some features for internal tests.
|
||||||
|
//
|
||||||
|
// TODO(a.garipov): Awful. Remove.
|
||||||
|
testing bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init initializes clients container
|
// Init initializes clients container
|
||||||
|
@ -202,24 +104,34 @@ func (clients *clientsContainer) handleHostsUpdates() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start - start the module
|
// webHandlersRegistered prevents a [clientsContainer] from regisering its web
|
||||||
|
// handlers more than once.
|
||||||
|
//
|
||||||
|
// TODO(a.garipov): Refactor HTTP handler registration logic.
|
||||||
|
var webHandlersRegistered = false
|
||||||
|
|
||||||
|
// Start starts the clients container.
|
||||||
func (clients *clientsContainer) Start() {
|
func (clients *clientsContainer) Start() {
|
||||||
if !clients.testing {
|
if clients.testing {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if !webHandlersRegistered {
|
if !webHandlersRegistered {
|
||||||
webHandlersRegistered = true
|
webHandlersRegistered = true
|
||||||
clients.registerWebHandlers()
|
clients.registerWebHandlers()
|
||||||
}
|
}
|
||||||
|
|
||||||
go clients.periodicUpdate()
|
go clients.periodicUpdate()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reload reloads runtime clients.
|
// reloadARP reloads runtime clients from ARP, if configured.
|
||||||
func (clients *clientsContainer) Reload() {
|
func (clients *clientsContainer) reloadARP() {
|
||||||
if clients.arpdb != nil {
|
if clients.arpdb != nil {
|
||||||
clients.addFromSystemARP()
|
clients.addFromSystemARP()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// clientObject is the YAML representation of a persistent client.
|
||||||
type clientObject struct {
|
type clientObject struct {
|
||||||
Name string `yaml:"name"`
|
Name string `yaml:"name"`
|
||||||
|
|
||||||
|
@ -317,12 +229,15 @@ func (clients *clientsContainer) forConfig() (objs []*clientObject) {
|
||||||
return objs
|
return objs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// arpClientsUpdatePeriod defines how often ARP clients are updated.
|
||||||
|
const arpClientsUpdatePeriod = 10 * time.Minute
|
||||||
|
|
||||||
func (clients *clientsContainer) periodicUpdate() {
|
func (clients *clientsContainer) periodicUpdate() {
|
||||||
defer log.OnPanic("clients container")
|
defer log.OnPanic("clients container")
|
||||||
|
|
||||||
for {
|
for {
|
||||||
clients.Reload()
|
clients.reloadARP()
|
||||||
time.Sleep(clientsUpdatePeriod)
|
time.Sleep(arpClientsUpdatePeriod)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -485,7 +400,8 @@ func (clients *clientsContainer) findUpstreams(
|
||||||
return conf, nil
|
return conf, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// findLocked searches for a client by its ID. For internal use only.
|
// findLocked searches for a client by its ID. clients.lock is expected to be
|
||||||
|
// locked.
|
||||||
func (clients *clientsContainer) findLocked(id string) (c *Client, ok bool) {
|
func (clients *clientsContainer) findLocked(id string) (c *Client, ok bool) {
|
||||||
c, ok = clients.idIndex[id]
|
c, ok = clients.idIndex[id]
|
||||||
if ok {
|
if ok {
|
||||||
|
@ -499,13 +415,13 @@ func (clients *clientsContainer) findLocked(id string) (c *Client, ok bool) {
|
||||||
|
|
||||||
for _, c = range clients.list {
|
for _, c = range clients.list {
|
||||||
for _, id := range c.IDs {
|
for _, id := range c.IDs {
|
||||||
var n netip.Prefix
|
var subnet netip.Prefix
|
||||||
n, err = netip.ParsePrefix(id)
|
subnet, err = netip.ParsePrefix(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if n.Contains(ip) {
|
if subnet.Contains(ip) {
|
||||||
return c, true
|
return c, true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -515,20 +431,25 @@ func (clients *clientsContainer) findLocked(id string) (c *Client, ok bool) {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
macFound := clients.dhcpServer.FindMACbyIP(ip.AsSlice())
|
return clients.findDHCP(ip)
|
||||||
if macFound == nil {
|
}
|
||||||
|
|
||||||
|
// findDHCP searches for a client by its MAC, if the DHCP server is active and
|
||||||
|
// there is such client. clients.lock is expected to be locked.
|
||||||
|
func (clients *clientsContainer) findDHCP(ip netip.Addr) (c *Client, ok bool) {
|
||||||
|
foundMAC := clients.dhcpServer.FindMACbyIP(ip)
|
||||||
|
if foundMAC == nil {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, c = range clients.list {
|
for _, c = range clients.list {
|
||||||
for _, id := range c.IDs {
|
for _, id := range c.IDs {
|
||||||
var mac net.HardwareAddr
|
mac, err := net.ParseMAC(id)
|
||||||
mac, err = net.ParseMAC(id)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if bytes.Equal(mac, macFound) {
|
if bytes.Equal(mac, foundMAC) {
|
||||||
return c, true
|
return c, true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -565,24 +486,13 @@ func (clients *clientsContainer) check(c *Client) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, id := range c.IDs {
|
for i, id := range c.IDs {
|
||||||
// Normalize structured data.
|
var norm string
|
||||||
var (
|
norm, err = normalizeClientIdentifier(id)
|
||||||
ip netip.Addr
|
if err != nil {
|
||||||
n netip.Prefix
|
return fmt.Errorf("client at index %d: %w", i, err)
|
||||||
mac net.HardwareAddr
|
|
||||||
)
|
|
||||||
|
|
||||||
if ip, err = netip.ParseAddr(id); err == nil {
|
|
||||||
c.IDs[i] = ip.String()
|
|
||||||
} else if n, err = netip.ParsePrefix(id); err == nil {
|
|
||||||
c.IDs[i] = n.String()
|
|
||||||
} else if mac, err = net.ParseMAC(id); err == nil {
|
|
||||||
c.IDs[i] = mac.String()
|
|
||||||
} else if err = dnsforward.ValidateClientID(id); err == nil {
|
|
||||||
c.IDs[i] = strings.ToLower(id)
|
|
||||||
} else {
|
|
||||||
return fmt.Errorf("invalid clientid at index %d: %q", i, id)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c.IDs[i] = norm
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, t := range c.Tags {
|
for _, t := range c.Tags {
|
||||||
|
@ -601,6 +511,35 @@ func (clients *clientsContainer) check(c *Client) (err error) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// normalizeClientIdentifier returns a normalized version of idStr. If idStr
|
||||||
|
// cannot be normalized, it returns an error.
|
||||||
|
func normalizeClientIdentifier(idStr string) (norm string, err error) {
|
||||||
|
if idStr == "" {
|
||||||
|
return "", errors.Error("clientid is empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
var ip netip.Addr
|
||||||
|
if ip, err = netip.ParseAddr(idStr); err == nil {
|
||||||
|
return ip.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var subnet netip.Prefix
|
||||||
|
if subnet, err = netip.ParsePrefix(idStr); err == nil {
|
||||||
|
return subnet.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var mac net.HardwareAddr
|
||||||
|
if mac, err = net.ParseMAC(idStr); err == nil {
|
||||||
|
return mac.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = dnsforward.ValidateClientID(idStr); err == nil {
|
||||||
|
return strings.ToLower(idStr), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", fmt.Errorf("bad client identifier %q", idStr)
|
||||||
|
}
|
||||||
|
|
||||||
// Add adds a new client object. ok is false if such client already exists or
|
// Add adds a new client object. ok is false if such client already exists or
|
||||||
// if an error occurred.
|
// if an error occurred.
|
||||||
func (clients *clientsContainer) Add(c *Client) (ok bool, err error) {
|
func (clients *clientsContainer) Add(c *Client) (ok bool, err error) {
|
||||||
|
@ -666,21 +605,6 @@ func (clients *clientsContainer) Del(name string) (ok bool) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// equalStringSlices returns true if the slices are equal.
|
|
||||||
func equalStringSlices(a, b []string) (ok bool) {
|
|
||||||
if len(a) != len(b) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := range a {
|
|
||||||
if a[i] != b[i] {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update updates a client by its name.
|
// Update updates a client by its name.
|
||||||
func (clients *clientsContainer) Update(name string, c *Client) (err error) {
|
func (clients *clientsContainer) Update(name string, c *Client) (err error) {
|
||||||
err = clients.check(c)
|
err = clients.check(c)
|
||||||
|
@ -704,22 +628,11 @@ func (clients *clientsContainer) Update(name string, c *Client) (err error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Second, check the IP index.
|
// Second, update the ID index.
|
||||||
if !equalStringSlices(prev.IDs, c.IDs) {
|
err = clients.updateIDIndex(prev, c.IDs)
|
||||||
for _, id := range c.IDs {
|
if err != nil {
|
||||||
c2, ok2 := clients.idIndex[id]
|
// Don't wrap the error, because it's informative enough as is.
|
||||||
if ok2 && c2 != prev {
|
return err
|
||||||
return fmt.Errorf("another client uses the same id (%q): %q", id, c2.Name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update ID index.
|
|
||||||
for _, id := range prev.IDs {
|
|
||||||
delete(clients.idIndex, id)
|
|
||||||
}
|
|
||||||
for _, id := range c.IDs {
|
|
||||||
clients.idIndex[id] = prev
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update name index.
|
// Update name index.
|
||||||
|
@ -739,6 +652,32 @@ func (clients *clientsContainer) Update(name string, c *Client) (err error) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// updateIDIndex updates the ID index data for cli using the information from
|
||||||
|
// newIDs.
|
||||||
|
func (clients *clientsContainer) updateIDIndex(cli *Client, newIDs []string) (err error) {
|
||||||
|
if slices.Equal(cli.IDs, newIDs) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, id := range newIDs {
|
||||||
|
existing, ok := clients.idIndex[id]
|
||||||
|
if ok && existing != cli {
|
||||||
|
return fmt.Errorf("id %q is used by client with name %q", id, existing.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the IDs in the index.
|
||||||
|
for _, id := range cli.IDs {
|
||||||
|
delete(clients.idIndex, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, id := range newIDs {
|
||||||
|
clients.idIndex[id] = cli
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// setWHOISInfo sets the WHOIS information for a client.
|
// setWHOISInfo sets the WHOIS information for a client.
|
||||||
func (clients *clientsContainer) setWHOISInfo(ip netip.Addr, wi *RuntimeClientWHOISInfo) {
|
func (clients *clientsContainer) setWHOISInfo(ip netip.Addr, wi *RuntimeClientWHOISInfo) {
|
||||||
clients.lock.Lock()
|
clients.lock.Lock()
|
||||||
|
|
|
@ -75,11 +75,21 @@ type osConfig struct {
|
||||||
|
|
||||||
type clientsConfig struct {
|
type clientsConfig struct {
|
||||||
// Sources defines the set of sources to fetch the runtime clients from.
|
// Sources defines the set of sources to fetch the runtime clients from.
|
||||||
Sources *clientSourcesConf `yaml:"runtime_sources"`
|
Sources *clientSourcesConfig `yaml:"runtime_sources"`
|
||||||
// Persistent are the configured clients.
|
// Persistent are the configured clients.
|
||||||
Persistent []*clientObject `yaml:"persistent"`
|
Persistent []*clientObject `yaml:"persistent"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// clientSourceConfig is used to configure where the runtime clients will be
|
||||||
|
// obtained from.
|
||||||
|
type clientSourcesConfig struct {
|
||||||
|
WHOIS bool `yaml:"whois"`
|
||||||
|
ARP bool `yaml:"arp"`
|
||||||
|
RDNS bool `yaml:"rdns"`
|
||||||
|
DHCP bool `yaml:"dhcp"`
|
||||||
|
HostsFile bool `yaml:"hosts"`
|
||||||
|
}
|
||||||
|
|
||||||
// configuration is loaded from YAML
|
// configuration is loaded from YAML
|
||||||
// field ordering is important -- yaml fields will mirror ordering from here
|
// field ordering is important -- yaml fields will mirror ordering from here
|
||||||
type configuration struct {
|
type configuration struct {
|
||||||
|
@ -334,7 +344,7 @@ var config = &configuration{
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Clients: &clientsConfig{
|
Clients: &clientsConfig{
|
||||||
Sources: &clientSourcesConf{
|
Sources: &clientSourcesConfig{
|
||||||
WHOIS: true,
|
WHOIS: true,
|
||||||
ARP: true,
|
ARP: true,
|
||||||
RDNS: true,
|
RDNS: true,
|
||||||
|
|
|
@ -125,7 +125,7 @@ func Main(clientBuildFS fs.FS) {
|
||||||
log.Info("Received signal %q", sig)
|
log.Info("Received signal %q", sig)
|
||||||
switch sig {
|
switch sig {
|
||||||
case syscall.SIGHUP:
|
case syscall.SIGHUP:
|
||||||
Context.clients.Reload()
|
Context.clients.reloadARP()
|
||||||
Context.tls.reload()
|
Context.tls.reload()
|
||||||
default:
|
default:
|
||||||
cleanup(context.Background())
|
cleanup(context.Background())
|
||||||
|
|
|
@ -90,6 +90,7 @@ func upgradeConfigSchema(oldVersion int, diskConf yobj) (err error) {
|
||||||
upgradeSchema14to15,
|
upgradeSchema14to15,
|
||||||
upgradeSchema15to16,
|
upgradeSchema15to16,
|
||||||
upgradeSchema16to17,
|
upgradeSchema16to17,
|
||||||
|
upgradeSchema17to18,
|
||||||
}
|
}
|
||||||
|
|
||||||
n := 0
|
n := 0
|
||||||
|
@ -793,7 +794,7 @@ func upgradeSchema13to14(diskConf yobj) (err error) {
|
||||||
|
|
||||||
diskConf["clients"] = yobj{
|
diskConf["clients"] = yobj{
|
||||||
"persistent": clientsVal,
|
"persistent": clientsVal,
|
||||||
"runtime_sources": &clientSourcesConf{
|
"runtime_sources": &clientSourcesConfig{
|
||||||
WHOIS: true,
|
WHOIS: true,
|
||||||
ARP: true,
|
ARP: true,
|
||||||
RDNS: rdnsSrc,
|
RDNS: rdnsSrc,
|
||||||
|
@ -893,13 +894,13 @@ func upgradeSchema15to16(diskConf yobj) (err error) {
|
||||||
"ignored": []any{},
|
"ignored": []any{},
|
||||||
}
|
}
|
||||||
|
|
||||||
k := "statistics_interval"
|
const field = "statistics_interval"
|
||||||
v, has := dns[k]
|
v, has := dns[field]
|
||||||
if has {
|
if has {
|
||||||
stats["enabled"] = v != 0
|
stats["enabled"] = v != 0
|
||||||
stats["interval"] = v
|
stats["interval"] = v
|
||||||
}
|
}
|
||||||
delete(dns, k)
|
delete(dns, field)
|
||||||
|
|
||||||
diskConf["statistics"] = stats
|
diskConf["statistics"] = stats
|
||||||
|
|
||||||
|
@ -909,15 +910,52 @@ func upgradeSchema15to16(diskConf yobj) (err error) {
|
||||||
// upgradeSchema16to17 performs the following changes:
|
// upgradeSchema16to17 performs the following changes:
|
||||||
//
|
//
|
||||||
// # BEFORE:
|
// # BEFORE:
|
||||||
|
// 'dns':
|
||||||
|
// 'edns_client_subnet': false
|
||||||
|
//
|
||||||
|
// # AFTER:
|
||||||
|
// 'dns':
|
||||||
|
// 'edns_client_subnet':
|
||||||
|
// 'enabled': false
|
||||||
|
// 'use_custom': false
|
||||||
|
// 'custom_ip': ""
|
||||||
|
func upgradeSchema16to17(diskConf yobj) (err error) {
|
||||||
|
log.Printf("Upgrade yaml: 16 to 17")
|
||||||
|
diskConf["schema_version"] = 17
|
||||||
|
|
||||||
|
dnsVal, ok := diskConf["dns"]
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
dns, ok := dnsVal.(yobj)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("unexpected type of dns: %T", dnsVal)
|
||||||
|
}
|
||||||
|
|
||||||
|
const field = "edns_client_subnet"
|
||||||
|
|
||||||
|
dns[field] = map[string]any{
|
||||||
|
"enabled": dns[field] == true,
|
||||||
|
"use_custom": false,
|
||||||
|
"custom_ip": "",
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// upgradeSchema17to18 performs the following changes:
|
||||||
|
//
|
||||||
|
// # BEFORE:
|
||||||
// 'statistics':
|
// 'statistics':
|
||||||
// 'interval': 1
|
// 'interval': 1
|
||||||
//
|
//
|
||||||
// # AFTER:
|
// # AFTER:
|
||||||
// 'statistics':
|
// 'statistics':
|
||||||
// 'interval': 24h
|
// 'interval': 24h
|
||||||
func upgradeSchema16to17(diskConf yobj) (err error) {
|
func upgradeSchema17to18(diskConf yobj) (err error) {
|
||||||
log.Printf("Upgrade yaml: 16 to 17")
|
log.Printf("Upgrade yaml: 17 to 18")
|
||||||
diskConf["schema_version"] = 17
|
diskConf["schema_version"] = 18
|
||||||
|
|
||||||
statsVal, ok := diskConf["statistics"]
|
statsVal, ok := diskConf["statistics"]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|
|
@ -579,7 +579,7 @@ func TestUpgradeSchema13to14(t *testing.T) {
|
||||||
// The clients field will be added anyway.
|
// The clients field will be added anyway.
|
||||||
"clients": yobj{
|
"clients": yobj{
|
||||||
"persistent": yarr{},
|
"persistent": yarr{},
|
||||||
"runtime_sources": &clientSourcesConf{
|
"runtime_sources": &clientSourcesConfig{
|
||||||
WHOIS: true,
|
WHOIS: true,
|
||||||
ARP: true,
|
ARP: true,
|
||||||
RDNS: false,
|
RDNS: false,
|
||||||
|
@ -597,7 +597,7 @@ func TestUpgradeSchema13to14(t *testing.T) {
|
||||||
"schema_version": newSchemaVer,
|
"schema_version": newSchemaVer,
|
||||||
"clients": yobj{
|
"clients": yobj{
|
||||||
"persistent": []*clientObject{testClient},
|
"persistent": []*clientObject{testClient},
|
||||||
"runtime_sources": &clientSourcesConf{
|
"runtime_sources": &clientSourcesConfig{
|
||||||
WHOIS: true,
|
WHOIS: true,
|
||||||
ARP: true,
|
ARP: true,
|
||||||
RDNS: false,
|
RDNS: false,
|
||||||
|
@ -618,7 +618,7 @@ func TestUpgradeSchema13to14(t *testing.T) {
|
||||||
"schema_version": newSchemaVer,
|
"schema_version": newSchemaVer,
|
||||||
"clients": yobj{
|
"clients": yobj{
|
||||||
"persistent": []*clientObject{testClient},
|
"persistent": []*clientObject{testClient},
|
||||||
"runtime_sources": &clientSourcesConf{
|
"runtime_sources": &clientSourcesConfig{
|
||||||
WHOIS: true,
|
WHOIS: true,
|
||||||
ARP: true,
|
ARP: true,
|
||||||
RDNS: true,
|
RDNS: true,
|
||||||
|
@ -749,6 +749,67 @@ func TestUpgradeSchema15to16(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUpgradeSchema16to17(t *testing.T) {
|
func TestUpgradeSchema16to17(t *testing.T) {
|
||||||
|
const newSchemaVer = 17
|
||||||
|
|
||||||
|
defaultWantObj := yobj{
|
||||||
|
"dns": map[string]any{
|
||||||
|
"edns_client_subnet": map[string]any{
|
||||||
|
"enabled": false,
|
||||||
|
"use_custom": false,
|
||||||
|
"custom_ip": "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"schema_version": newSchemaVer,
|
||||||
|
}
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
in yobj
|
||||||
|
want yobj
|
||||||
|
name string
|
||||||
|
}{{
|
||||||
|
in: yobj{
|
||||||
|
"dns": map[string]any{
|
||||||
|
"edns_client_subnet": false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: defaultWantObj,
|
||||||
|
name: "basic",
|
||||||
|
}, {
|
||||||
|
in: yobj{
|
||||||
|
"dns": map[string]any{},
|
||||||
|
},
|
||||||
|
want: defaultWantObj,
|
||||||
|
name: "default_values",
|
||||||
|
}, {
|
||||||
|
in: yobj{
|
||||||
|
"dns": map[string]any{
|
||||||
|
"edns_client_subnet": true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: yobj{
|
||||||
|
"dns": map[string]any{
|
||||||
|
"edns_client_subnet": map[string]any{
|
||||||
|
"enabled": true,
|
||||||
|
"use_custom": false,
|
||||||
|
"custom_ip": "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"schema_version": newSchemaVer,
|
||||||
|
},
|
||||||
|
name: "is_true",
|
||||||
|
}}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
err := upgradeSchema16to17(tc.in)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, tc.want, tc.in)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpgradeSchema17to18(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
ivl any
|
ivl any
|
||||||
want any
|
want any
|
||||||
|
@ -771,10 +832,10 @@ func TestUpgradeSchema16to17(t *testing.T) {
|
||||||
"statistics": yobj{
|
"statistics": yobj{
|
||||||
"interval": tc.ivl,
|
"interval": tc.ivl,
|
||||||
},
|
},
|
||||||
"schema_version": 16,
|
"schema_version": 17,
|
||||||
}
|
}
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
err := upgradeSchema16to17(conf)
|
err := upgradeSchema17to18(conf)
|
||||||
|
|
||||||
if tc.wantErr != "" {
|
if tc.wantErr != "" {
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
|
@ -785,7 +846,7 @@ func TestUpgradeSchema16to17(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, conf["schema_version"], 17)
|
require.Equal(t, conf["schema_version"], 18)
|
||||||
|
|
||||||
statsVal, ok := conf["statistics"]
|
statsVal, ok := conf["statistics"]
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
|
@ -803,13 +864,13 @@ func TestUpgradeSchema16to17(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Run("no_stats", func(t *testing.T) {
|
t.Run("no_stats", func(t *testing.T) {
|
||||||
err := upgradeSchema16to17(yobj{})
|
err := upgradeSchema17to18(yobj{})
|
||||||
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("bad_stats", func(t *testing.T) {
|
t.Run("bad_stats", func(t *testing.T) {
|
||||||
err := upgradeSchema16to17(yobj{
|
err := upgradeSchema17to18(yobj{
|
||||||
"statistics": 0,
|
"statistics": 0,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -821,7 +882,7 @@ func TestUpgradeSchema16to17(t *testing.T) {
|
||||||
"statistics": yobj{},
|
"statistics": yobj{},
|
||||||
}
|
}
|
||||||
|
|
||||||
err := upgradeSchema16to17(conf)
|
err := upgradeSchema17to18(conf)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
statsVal, ok := conf["statistics"]
|
statsVal, ok := conf["statistics"]
|
||||||
|
|
|
@ -315,7 +315,7 @@ func (u *Updater) clean() {
|
||||||
// MaxPackageFileSize is a maximum package file length in bytes. The largest
|
// MaxPackageFileSize is a maximum package file length in bytes. The largest
|
||||||
// package whose size is limited by this constant currently has the size of
|
// package whose size is limited by this constant currently has the size of
|
||||||
// approximately 9 MiB.
|
// approximately 9 MiB.
|
||||||
const MaxPackageFileSize = 32 * 10 * 1024
|
const MaxPackageFileSize = 32 * 1024 * 1024
|
||||||
|
|
||||||
// Download package file and save it to disk
|
// Download package file and save it to disk
|
||||||
func (u *Updater) downloadPackageFile() (err error) {
|
func (u *Updater) downloadPackageFile() (err error) {
|
||||||
|
|
Loading…
Reference in New Issue