mirror of
https://github.com/AdguardTeam/AdGuardHome.git
synced 2025-10-26 11:27:18 +00:00
Merge branch 'master' into AGDNS-3224-aghhttp-slog
This commit is contained in:
commit
e2ed1fef7f
40
CHANGELOG.md
40
CHANGELOG.md
@ -9,17 +9,29 @@ The format is based on [*Keep a Changelog*](https://keepachangelog.com/en/1.0.0/
|
||||
<!--
|
||||
## [v0.108.0] – TBA
|
||||
|
||||
## [v0.107.67] - 2025-09-25 (APPROX.)
|
||||
## [v0.107.68] - 2025-10-14 (APPROX.)
|
||||
|
||||
See also the [v0.107.67 GitHub milestone][ms-v0.107.67].
|
||||
See also the [v0.107.68 GitHub milestone][ms-v0.107.68].
|
||||
|
||||
[ms-v0.107.67]: https://github.com/AdguardTeam/AdGuardHome/milestone/102?closed=1
|
||||
[ms-v0.107.68]: https://github.com/AdguardTeam/AdGuardHome/milestone/103?closed=1
|
||||
|
||||
NOTE: Add new changes BELOW THIS COMMENT.
|
||||
-->
|
||||
### Added
|
||||
|
||||
- New fields `"groups"` and `"group_id"` added to the HTTP API (`GET /control/blocked_services/all`). See `openapi/openapi.yaml` for the full description.
|
||||
|
||||
<!--
|
||||
NOTE: Add new changes ABOVE THIS COMMENT.
|
||||
-->
|
||||
|
||||
## [v0.107.67] - 2025-09-29
|
||||
|
||||
See also the [v0.107.67 GitHub milestone][ms-v0.107.67].
|
||||
|
||||
### Added
|
||||
|
||||
- The *HaGeZi's DNS Rebind Protection* filter for protecting against DNS rebinding attacks ([#102]).
|
||||
- Support for configuring the suggested default HTTP port for the installation wizard via the `ADGUARD_HOME_DEFAULT_WEB_PORT` environment variable (useful for vendors).
|
||||
|
||||
### Changed
|
||||
@ -31,11 +43,10 @@ NOTE: Add new changes BELOW THIS COMMENT.
|
||||
- Excessive configuration file overwrites when visiting the Web UI and a non-empty `language` is set.
|
||||
- Lowered the severity of log messages for failed deletion of old filter files ([#7964]).
|
||||
|
||||
[#102]: https://github.com/AdguardTeam/AdGuardHome/issues/102
|
||||
[#7964]: https://github.com/AdguardTeam/AdGuardHome/issues/7964
|
||||
|
||||
<!--
|
||||
NOTE: Add new changes ABOVE THIS COMMENT.
|
||||
-->
|
||||
[ms-v0.107.67]: https://github.com/AdguardTeam/AdGuardHome/milestone/102?closed=1
|
||||
|
||||
## [v0.107.66] - 2025-09-15
|
||||
|
||||
@ -60,7 +71,7 @@ See also the [v0.107.66 GitHub milestone][ms-v0.107.66].
|
||||
[#7985]: https://github.com/AdguardTeam/AdGuardHome/issues/7985
|
||||
[#7987]: https://github.com/AdguardTeam/AdGuardHome/issues/7987
|
||||
|
||||
[go-1.25.1]: https://groups.google.com/g/golang-announce/c/PtW9VW21NPs
|
||||
[go-1.25.1]: https://groups.google.com/g/golang-announce/c/PtW9VW21NPs
|
||||
[ms-v0.107.66]: https://github.com/AdguardTeam/AdGuardHome/milestone/101?closed=1
|
||||
|
||||
## [v0.107.65] - 2025-08-20
|
||||
@ -106,7 +117,7 @@ In this release, the schema version has changed from 29 to 30.
|
||||
|
||||
[#7923]: https://github.com/AdguardTeam/AdGuardHome/issues/7923
|
||||
|
||||
[go-1.24.6]: https://groups.google.com/g/golang-announce/c/x5MKroML2yM
|
||||
[go-1.24.6]: https://groups.google.com/g/golang-announce/c/x5MKroML2yM
|
||||
[ms-v0.107.65]: https://github.com/AdguardTeam/AdGuardHome/milestone/100?closed=1
|
||||
|
||||
## [v0.107.64] - 2025-07-28
|
||||
@ -125,7 +136,7 @@ See also the [v0.107.64 GitHub milestone][ms-v0.107.64].
|
||||
[#7856]: https://github.com/AdguardTeam/AdGuardHome/issues/7856
|
||||
[#7903]: https://github.com/AdguardTeam/AdGuardHome/issues/7903
|
||||
|
||||
[go-1.24.5]: https://groups.google.com/g/golang-announce/c/gTNJnDXmn34
|
||||
[go-1.24.5]: https://groups.google.com/g/golang-announce/c/gTNJnDXmn34
|
||||
[ms-v0.107.64]: https://github.com/AdguardTeam/AdGuardHome/milestone/99?closed=1
|
||||
|
||||
## [v0.107.63] - 2025-06-26
|
||||
@ -142,7 +153,7 @@ See also the [v0.107.63 GitHub milestone][ms-v0.107.63].
|
||||
|
||||
- Status reported by the systemd service implementation in cases of auto-restart after a failed start.
|
||||
|
||||
[go-1.24.4]: https://groups.google.com/g/golang-announce/c/ufZ8WpEsA3A
|
||||
[go-1.24.4]: https://groups.google.com/g/golang-announce/c/ufZ8WpEsA3A
|
||||
[ms-v0.107.63]: https://github.com/AdguardTeam/AdGuardHome/milestone/98?closed=1
|
||||
|
||||
## [v0.107.62] - 2025-05-27
|
||||
@ -168,7 +179,7 @@ See also the [v0.107.62 GitHub milestone][ms-v0.107.62].
|
||||
[#2945]: https://github.com/AdguardTeam/AdGuardHome/issues/2945
|
||||
[#7801]: https://github.com/AdguardTeam/AdGuardHome/issues/7801
|
||||
|
||||
[go-1.24.3]: https://groups.google.com/g/golang-announce/c/UZoIkUT367A
|
||||
[go-1.24.3]: https://groups.google.com/g/golang-announce/c/UZoIkUT367A
|
||||
[ms-v0.107.62]: https://github.com/AdguardTeam/AdGuardHome/milestone/97?closed=1
|
||||
|
||||
## [v0.107.61] - 2025-04-22
|
||||
@ -3265,11 +3276,12 @@ See also the [v0.104.2 GitHub milestone][ms-v0.104.2].
|
||||
[ms-v0.104.2]: https://github.com/AdguardTeam/AdGuardHome/milestone/28?closed=1
|
||||
|
||||
<!--
|
||||
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.67...HEAD
|
||||
[v0.107.67]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.66...v0.107.67
|
||||
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.68...HEAD
|
||||
[v0.107.68]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.67...v0.107.68
|
||||
-->
|
||||
|
||||
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.66...HEAD
|
||||
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.67...HEAD
|
||||
[v0.107.67]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.66...v0.107.67
|
||||
[v0.107.66]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.65...v0.107.66
|
||||
[v0.107.65]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.64...v0.107.65
|
||||
[v0.107.64]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.63...v0.107.64
|
||||
|
||||
@ -156,7 +156,7 @@
|
||||
"enforce_safe_search": "Узмацніць бяспечны пошук",
|
||||
"enforce_save_search_hint": "AdGuard Home можа забяспечыць бяспечны пошук у наступных пошукавых сістэмах: Google, Youtube, Bing, DuckDuckGo, Yandex і Pixabay.",
|
||||
"no_servers_specified": "Не паказаных сервераў",
|
||||
"general_settings": "Асноўныя налады",
|
||||
"general_settings": "Агульныя налады",
|
||||
"dns_settings": "Налады DNS",
|
||||
"dns_blocklists": "Чорныя спісы DNS",
|
||||
"dns_allowlists": "Белыя спісы DNS",
|
||||
|
||||
@ -643,7 +643,7 @@
|
||||
"dnssec_enable_desc": "Установите флаг DNSSEC в исходящих DNS-запросах и проверьте результат (требуется резолвер с поддержкой DNSSEC).",
|
||||
"validated_with_dnssec": "Подтверждено с помощью DNSSEC",
|
||||
"all_queries": "Все запросы",
|
||||
"show_blocked_responses": "Заблокировано",
|
||||
"show_blocked_responses": "Заблокирован",
|
||||
"show_whitelisted_responses": "Разрешённые",
|
||||
"show_processed_responses": "Обработан",
|
||||
"blocked_safebrowsing": "Заблокировано согласно базе данных Safe Browsing",
|
||||
@ -651,7 +651,7 @@
|
||||
"blocked_threats": "Заблокировано угроз",
|
||||
"allowed": "Разрешённые",
|
||||
"filtered": "Отфильтрованные",
|
||||
"rewritten": "Переписанные",
|
||||
"rewritten": "Перезаписан",
|
||||
"safe_search": "Безопасный поиск",
|
||||
"blocklist": "Чёрный список",
|
||||
"milliseconds_abbreviation": "мс",
|
||||
|
||||
@ -655,7 +655,10 @@
|
||||
"safe_search": "Безпечний пошук",
|
||||
"blocklist": "Список блокування",
|
||||
"milliseconds_abbreviation": "мс",
|
||||
"cache_enabled": "Увімкнути кеш",
|
||||
"cache_enabled_desc": "Зберігати відповіді DNS локально.",
|
||||
"cache_size": "Розмір кешу",
|
||||
"cache_size_validation": "Розмір кешу має бути більшим за нуль, коли цю функцію увімкнуто.",
|
||||
"cache_size_desc": "Розмір кешу DNS (в байтах). Щоб вимкнути кешування, встановіть 0.",
|
||||
"cache_ttl_min_override": "Змінити мінімальний TTL",
|
||||
"cache_ttl_max_override": "Змінити максимальний TTL",
|
||||
|
||||
@ -214,6 +214,12 @@ export default {
|
||||
"homepage": "https://github.com/hagezi/dns-blocklists",
|
||||
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_55.txt"
|
||||
},
|
||||
"hagezi_dns_rebind_protection": {
|
||||
"name": "HaGeZi's DNS Rebind Protection",
|
||||
"categoryId": "security",
|
||||
"homepage": "https://github.com/hagezi/dns-blocklists",
|
||||
"source": "https://adguardteam.github.io/HostlistsRegistry/assets/filter_71.txt"
|
||||
},
|
||||
"hagezi_dyndns_blocklist": {
|
||||
"name": "HaGeZi's DynDNS Blocklist",
|
||||
"categoryId": "security",
|
||||
|
||||
62
go.mod
62
go.mod
@ -4,9 +4,8 @@ go 1.25.1
|
||||
|
||||
require (
|
||||
github.com/AdguardTeam/dnsproxy v0.76.1
|
||||
// TODO(s.chzhen): Use osutil/executil and fakeos/fakeexec.
|
||||
github.com/AdguardTeam/golibs v0.34.0
|
||||
github.com/AdguardTeam/urlfilter v0.21.0
|
||||
github.com/AdguardTeam/golibs v0.34.1
|
||||
github.com/AdguardTeam/urlfilter v0.22.0
|
||||
github.com/NYTimes/gziphandler v1.1.1
|
||||
github.com/ameshkov/dnscrypt/v2 v2.4.0
|
||||
github.com/bluele/gcache v0.0.2
|
||||
@ -20,34 +19,34 @@ require (
|
||||
github.com/google/gopacket v1.1.19
|
||||
github.com/google/renameio/v2 v2.0.0
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/insomniacslk/dhcp v0.0.0-20250417080101-5f8cf70e8c5f
|
||||
github.com/kardianos/service v1.2.2
|
||||
github.com/insomniacslk/dhcp v0.0.0-20250828142853-d3abe7ccb0ad
|
||||
github.com/kardianos/service v1.2.4
|
||||
github.com/mdlayher/ethernet v0.0.0-20220221185849-529eae5b6118
|
||||
github.com/mdlayher/netlink v1.7.2
|
||||
github.com/mdlayher/netlink v1.8.0
|
||||
github.com/mdlayher/packet v1.1.2
|
||||
// TODO(a.garipov): This package is deprecated; find a new one or use our
|
||||
// own code for that. Perhaps, use gopacket.
|
||||
github.com/mdlayher/raw v0.1.0
|
||||
github.com/miekg/dns v1.1.68
|
||||
github.com/quic-go/quic-go v0.53.0
|
||||
github.com/quic-go/quic-go v0.54.0
|
||||
github.com/stretchr/testify v1.11.1
|
||||
github.com/ti-mo/netfilter v0.5.3
|
||||
go.etcd.io/bbolt v1.4.1
|
||||
go.etcd.io/bbolt v1.4.3
|
||||
go.yaml.in/yaml/v4 v4.0.0-rc.2
|
||||
golang.org/x/crypto v0.41.0
|
||||
golang.org/x/exp v0.0.0-20250813145105-42675adae3e6
|
||||
golang.org/x/net v0.43.0
|
||||
golang.org/x/sys v0.35.0
|
||||
golang.org/x/crypto v0.42.0
|
||||
golang.org/x/exp v0.0.0-20250911091902-df9299821621
|
||||
golang.org/x/net v0.44.0
|
||||
golang.org/x/sys v0.36.0
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
||||
howett.net/plist v1.0.1
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.121.6 // indirect
|
||||
cloud.google.com/go v0.122.0 // indirect
|
||||
cloud.google.com/go/ai v0.12.1 // indirect
|
||||
cloud.google.com/go/auth v0.16.5 // indirect
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.8.0 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.8.3 // indirect
|
||||
cloud.google.com/go/longrunning v0.6.7 // indirect
|
||||
github.com/BurntSushi/toml v1.5.0 // indirect
|
||||
github.com/ameshkov/dnsstamps v1.0.3 // indirect
|
||||
@ -80,33 +79,34 @@ require (
|
||||
github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 // indirect
|
||||
github.com/uudashr/gocognit v1.2.0 // indirect
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 // indirect
|
||||
go.opentelemetry.io/otel v1.38.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.38.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.38.0 // indirect
|
||||
go.uber.org/mock v0.5.2 // indirect
|
||||
golang.org/x/exp/typeparams v0.0.0-20250819193227-8b4c13bb791b // indirect
|
||||
golang.org/x/mod v0.27.0 // indirect
|
||||
golang.org/x/oauth2 v0.30.0 // indirect
|
||||
golang.org/x/sync v0.16.0 // indirect
|
||||
golang.org/x/telemetry v0.0.0-20250829165349-50b750f55de1 // indirect
|
||||
golang.org/x/term v0.34.0 // indirect
|
||||
golang.org/x/text v0.28.0 // indirect
|
||||
golang.org/x/time v0.12.0 // indirect
|
||||
golang.org/x/tools v0.36.0 // indirect
|
||||
go.uber.org/mock v0.6.0 // indirect
|
||||
golang.org/x/exp/typeparams v0.0.0-20250911091902-df9299821621 // indirect
|
||||
golang.org/x/mod v0.28.0 // indirect
|
||||
golang.org/x/oauth2 v0.31.0 // indirect
|
||||
golang.org/x/sync v0.17.0 // indirect
|
||||
golang.org/x/telemetry v0.0.0-20250908211612-aef8a434d053 // indirect
|
||||
golang.org/x/term v0.35.0 // indirect
|
||||
golang.org/x/text v0.29.0 // indirect
|
||||
golang.org/x/time v0.13.0 // indirect
|
||||
golang.org/x/tools v0.37.0 // indirect
|
||||
golang.org/x/vuln v1.1.4 // indirect
|
||||
gonum.org/v1/gonum v0.16.0 // indirect
|
||||
google.golang.org/api v0.248.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250826171959-ef028d996bc1 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250826171959-ef028d996bc1 // indirect
|
||||
google.golang.org/grpc v1.75.0 // indirect
|
||||
google.golang.org/protobuf v1.36.8 // indirect
|
||||
google.golang.org/api v0.249.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20250908214217-97024824d090 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 // indirect
|
||||
google.golang.org/grpc v1.75.1 // indirect
|
||||
google.golang.org/protobuf v1.36.9 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
honnef.co/go/tools v0.6.1 // indirect
|
||||
mvdan.cc/editorconfig v0.3.0 // indirect
|
||||
mvdan.cc/gofumpt v0.9.0 // indirect
|
||||
mvdan.cc/gofumpt v0.9.1 // indirect
|
||||
mvdan.cc/sh/v3 v3.12.0 // indirect
|
||||
mvdan.cc/unparam v0.0.0-20250301125049-0df0534333a4 // indirect
|
||||
)
|
||||
|
||||
141
go.sum
141
go.sum
@ -1,21 +1,21 @@
|
||||
cloud.google.com/go v0.121.6 h1:waZiuajrI28iAf40cWgycWNgaXPO06dupuS+sgibK6c=
|
||||
cloud.google.com/go v0.121.6/go.mod h1:coChdst4Ea5vUpiALcYKXEpR1S9ZgXbhEzzMcMR66vI=
|
||||
cloud.google.com/go v0.122.0 h1:0JTLGrcSIs3HIGsgVPvTx3cfyFSP/k9CI8vLPHTd6Wc=
|
||||
cloud.google.com/go v0.122.0/go.mod h1:xBoMV08QcqUGuPW65Qfm1o9Y4zKZBpGS+7bImXLTAZU=
|
||||
cloud.google.com/go/ai v0.12.1 h1:m1n/VjUuHS+pEO/2R4/VbuuEIkgk0w67fDQvFaMngM0=
|
||||
cloud.google.com/go/ai v0.12.1/go.mod h1:5vIPNe1ZQsVZqCliXIPL4QnhObQQY4d9hAGHdVc4iw4=
|
||||
cloud.google.com/go/auth v0.16.5 h1:mFWNQ2FEVWAliEQWpAdH80omXFokmrnbDhUS9cBywsI=
|
||||
cloud.google.com/go/auth v0.16.5/go.mod h1:utzRfHMP+Vv0mpOkTRQoWD2q3BatTOoWbA7gCc2dUhQ=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=
|
||||
cloud.google.com/go/compute/metadata v0.8.0 h1:HxMRIbao8w17ZX6wBnjhcDkW6lTFpgcaobyVfZWqRLA=
|
||||
cloud.google.com/go/compute/metadata v0.8.0/go.mod h1:sYOGTp851OV9bOFJ9CH7elVvyzopvWQFNNghtDQ/Biw=
|
||||
cloud.google.com/go/compute/metadata v0.8.3 h1:1AzcHmzbrX8t3m0CVosfxCAwGvaAShtrnlNxDriLgIk=
|
||||
cloud.google.com/go/compute/metadata v0.8.3/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10=
|
||||
cloud.google.com/go/longrunning v0.6.7 h1:IGtfDWHhQCgCjwQjV9iiLnUta9LBCo8R9QmAFsS/PrE=
|
||||
cloud.google.com/go/longrunning v0.6.7/go.mod h1:EAFV3IZAKmM56TyiE6VAP3VoTzhZzySwI/YI1s/nRsY=
|
||||
github.com/AdguardTeam/dnsproxy v0.76.1 h1:ms5vgdbYYXrKGPEpMFqUeql2j3aSfK1tGbCKju9rUgM=
|
||||
github.com/AdguardTeam/dnsproxy v0.76.1/go.mod h1:9Mw3wQMTYwM/HR9FdtatQAd+m0S8mbwq2J+UZiy/gXc=
|
||||
github.com/AdguardTeam/golibs v0.34.0 h1:JQK024DkTYxE7vsPVsYsoyDHW/53Nun7OYb9qscniK8=
|
||||
github.com/AdguardTeam/golibs v0.34.0/go.mod h1:K4C2EbfSEM1zY5YXoti9SfbTAHN/kIX97LpDtCwORrM=
|
||||
github.com/AdguardTeam/urlfilter v0.21.0 h1:ThIxiP7yoaXt8JTEroGQeU5ftQSoFpUq+t1L+TIx2pA=
|
||||
github.com/AdguardTeam/urlfilter v0.21.0/go.mod h1:xoZ3AF5qpE9ngbbeSShY9hgVeyHtm9MdH5xH1u714Wg=
|
||||
github.com/AdguardTeam/golibs v0.34.1 h1:RyBpZiXnJqlO3T+xjWldlxsEZDelmaFfKvXiJHDZZFQ=
|
||||
github.com/AdguardTeam/golibs v0.34.1/go.mod h1:K4C2EbfSEM1zY5YXoti9SfbTAHN/kIX97LpDtCwORrM=
|
||||
github.com/AdguardTeam/urlfilter v0.22.0 h1:ybOz3FywbpGDGC+8gFFkM1LMUOSosY7CWSBXIYXnG1U=
|
||||
github.com/AdguardTeam/urlfilter v0.22.0/go.mod h1:q0lWKapXlYTA4TUWUM1YDwU6Q0PKvQEokztcvRV2OW0=
|
||||
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
|
||||
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||
github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I=
|
||||
@ -48,8 +48,6 @@ github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-ping/ping v1.2.0 h1:vsJ8slZBZAXNCK4dPcI2PEE9eM9n9RbXbGouVQ/Y4yQ=
|
||||
github.com/go-ping/ping v1.2.0/go.mod h1:xIFjORFzTxqIV/tDVGO4eDy/bLuSyawEeojSm3GfRGk=
|
||||
github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI=
|
||||
@ -95,29 +93,27 @@ github.com/gordonklaus/ineffassign v0.2.0 h1:Uths4KnmwxNJNzq87fwQQDDnbNb7De00VOk
|
||||
github.com/gordonklaus/ineffassign v0.2.0/go.mod h1:TIpymnagPSexySzs7F9FnO1XFTy8IT3a59vmZp5Y9Lw=
|
||||
github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714 h1:/jC7qQFrv8CrSJVmaolDVOxTfS9kc36uB6H40kdbQq8=
|
||||
github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis=
|
||||
github.com/insomniacslk/dhcp v0.0.0-20250417080101-5f8cf70e8c5f h1:dd33oobuIv9PcBVqvbEiCXEbNTomOHyj3WFuC5YiPRU=
|
||||
github.com/insomniacslk/dhcp v0.0.0-20250417080101-5f8cf70e8c5f/go.mod h1:zhFlBeJssZ1YBCMZ5Lzu1pX4vhftDvU10WUVb1uXKtM=
|
||||
github.com/insomniacslk/dhcp v0.0.0-20250828142853-d3abe7ccb0ad h1:F2k0SD55QlicoEZ1IK+a6QEt/eUqT+okQAoQG7AwSk0=
|
||||
github.com/insomniacslk/dhcp v0.0.0-20250828142853-d3abe7ccb0ad/go.mod h1:qfvBmyDNp+/liLEYWRvqny/PEz9hGe2Dz833eXILSmo=
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/josharian/native v1.0.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
||||
github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA=
|
||||
github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
||||
github.com/jstemmer/go-junit-report/v2 v2.1.0 h1:X3+hPYlSczH9IMIpSC9CQSZA0L+BipYafciZUWHEmsc=
|
||||
github.com/jstemmer/go-junit-report/v2 v2.1.0/go.mod h1:mgHVr7VUo5Tn8OLVr1cKnLuEy0M92wdRntM99h7RkgQ=
|
||||
github.com/kardianos/service v1.2.2 h1:ZvePhAHfvo0A7Mftk/tEzqEZ7Q4lgnR8sGz4xu1YX60=
|
||||
github.com/kardianos/service v1.2.2/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM=
|
||||
github.com/kardianos/service v1.2.4 h1:XNlGtZOYNx2u91urOdg/Kfmc+gfmuIo1Dd3rEi2OgBk=
|
||||
github.com/kardianos/service v1.2.4/go.mod h1:E4V9ufUuY82F7Ztlu1eN9VXWIQxg8NoLQlmFe0MtrXc=
|
||||
github.com/kisielk/errcheck v1.9.0 h1:9xt1zI9EBfcYBvdU1nVrzMzzUPUtPKs9bVSIM3TAb3M=
|
||||
github.com/kisielk/errcheck v1.9.0/go.mod h1:kQxWMMVZgIkDq7U8xtG/n2juOjbLgZtedi0D+/VL/i8=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
|
||||
github.com/mdlayher/ethernet v0.0.0-20220221185849-529eae5b6118 h1:2oDp6OOhLxQ9JBoUuysVz9UZ9uI6oLUbvAZu0x8o+vE=
|
||||
github.com/mdlayher/ethernet v0.0.0-20220221185849-529eae5b6118/go.mod h1:ZFUnHIVchZ9lJoWoEGUg8Q3M4U8aNNWA3CVSUTkW4og=
|
||||
github.com/mdlayher/netlink v0.0.0-20190313131330-258ea9dff42c/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA=
|
||||
github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g=
|
||||
github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw=
|
||||
github.com/mdlayher/netlink v1.8.0 h1:e7XNIYJKD7hUct3Px04RuIGJbBxy1/c4nX7D5YyvvlM=
|
||||
github.com/mdlayher/netlink v1.8.0/go.mod h1:UhgKXUlDQhzb09DrCl2GuRNEglHmhYoWAHid9HK3594=
|
||||
github.com/mdlayher/packet v1.0.0/go.mod h1:eE7/ctqDhoiRhQ44ko5JZU2zxB88g+JH/6jmnjzPjOU=
|
||||
github.com/mdlayher/packet v1.1.2 h1:3Up1NG6LZrsgDVn6X4L9Ge/iyRyxFEFD9o6Pr3Q1nQY=
|
||||
github.com/mdlayher/packet v1.1.2/go.mod h1:GEu1+n9sG5VtiRE4SydOmX5GTwyyYlteZiFU+x0kew4=
|
||||
@ -141,22 +137,16 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
|
||||
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
|
||||
github.com/quic-go/quic-go v0.53.0 h1:QHX46sISpG2S03dPeZBgVIZp8dGagIaiu2FiVYvpCZI=
|
||||
github.com/quic-go/quic-go v0.53.0/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY=
|
||||
github.com/quic-go/quic-go v0.54.0 h1:6s1YB9QotYI6Ospeiguknbp2Znb/jZYjZLRXn9kMQBg=
|
||||
github.com/quic-go/quic-go v0.54.0/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY=
|
||||
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||
github.com/securego/gosec/v2 v2.22.8 h1:3NMpmfXO8wAVFZPNsd3EscOTa32Jyo6FLLlW53bexMI=
|
||||
github.com/securego/gosec/v2 v2.22.8/go.mod h1:ZAw8K2ikuH9qDlfdV87JmNghnVfKB1XC7+TVzk6Utto=
|
||||
github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI=
|
||||
github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk=
|
||||
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
|
||||
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
@ -166,22 +156,16 @@ github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD
|
||||
github.com/ti-mo/netfilter v0.2.0/go.mod h1:8GbBGsY/8fxtyIdfwy29JiluNcPK4K7wIT+x42ipqUU=
|
||||
github.com/ti-mo/netfilter v0.5.3 h1:ikzduvnaUMwre5bhbNwWOd6bjqLMVb33vv0XXbK0xGQ=
|
||||
github.com/ti-mo/netfilter v0.5.3/go.mod h1:08SyBCg6hu1qyQk4s3DjjJKNrm3RTb32nm6AzyT972E=
|
||||
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
|
||||
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
|
||||
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
|
||||
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
|
||||
github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 h1:pyC9PaHYZFgEKFdlp3G8RaCKgVpHZnecvArXvPXcFkM=
|
||||
github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701/go.mod h1:P3a5rG4X7tI17Nn3aOIAYr5HbIMukwXG0urG0WuL8OA=
|
||||
github.com/uudashr/gocognit v1.2.0 h1:3BU9aMr1xbhPlvJLSydKwdLN3tEUUrzPSSM8S4hDYRA=
|
||||
github.com/uudashr/gocognit v1.2.0/go.mod h1:k/DdKPI6XBZO1q7HgoV2juESI2/Ofj9AcHPZhBBdrTU=
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
|
||||
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
go.etcd.io/bbolt v1.4.1 h1:5mOV+HWjIPLEAlUGMsveaUvK2+byZMFOzojoi7bh7uI=
|
||||
go.etcd.io/bbolt v1.4.1/go.mod h1:c8zu2BnXWTu2XM4XcICtbGSl9cFwsXtcf9zLt2OncM8=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.etcd.io/bbolt v1.4.3 h1:dEadXpI6G79deX5prL3QRNP6JB8UxVkqo4UPnHaNXJo=
|
||||
go.etcd.io/bbolt v1.4.3/go.mod h1:tKQlpPaYCVFctUIgFKFnAlvbmB3tpy1vkTnDWohtc0E=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 h1:YH4g8lQroajqUwWbq/tr2QX1JFmEXaDLgG+ew9bLMWo=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0/go.mod h1:fvPi2qXDqFs8M4B4fmJhE92TyQs9Ydjlg3RvfUp+NbQ=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 h1:RbKq8BG0FI8OiXhBfcRtqqHcZcka+gU3cskNuf05R18=
|
||||
@ -198,62 +182,61 @@ go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJr
|
||||
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
|
||||
go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
|
||||
go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
|
||||
go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
|
||||
go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o=
|
||||
go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
|
||||
go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
|
||||
go.yaml.in/yaml/v4 v4.0.0-rc.2 h1:/FrI8D64VSr4HtGIlUtlFMGsm7H7pWTbj6vOLVZcA6s=
|
||||
go.yaml.in/yaml/v4 v4.0.0-rc.2/go.mod h1:aZqd9kCMsGL7AuUv/m/PvWLdg5sjJsZ4oHDEnfPPfY0=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
|
||||
golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
|
||||
golang.org/x/exp v0.0.0-20250813145105-42675adae3e6 h1:SbTAbRFnd5kjQXbczszQ0hdk3ctwYf3qBNH9jIsGclE=
|
||||
golang.org/x/exp v0.0.0-20250813145105-42675adae3e6/go.mod h1:4QTo5u+SEIbbKW1RacMZq1YEfOBqeXa19JeshGi+zc4=
|
||||
golang.org/x/exp/typeparams v0.0.0-20250819193227-8b4c13bb791b h1:GU1ttDuJS89SePnuEsEuLj7dMMFP2JkGsDV1Z51iDXo=
|
||||
golang.org/x/exp/typeparams v0.0.0-20250819193227-8b4c13bb791b/go.mod h1:4Mzdyp/6jzw9auFDJ3OMF5qksa7UvPnzKqTVGcb04ms=
|
||||
golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=
|
||||
golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
|
||||
golang.org/x/exp v0.0.0-20250911091902-df9299821621 h1:2id6c1/gto0kaHYyrixvknJ8tUK/Qs5IsmBtrc+FtgU=
|
||||
golang.org/x/exp v0.0.0-20250911091902-df9299821621/go.mod h1:TwQYMMnGpvZyc+JpB/UAuTNIsVJifOlSkrZkhcvpVUk=
|
||||
golang.org/x/exp/typeparams v0.0.0-20250911091902-df9299821621 h1:Yl4H5w2RV7L/dvSHp2GerziT5K2CORgFINPaMFxWGWw=
|
||||
golang.org/x/exp/typeparams v0.0.0-20250911091902-df9299821621/go.mod h1:4Mzdyp/6jzw9auFDJ3OMF5qksa7UvPnzKqTVGcb04ms=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ=
|
||||
golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc=
|
||||
golang.org/x/mod v0.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U=
|
||||
golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
|
||||
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
|
||||
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
|
||||
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
|
||||
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
|
||||
golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I=
|
||||
golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
|
||||
golang.org/x/oauth2 v0.31.0 h1:8Fq0yVZLh4j4YA47vHKFTa9Ew5XIrCP8LC6UeNZnLxo=
|
||||
golang.org/x/oauth2 v0.31.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
|
||||
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
|
||||
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190322080309-f49334f85ddc/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
|
||||
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/telemetry v0.0.0-20250829165349-50b750f55de1 h1:zRLyLxwtVA3d2qsYvSJVSNco/qz2wzR8oJNhpLTN6x8=
|
||||
golang.org/x/telemetry v0.0.0-20250829165349-50b750f55de1/go.mod h1:JIJwPkb04vX0KeIBbQ7epGtgIjA8ihHbsAtW4A/lIQ4=
|
||||
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
|
||||
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/telemetry v0.0.0-20250908211612-aef8a434d053 h1:dHQOQddU4YHS5gY33/6klKjq7Gp3WwMyOXGNp5nzRj8=
|
||||
golang.org/x/telemetry v0.0.0-20250908211612-aef8a434d053/go.mod h1:+nZKN+XVh4LCiA9DV3ywrzN4gumyCnKjau3NGb9SGoE=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4=
|
||||
golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw=
|
||||
golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ=
|
||||
golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
|
||||
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
|
||||
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
|
||||
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
||||
golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
|
||||
golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
|
||||
golang.org/x/time v0.13.0 h1:eUlYslOIt32DgYD6utsuUeHs4d7AsEYLuIAdg7FlYgI=
|
||||
golang.org/x/time v0.13.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg=
|
||||
golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s=
|
||||
golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE=
|
||||
golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w=
|
||||
golang.org/x/tools/go/expect v0.1.1-deprecated h1:jpBZDwmgPhXsKZC6WhL20P4b/wmnpsEAGHaNy0n/rJM=
|
||||
golang.org/x/tools/go/expect v0.1.1-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY=
|
||||
golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated h1:1h2MnaIAIXISqTFKdENegdpAgUXz6NrPEsbIeWaBRvM=
|
||||
@ -264,18 +247,18 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||
google.golang.org/api v0.248.0 h1:hUotakSkcwGdYUqzCRc5yGYsg4wXxpkKlW5ryVqvC1Y=
|
||||
google.golang.org/api v0.248.0/go.mod h1:yAFUAF56Li7IuIQbTFoLwXTCI6XCFKueOlS7S9e4F9k=
|
||||
google.golang.org/genproto v0.0.0-20250603155806-513f23925822 h1:rHWScKit0gvAPuOnu87KpaYtjK5zBMLcULh7gxkCXu4=
|
||||
google.golang.org/genproto v0.0.0-20250603155806-513f23925822/go.mod h1:HubltRL7rMh0LfnQPkMH4NPDFEWp0jw3vixw7jEM53s=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250826171959-ef028d996bc1 h1:APHvLLYBhtZvsbnpkfknDZ7NyH4z5+ub/I0u8L3Oz6g=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250826171959-ef028d996bc1/go.mod h1:xUjFWUnWDpZ/C0Gu0qloASKFb6f8/QXiiXhSPFsD668=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250826171959-ef028d996bc1 h1:pmJpJEvT846VzausCQ5d7KreSROcDqmO388w5YbnltA=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250826171959-ef028d996bc1/go.mod h1:GmFNa4BdJZ2a8G+wCe9Bg3wwThLrJun751XstdJt5Og=
|
||||
google.golang.org/grpc v1.75.0 h1:+TW+dqTd2Biwe6KKfhE5JpiYIBWq865PhKGSXiivqt4=
|
||||
google.golang.org/grpc v1.75.0/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
|
||||
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
|
||||
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
google.golang.org/api v0.249.0 h1:0VrsWAKzIZi058aeq+I86uIXbNhm9GxSHpbmZ92a38w=
|
||||
google.golang.org/api v0.249.0/go.mod h1:dGk9qyI0UYPwO/cjt2q06LG/EhUpwZGdAbYF14wHHrQ=
|
||||
google.golang.org/genproto v0.0.0-20250908214217-97024824d090 h1:ywCL7vA2n3vVHyf+bx1ZV/knaTPRI8GIeKY0MEhEeOc=
|
||||
google.golang.org/genproto v0.0.0-20250908214217-97024824d090/go.mod h1:zwJI9HzbJJlw2KXy0wX+lmT2JuZoaKK9JC4ppqmxxjk=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 h1:d8Nakh1G+ur7+P3GcMjpRDEkoLUcLW2iU92XVqR+XMQ=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090/go.mod h1:U8EXRNSd8sUYyDfs/It7KVWodQr+Hf9xtxyxWudSwEw=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 h1:/OQuEa4YWtDt7uQWHd3q3sUMb+QOLQUg1xa8CEsRv5w=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090/go.mod h1:GmFNa4BdJZ2a8G+wCe9Bg3wwThLrJun751XstdJt5Og=
|
||||
google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI=
|
||||
google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
|
||||
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
|
||||
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
@ -290,8 +273,8 @@ howett.net/plist v1.0.1 h1:37GdZ8tP09Q35o9ych3ehygcsL+HqKSwzctveSlarvM=
|
||||
howett.net/plist v1.0.1/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g=
|
||||
mvdan.cc/editorconfig v0.3.0 h1:D1D2wLYEYGpawWT5SpM5pRivgEgXjtEXwC9MWhEY0gQ=
|
||||
mvdan.cc/editorconfig v0.3.0/go.mod h1:NcJHuDtNOTEJ6251indKiWuzK6+VcrMuLzGMLKBFupQ=
|
||||
mvdan.cc/gofumpt v0.9.0 h1:W0wNHMSvDBDIyZsm3nnGbVfgp5AknzBrGJnfLCy501w=
|
||||
mvdan.cc/gofumpt v0.9.0/go.mod h1:3xYtNemnKiXaTh6R4VtlqDATFwBbdXI8lJvH/4qk7mw=
|
||||
mvdan.cc/gofumpt v0.9.1 h1:p5YT2NfFWsYyTieYgwcQ8aKV3xRvFH4uuN/zB2gBbMQ=
|
||||
mvdan.cc/gofumpt v0.9.1/go.mod h1:3xYtNemnKiXaTh6R4VtlqDATFwBbdXI8lJvH/4qk7mw=
|
||||
mvdan.cc/sh/v3 v3.12.0 h1:ejKUR7ONP5bb+UGHGEG/k9V5+pRVIyD+LsZz7o8KHrI=
|
||||
mvdan.cc/sh/v3 v3.12.0/go.mod h1:Se6Cj17eYSn+sNooLZiEUnNNmNxg0imoYlTu4CyaGyg=
|
||||
mvdan.cc/unparam v0.0.0-20250301125049-0df0534333a4 h1:WjUu4yQoT5BHT1w8Zu56SP8367OuBV5jvo+4Ulppyf8=
|
||||
|
||||
@ -1,25 +1,29 @@
|
||||
package aghalg
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"slices"
|
||||
)
|
||||
|
||||
// SortedMap is a map that keeps elements in order with internal sorting
|
||||
// function. Must be initialized by the [NewSortedMap].
|
||||
// function. It must be initialized with [NewSortedMap] or [NewSortedMapFunc].
|
||||
type SortedMap[K comparable, V any] struct {
|
||||
vals map[K]V
|
||||
cmp func(a, b K) (res int)
|
||||
keys []K
|
||||
}
|
||||
|
||||
// NewSortedMap initializes the new instance of sorted map. cmp is a sort
|
||||
// function to keep elements in order.
|
||||
//
|
||||
// TODO(s.chzhen): Use cmp.Compare in Go 1.21.
|
||||
func NewSortedMap[K comparable, V any](cmp func(a, b K) (res int)) SortedMap[K, V] {
|
||||
return SortedMap[K, V]{
|
||||
// NewSortedMap initializes a new instance of sorted map.
|
||||
func NewSortedMap[K cmp.Ordered, V any]() (m *SortedMap[K, V]) {
|
||||
return NewSortedMapFunc[K, V](cmp.Compare[K])
|
||||
}
|
||||
|
||||
// NewSortedMapFunc initializes a new instance of sorted map. cmpFunc is a
|
||||
// comparison function to keep elements in order. cmpFunc must not be nil.
|
||||
func NewSortedMapFunc[K comparable, V any](cmpFunc func(a, b K) (res int)) (m *SortedMap[K, V]) {
|
||||
return &SortedMap[K, V]{
|
||||
vals: map[K]V{},
|
||||
cmp: cmp,
|
||||
cmp: cmpFunc,
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,7 +73,7 @@ func (m *SortedMap[K, V]) Clear() {
|
||||
return
|
||||
}
|
||||
|
||||
m.keys = nil
|
||||
m.keys = m.keys[:0]
|
||||
clear(m.vals)
|
||||
}
|
||||
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
package aghalg_test
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghalg"
|
||||
@ -9,7 +8,7 @@ import (
|
||||
)
|
||||
|
||||
func TestNewSortedMap(t *testing.T) {
|
||||
var m aghalg.SortedMap[string, int]
|
||||
var m *aghalg.SortedMap[string, int]
|
||||
|
||||
letters := []string{}
|
||||
for i := range 10 {
|
||||
@ -18,7 +17,7 @@ func TestNewSortedMap(t *testing.T) {
|
||||
}
|
||||
|
||||
t.Run("create_and_fill", func(t *testing.T) {
|
||||
m = aghalg.NewSortedMap[string, int](strings.Compare)
|
||||
m = aghalg.NewSortedMap[string, int]()
|
||||
|
||||
nums := []int{}
|
||||
for i, r := range letters {
|
||||
|
||||
@ -39,6 +39,7 @@ func checkOtherDHCP(ifaceName string) (ok4, ok6 bool, err4, err6 error) {
|
||||
}
|
||||
|
||||
// ifaceIPv4Subnet returns the first suitable IPv4 subnetwork iface has.
|
||||
// iface must not be nil.
|
||||
func ifaceIPv4Subnet(iface *net.Interface) (subnet netip.Prefix, err error) {
|
||||
var addrs []net.Addr
|
||||
if addrs, err = iface.Addrs(); err != nil {
|
||||
@ -90,6 +91,8 @@ func checkOtherDHCPv4(iface *net.Interface) (ok bool, err error) {
|
||||
return discover4(iface, dstAddr, hostname)
|
||||
}
|
||||
|
||||
// discover4 sends a DHCPv4 discovery to the specified network interface and
|
||||
// waits for response. iface and dstAddr must not be nil.
|
||||
func discover4(iface *net.Interface, dstAddr *net.UDPAddr, hostname string) (ok bool, err error) {
|
||||
var req *dhcpv4.DHCPv4
|
||||
if req, err = dhcpv4.NewDiscovery(iface.HardwareAddr); err != nil {
|
||||
@ -120,17 +123,9 @@ func discover4(iface *net.Interface, dstAddr *net.UDPAddr, hostname string) (ok
|
||||
}
|
||||
|
||||
for {
|
||||
if err = c.SetDeadline(time.Now().Add(defaultDiscoverTime)); err != nil {
|
||||
return false, fmt.Errorf("setting deadline: %w", err)
|
||||
}
|
||||
|
||||
var next bool
|
||||
ok, next, err = tryConn4(req, c, iface)
|
||||
if next {
|
||||
if err != nil {
|
||||
log.Debug("dhcpv4: trying a connection: %s", err)
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
@ -142,9 +137,20 @@ func discover4(iface *net.Interface, dstAddr *net.UDPAddr, hostname string) (ok
|
||||
}
|
||||
}
|
||||
|
||||
// tryConn4 reads and validates DHCPv4 response packet if it matches
|
||||
// the original request. req and c must not be nil.
|
||||
//
|
||||
// TODO(a.garipov): Refactor further. Inspect error handling, remove parameter
|
||||
// next, address the TODO, merge with tryConn6, etc.
|
||||
func tryConn4(req *dhcpv4.DHCPv4, c net.PacketConn, iface *net.Interface) (ok, next bool, err error) {
|
||||
func tryConn4(
|
||||
req *dhcpv4.DHCPv4,
|
||||
c net.PacketConn,
|
||||
iface *net.Interface,
|
||||
) (ok, next bool, err error) {
|
||||
if err = c.SetDeadline(time.Now().Add(defaultDiscoverTime)); err != nil {
|
||||
return false, false, fmt.Errorf("dhcpv4: setting deadline: %w", err)
|
||||
}
|
||||
|
||||
// TODO: replicate dhclient's behavior of retrying several times with
|
||||
// progressively longer timeouts.
|
||||
log.Tracef("dhcpv4: waiting %v for an answer", defaultDiscoverTime)
|
||||
@ -221,6 +227,8 @@ func checkOtherDHCPv6(iface *net.Interface) (ok bool, err error) {
|
||||
return discover6(iface, udpAddr, dstAddr)
|
||||
}
|
||||
|
||||
// discover6 sends a DHCPv6 discovery to the specified network interface and
|
||||
// waits for response. iface, updAddr and dstAddr must not be nil.
|
||||
func discover6(iface *net.Interface, udpAddr, dstAddr *net.UDPAddr) (ok bool, err error) {
|
||||
req, err := dhcpv6.NewSolicit(iface.HardwareAddr)
|
||||
if err != nil {
|
||||
@ -243,10 +251,6 @@ func discover6(iface *net.Interface, udpAddr, dstAddr *net.UDPAddr) (ok bool, er
|
||||
var next bool
|
||||
ok, next, err = tryConn6(req, c)
|
||||
if next {
|
||||
if err != nil {
|
||||
log.Debug("dhcpv6: trying a connection: %s", err)
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
@ -258,6 +262,9 @@ func discover6(iface *net.Interface, udpAddr, dstAddr *net.UDPAddr) (ok bool, er
|
||||
}
|
||||
}
|
||||
|
||||
// tryConn6 reads and validates DHCPv6 response packet if it matches
|
||||
// the original request. req and c must not be nil.
|
||||
//
|
||||
// TODO(a.garipov): See the comment on tryConn4. Sigh…
|
||||
func tryConn6(req *dhcpv6.Message, c net.PacketConn) (ok, next bool, err error) {
|
||||
// TODO: replicate dhclient's behavior of retrying several times with
|
||||
|
||||
@ -23,7 +23,7 @@ type NetIface interface {
|
||||
Addrs() ([]net.Addr, error)
|
||||
}
|
||||
|
||||
// IfaceIPAddrs returns the interface's IP addresses.
|
||||
// IfaceIPAddrs returns the interface's IP addresses. iface must not be nil.
|
||||
func IfaceIPAddrs(iface NetIface, ipv IPVersion) (ips []net.IP, err error) {
|
||||
switch ipv {
|
||||
case IPVersion4, IPVersion6:
|
||||
@ -38,25 +38,7 @@ func IfaceIPAddrs(iface NetIface, ipv IPVersion) (ips []net.IP, err error) {
|
||||
}
|
||||
|
||||
for _, a := range addrs {
|
||||
var ip net.IP
|
||||
switch a := a.(type) {
|
||||
case *net.IPAddr:
|
||||
ip = a.IP
|
||||
case *net.IPNet:
|
||||
ip = a.IP
|
||||
default:
|
||||
continue
|
||||
}
|
||||
|
||||
// Assume that net.(*Interface).Addrs can only return valid IPv4 and
|
||||
// IPv6 addresses. Thus, if it isn't an IPv4 address, it must be an
|
||||
// IPv6 one.
|
||||
ip4 := ip.To4()
|
||||
if ipv == IPVersion4 {
|
||||
if ip4 != nil {
|
||||
ips = append(ips, ip4)
|
||||
}
|
||||
} else if ip4 == nil {
|
||||
if ip := ipFromAddr(a, ipv); ip != nil {
|
||||
ips = append(ips, ip)
|
||||
}
|
||||
}
|
||||
@ -64,6 +46,29 @@ func IfaceIPAddrs(iface NetIface, ipv IPVersion) (ips []net.IP, err error) {
|
||||
return ips, nil
|
||||
}
|
||||
|
||||
// ipFromAddr converts addr to IP. addr must not be nil.
|
||||
func ipFromAddr(addr net.Addr, ipv IPVersion) (ip net.IP) {
|
||||
switch addr := addr.(type) {
|
||||
case *net.IPAddr:
|
||||
ip = addr.IP
|
||||
case *net.IPNet:
|
||||
ip = addr.IP
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
// Assume that net.Addr can only be valid IPv4 or IPv6. Thus,
|
||||
// if it isn't an IPv4 address, it must be an IPv6 one.
|
||||
ip4 := ip.To4()
|
||||
if ipv == IPVersion4 {
|
||||
return ip4
|
||||
} else if ip4 == nil {
|
||||
return ip
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// IfaceDNSIPAddrs returns IP addresses of the interface suitable to send to
|
||||
// clients as DNS addresses. If err is nil, addrs contains either no addresses
|
||||
// or at least two.
|
||||
|
||||
@ -148,44 +148,72 @@ func NetInterfaceFrom(iface *net.Interface) (niface *NetInterface, err error) {
|
||||
|
||||
addrs, err := iface.Addrs()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get addresses for interface %s: %w", iface.Name, err)
|
||||
return nil, fmt.Errorf("getting addresses for interface %q: %w", iface.Name, err)
|
||||
}
|
||||
|
||||
// Collect network interface addresses.
|
||||
for _, addr := range addrs {
|
||||
n, ok := addr.(*net.IPNet)
|
||||
if !ok {
|
||||
// Should be *net.IPNet, this is weird.
|
||||
return nil, fmt.Errorf("expected %[2]s to be %[1]T, got %[2]T", n, addr)
|
||||
} else if ip4 := n.IP.To4(); ip4 != nil {
|
||||
n.IP = ip4
|
||||
for i, addr := range addrs {
|
||||
if err = populateAddrs(addr, niface); err != nil {
|
||||
return nil, fmt.Errorf("populating at index %d: %w", i, err)
|
||||
}
|
||||
|
||||
ip, ok := netip.AddrFromSlice(n.IP)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("bad address %s", n.IP)
|
||||
}
|
||||
|
||||
ip = ip.Unmap()
|
||||
if ip.IsLinkLocalUnicast() {
|
||||
// Ignore link-local IPv4.
|
||||
if ip.Is4() {
|
||||
continue
|
||||
}
|
||||
|
||||
ip = ip.WithZone(iface.Name)
|
||||
}
|
||||
|
||||
ones, _ := n.Mask.Size()
|
||||
p := netip.PrefixFrom(ip, ones)
|
||||
|
||||
niface.Addresses = append(niface.Addresses, ip)
|
||||
niface.Subnets = append(niface.Subnets, p)
|
||||
}
|
||||
|
||||
return niface, nil
|
||||
}
|
||||
|
||||
// populateAddrs fills *NetInterface IP addresses and subnets. addr and niface
|
||||
// must not be nil.
|
||||
func populateAddrs(addr net.Addr, niface *NetInterface) (err error) {
|
||||
n, err := ipNetFromAddr(addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ip, ok := netip.AddrFromSlice(n.IP)
|
||||
if !ok {
|
||||
return fmt.Errorf("bad address %s", n.IP)
|
||||
}
|
||||
|
||||
ip = ip.Unmap()
|
||||
|
||||
// Skip link-local IPv4 addresses
|
||||
if isLinkLocalV4(ip) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if ip.IsLinkLocalUnicast() {
|
||||
ip = ip.WithZone(niface.Name)
|
||||
}
|
||||
|
||||
ones, _ := n.Mask.Size()
|
||||
p := netip.PrefixFrom(ip, ones)
|
||||
|
||||
niface.Addresses = append(niface.Addresses, ip)
|
||||
niface.Subnets = append(niface.Subnets, p)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ipNetFromAddr converts net.Addr to *net.IPNet and its IP to v4 if necessary.
|
||||
func ipNetFromAddr(addr net.Addr) (ip *net.IPNet, err error) {
|
||||
ipNet, ok := addr.(*net.IPNet)
|
||||
if !ok {
|
||||
// Should be *net.IPNet, this is weird.
|
||||
return nil, fmt.Errorf("bad type for interface net.Addr %T(%[1]v)", ipNet)
|
||||
}
|
||||
|
||||
// TODO(f.setrakov): Explore whether this logic can be safely removed.
|
||||
if ip4 := ipNet.IP.To4(); ip4 != nil {
|
||||
ipNet.IP = ip4
|
||||
}
|
||||
|
||||
return ipNet, nil
|
||||
}
|
||||
|
||||
// isLinkLocalV4 checks if ip is link-local unicast IPv4 address.
|
||||
func isLinkLocalV4(ip netip.Addr) (ok bool) {
|
||||
return ip.Is4() && ip.IsLinkLocalUnicast()
|
||||
}
|
||||
|
||||
// GetValidNetInterfacesForWeb returns interfaces that are eligible for DNS and
|
||||
// WEB only we do not return link-local addresses here.
|
||||
//
|
||||
|
||||
@ -31,6 +31,9 @@ func macToKey(mac net.HardwareAddr) (key macKey) {
|
||||
|
||||
// index stores all information about persistent clients.
|
||||
type index struct {
|
||||
// subnetToUID maps subnet to UID.
|
||||
subnetToUID *aghalg.SortedMap[netip.Prefix, UID]
|
||||
|
||||
// nameToUID maps client name to UID.
|
||||
nameToUID map[string]UID
|
||||
|
||||
@ -45,18 +48,15 @@ type index struct {
|
||||
|
||||
// uidToClient maps UID to the persistent client.
|
||||
uidToClient map[UID]*Persistent
|
||||
|
||||
// subnetToUID maps subnet to UID.
|
||||
subnetToUID aghalg.SortedMap[netip.Prefix, UID]
|
||||
}
|
||||
|
||||
// newIndex initializes the new instance of client index.
|
||||
func newIndex() (ci *index) {
|
||||
return &index{
|
||||
subnetToUID: aghalg.NewSortedMapFunc[netip.Prefix, UID](subnetCompare),
|
||||
nameToUID: map[string]UID{},
|
||||
clientIDToUID: map[ClientID]UID{},
|
||||
ipToUID: map[netip.Addr]UID{},
|
||||
subnetToUID: aghalg.NewSortedMap[netip.Prefix, UID](subnetCompare),
|
||||
macToUID: map[macKey]UID{},
|
||||
uidToClient: map[UID]*Persistent{},
|
||||
}
|
||||
|
||||
@ -191,6 +191,8 @@ func (c *Persistent) SetIDs(ids []string) (err error) {
|
||||
// subnetCompare is a comparison function for the two subnets. It returns -1 if
|
||||
// x sorts before y, 1 if x sorts after y, and 0 if their relative sorting
|
||||
// position is the same.
|
||||
//
|
||||
// TODO(s.chzhen): Use netip.Prefix.Compare in Go 1.26.
|
||||
func subnetCompare(x, y netip.Prefix) (cmp int) {
|
||||
if x == y {
|
||||
return 0
|
||||
|
||||
@ -32,7 +32,7 @@ func initBlockedServices(ctx context.Context, l *slog.Logger) {
|
||||
for i, s := range blockedServices {
|
||||
netRules := make([]*rules.NetworkRule, 0, len(s.Rules))
|
||||
for _, text := range s.Rules {
|
||||
rule, err := rules.NewNetworkRule(text, rulelist.URLFilterIDBlockedService)
|
||||
rule, err := rules.NewNetworkRule(text, rulelist.IDBlockedService)
|
||||
if err == nil {
|
||||
netRules = append(netRules, rule)
|
||||
|
||||
@ -133,8 +133,10 @@ func (d *DNSFilter) handleBlockedServicesIDs(w http.ResponseWriter, r *http.Requ
|
||||
func (d *DNSFilter) handleBlockedServicesAll(w http.ResponseWriter, r *http.Request) {
|
||||
aghhttp.WriteJSONResponseOK(w, r, struct {
|
||||
BlockedServices []blockedService `json:"blocked_services"`
|
||||
ServiceGroups []serviceGroup `json:"groups"`
|
||||
}{
|
||||
BlockedServices: blockedServices,
|
||||
ServiceGroups: serviceGroups,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -29,10 +29,9 @@ func (d *DNSFilter) processDNSRewrites(dnsr []*rules.NetworkRule) (res Result) {
|
||||
dr := nr.DNSRewrite
|
||||
if dr.NewCNAME != "" {
|
||||
// NewCNAME rules have a higher priority than other rules.
|
||||
rules = []*ResultRule{{
|
||||
FilterListID: nr.GetFilterListID(),
|
||||
Text: nr.RuleText,
|
||||
}}
|
||||
rules = []*ResultRule{
|
||||
NewResultRule(nr),
|
||||
}
|
||||
|
||||
return Result{
|
||||
Rules: rules,
|
||||
@ -45,17 +44,13 @@ func (d *DNSFilter) processDNSRewrites(dnsr []*rules.NetworkRule) (res Result) {
|
||||
case dns.RcodeSuccess:
|
||||
dnsrr.RCode = dr.RCode
|
||||
dnsrr.Response[dr.RRType] = append(dnsrr.Response[dr.RRType], dr.Value)
|
||||
rules = append(rules, &ResultRule{
|
||||
FilterListID: nr.GetFilterListID(),
|
||||
Text: nr.RuleText,
|
||||
})
|
||||
rules = append(rules, NewResultRule(nr))
|
||||
default:
|
||||
// RcodeRefused and other such codes have higher priority. Return
|
||||
// immediately.
|
||||
rules = []*ResultRule{{
|
||||
FilterListID: nr.GetFilterListID(),
|
||||
Text: nr.RuleText,
|
||||
}}
|
||||
rules = []*ResultRule{
|
||||
NewResultRule(nr),
|
||||
}
|
||||
dnsrr = &DNSRewriteResult{
|
||||
RCode: dr.RCode,
|
||||
}
|
||||
|
||||
@ -52,7 +52,8 @@ func (filter *FilterYAML) Path(dataDir string) string {
|
||||
return filepath.Join(
|
||||
dataDir,
|
||||
filterDir,
|
||||
strconv.FormatInt(int64(filter.ID), 10)+".txt")
|
||||
strconv.FormatUint(uint64(filter.ID), 10)+".txt",
|
||||
)
|
||||
}
|
||||
|
||||
// ensureName sets provided title or default name for the filter if it doesn't
|
||||
@ -612,6 +613,7 @@ func (d *DNSFilter) load(ctx context.Context, flt *FilterYAML) (err error) {
|
||||
|
||||
d.logger.DebugContext(ctx, "loading filter", "id", flt.ID, "path", fileName)
|
||||
|
||||
// #nosec G304 -- Assume that fileName is always within DataDir.
|
||||
file, err := os.Open(fileName)
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
// Do nothing, file doesn't exist.
|
||||
@ -655,7 +657,7 @@ func (d *DNSFilter) EnableFilters(async bool) {
|
||||
func (d *DNSFilter) enableFiltersLocked(ctx context.Context, async bool) {
|
||||
filters := make([]Filter, 1, len(d.conf.Filters)+len(d.conf.WhitelistFilters)+1)
|
||||
filters[0] = Filter{
|
||||
ID: rulelist.URLFilterIDCustom,
|
||||
ID: rulelist.IDCustom,
|
||||
Data: []byte(strings.Join(d.conf.UserRules, "\n")),
|
||||
}
|
||||
|
||||
|
||||
@ -302,86 +302,10 @@ type Filter struct {
|
||||
// Data is the content of the file.
|
||||
Data []byte `yaml:"-"`
|
||||
|
||||
// ID is automatically assigned when filter is added using nextFilterID.
|
||||
ID rulelist.URLFilterID `yaml:"id"`
|
||||
// ID is automatically assigned when filter is added.
|
||||
ID rules.ListID `yaml:"id"`
|
||||
}
|
||||
|
||||
// Reason holds an enum detailing why it was filtered or not filtered
|
||||
type Reason int
|
||||
|
||||
const (
|
||||
// reasons for not filtering
|
||||
|
||||
// NotFilteredNotFound - host was not find in any checks, default value for result
|
||||
NotFilteredNotFound Reason = iota
|
||||
// NotFilteredAllowList - the host is explicitly allowed
|
||||
NotFilteredAllowList
|
||||
// NotFilteredError is returned when there was an error during
|
||||
// checking. Reserved, currently unused.
|
||||
NotFilteredError
|
||||
|
||||
// reasons for filtering
|
||||
|
||||
// FilteredBlockList - the host was matched to be advertising host
|
||||
FilteredBlockList
|
||||
// FilteredSafeBrowsing - the host was matched to be malicious/phishing
|
||||
FilteredSafeBrowsing
|
||||
// FilteredParental - the host was matched to be outside of parental control settings
|
||||
FilteredParental
|
||||
// FilteredInvalid - the request was invalid and was not processed
|
||||
FilteredInvalid
|
||||
// FilteredSafeSearch - the host was replaced with safesearch variant
|
||||
FilteredSafeSearch
|
||||
// FilteredBlockedService - the host is blocked by "blocked services" settings
|
||||
FilteredBlockedService
|
||||
|
||||
// Rewritten is returned when there was a rewrite by a legacy DNS rewrite
|
||||
// rule.
|
||||
Rewritten
|
||||
|
||||
// RewrittenAutoHosts is returned when there was a rewrite by autohosts
|
||||
// rules (/etc/hosts and so on).
|
||||
RewrittenAutoHosts
|
||||
|
||||
// RewrittenRule is returned when a $dnsrewrite filter rule was applied.
|
||||
//
|
||||
// TODO(a.garipov): Remove Rewritten and RewrittenAutoHosts by merging their
|
||||
// functionality into RewrittenRule.
|
||||
//
|
||||
// See https://github.com/AdguardTeam/AdGuardHome/issues/2499.
|
||||
RewrittenRule
|
||||
)
|
||||
|
||||
// TODO(a.garipov): Resync with actual code names or replace completely
|
||||
// in HTTP API v1.
|
||||
var reasonNames = []string{
|
||||
NotFilteredNotFound: "NotFilteredNotFound",
|
||||
NotFilteredAllowList: "NotFilteredWhiteList",
|
||||
NotFilteredError: "NotFilteredError",
|
||||
|
||||
FilteredBlockList: "FilteredBlackList",
|
||||
FilteredSafeBrowsing: "FilteredSafeBrowsing",
|
||||
FilteredParental: "FilteredParental",
|
||||
FilteredInvalid: "FilteredInvalid",
|
||||
FilteredSafeSearch: "FilteredSafeSearch",
|
||||
FilteredBlockedService: "FilteredBlockedService",
|
||||
|
||||
Rewritten: "Rewrite",
|
||||
RewrittenAutoHosts: "RewriteEtcHosts",
|
||||
RewrittenRule: "RewriteRule",
|
||||
}
|
||||
|
||||
func (r Reason) String() string {
|
||||
if r < 0 || int(r) >= len(reasonNames) {
|
||||
return ""
|
||||
}
|
||||
|
||||
return reasonNames[r]
|
||||
}
|
||||
|
||||
// In returns true if reasons include r.
|
||||
func (r Reason) In(reasons ...Reason) (ok bool) { return slices.Contains(reasons, r) }
|
||||
|
||||
// SetEnabled sets the status of the *DNSFilter.
|
||||
func (d *DNSFilter) SetEnabled(enabled bool) {
|
||||
atomic.StoreUint32(&d.conf.enabled, mathutil.BoolToNumber[uint32](enabled))
|
||||
@ -556,54 +480,6 @@ func (d *DNSFilter) ParentalBlockHost() (host string) {
|
||||
return d.conf.ParentalBlockHost
|
||||
}
|
||||
|
||||
// ResultRule contains information about applied rules.
|
||||
type ResultRule struct {
|
||||
// Text is the text of the rule.
|
||||
Text string `json:",omitempty"`
|
||||
|
||||
// IP is the host IP. It is nil unless the rule uses the
|
||||
// /etc/hosts syntax or the reason is FilteredSafeSearch.
|
||||
IP netip.Addr `json:",omitempty"`
|
||||
|
||||
// FilterListID is the ID of the rule's filter list.
|
||||
FilterListID rulelist.URLFilterID `json:",omitempty"`
|
||||
}
|
||||
|
||||
// Result contains the result of a request check.
|
||||
//
|
||||
// All fields transitively have omitempty tags so that the query log doesn't
|
||||
// become too large.
|
||||
//
|
||||
// TODO(a.garipov): Clarify relationships between fields. Perhaps replace with
|
||||
// a sum type or an interface?
|
||||
type Result struct {
|
||||
// DNSRewriteResult is the $dnsrewrite filter rule result.
|
||||
DNSRewriteResult *DNSRewriteResult `json:",omitempty"`
|
||||
|
||||
// CanonName is the CNAME value from the lookup rewrite result. It is empty
|
||||
// unless Reason is set to Rewritten or RewrittenRule.
|
||||
CanonName string `json:",omitempty"`
|
||||
|
||||
// ServiceName is the name of the blocked service. It is empty unless
|
||||
// Reason is set to FilteredBlockedService.
|
||||
ServiceName string `json:",omitempty"`
|
||||
|
||||
// IPList is the lookup rewrite result. It is empty unless Reason is set to
|
||||
// Rewritten.
|
||||
IPList []netip.Addr `json:",omitempty"`
|
||||
|
||||
// Rules are applied rules. If Rules are not empty, each rule is not nil.
|
||||
Rules []*ResultRule `json:",omitempty"`
|
||||
|
||||
// Reason is the reason for blocking or unblocking the request.
|
||||
Reason Reason `json:",omitempty"`
|
||||
|
||||
// IsFiltered is true if the request is filtered.
|
||||
//
|
||||
// TODO(d.kolyshev): Get rid of this flag.
|
||||
IsFiltered bool `json:",omitempty"`
|
||||
}
|
||||
|
||||
// Matched returns true if any match at all was found regardless of
|
||||
// whether it was filtered or not.
|
||||
func (r Reason) Matched() bool {
|
||||
@ -741,7 +617,9 @@ func (d *DNSFilter) matchBlockedServicesRules(
|
||||
|
||||
ruleText := rule.Text()
|
||||
res.Rules = []*ResultRule{{
|
||||
FilterListID: rule.GetFilterListID(),
|
||||
// #nosec G115 -- The overflow is required for backwards
|
||||
// compatibility.
|
||||
FilterListID: rulelist.APIID(rule.GetFilterListID()),
|
||||
Text: ruleText,
|
||||
}}
|
||||
|
||||
@ -793,11 +671,9 @@ func newRuleStorage(filters []Filter) (rs *filterlist.RuleStorage, err error) {
|
||||
|
||||
// ruleListFromFilter returns a rule list from a Filter.
|
||||
func ruleListFromFilter(f Filter) (rl filterlist.Interface, skip bool, err error) {
|
||||
id := int(f.ID)
|
||||
|
||||
if len(f.Data) != 0 {
|
||||
return filterlist.NewBytes(&filterlist.BytesConfig{
|
||||
ID: id,
|
||||
ID: f.ID,
|
||||
RulesText: f.Data,
|
||||
IgnoreCosmetic: true,
|
||||
}), false, nil
|
||||
@ -819,14 +695,14 @@ func ruleListFromFilter(f Filter) (rl filterlist.Interface, skip bool, err error
|
||||
}
|
||||
|
||||
return filterlist.NewBytes(&filterlist.BytesConfig{
|
||||
ID: id,
|
||||
ID: f.ID,
|
||||
RulesText: data,
|
||||
IgnoreCosmetic: true,
|
||||
}), false, nil
|
||||
}
|
||||
|
||||
rl, err = filterlist.NewFile(&filterlist.FileConfig{
|
||||
ID: id,
|
||||
ID: f.ID,
|
||||
Path: f.FilePath,
|
||||
IgnoreCosmetic: true,
|
||||
})
|
||||
@ -1048,10 +924,7 @@ func (d *DNSFilter) matchHost(
|
||||
func makeResult(matchedRules []rules.Rule, reason Reason) (res Result) {
|
||||
resRules := make([]*ResultRule, len(matchedRules))
|
||||
for i, mr := range matchedRules {
|
||||
resRules[i] = &ResultRule{
|
||||
FilterListID: mr.GetFilterListID(),
|
||||
Text: mr.Text(),
|
||||
}
|
||||
resRules[i] = NewResultRule(mr)
|
||||
}
|
||||
|
||||
return Result{
|
||||
@ -1072,8 +945,9 @@ func New(c *Config, blockFilters []Filter) (d *DNSFilter, err error) {
|
||||
ctx := context.TODO()
|
||||
|
||||
d = &DNSFilter{
|
||||
logger: c.Logger,
|
||||
idGen: newIDGenerator(int32(time.Now().Unix()), c.Logger),
|
||||
logger: c.Logger,
|
||||
// #nosec G115 -- The Unix epoch time is highly unlikely to be negative.
|
||||
idGen: newIDGenerator(uint64(time.Now().Unix()), c.Logger),
|
||||
bufPool: syncutil.NewSlicePool[byte](rulelist.DefaultRuleBufSize),
|
||||
safeSearch: c.SafeSearch,
|
||||
refreshLock: &sync.Mutex{},
|
||||
@ -1253,7 +1127,7 @@ func (d *DNSFilter) checkSafeBrowsing(
|
||||
res = Result{
|
||||
Rules: []*ResultRule{{
|
||||
Text: "adguard-malware-shavar",
|
||||
FilterListID: rulelist.URLFilterIDSafeBrowsing,
|
||||
FilterListID: rulelist.APIIDSafeBrowsing,
|
||||
}},
|
||||
Reason: FilteredSafeBrowsing,
|
||||
IsFiltered: true,
|
||||
@ -1289,7 +1163,7 @@ func (d *DNSFilter) checkParental(
|
||||
res = Result{
|
||||
Rules: []*ResultRule{{
|
||||
Text: "parental CATEGORY_BLACKLISTED",
|
||||
FilterListID: rulelist.URLFilterIDParentalControl,
|
||||
FilterListID: rulelist.APIIDParentalControl,
|
||||
}},
|
||||
Reason: FilteredParental,
|
||||
IsFiltered: true,
|
||||
|
||||
@ -21,6 +21,8 @@ type cacheItem struct {
|
||||
// toCacheItem decodes cacheItem from data. data must be at least equal to
|
||||
// expiry size.
|
||||
func toCacheItem(data []byte) *cacheItem {
|
||||
// #nosec G115 -- Assume that the values are as the ones that have been
|
||||
// encoded.
|
||||
t := time.Unix(int64(binary.BigEndian.Uint64(data)), 0)
|
||||
|
||||
data = data[expirySize:]
|
||||
@ -43,6 +45,7 @@ func fromCacheItem(item *cacheItem) (data []byte) {
|
||||
data = make([]byte, 0, len(item.hashes)*hashSize+expirySize)
|
||||
|
||||
expiry := item.expiry.Unix()
|
||||
// #nosec G115 -- The Unix epoch time is highly unlikely to be negative.
|
||||
data = binary.BigEndian.AppendUint64(data, uint64(expiry))
|
||||
|
||||
for _, v := range item.hashes {
|
||||
|
||||
@ -75,7 +75,7 @@ func (d *DNSFilter) hostsRewrites(
|
||||
vals = append(vals, name)
|
||||
rls = append(rls, &ResultRule{
|
||||
Text: fmt.Sprintf("%s %s", addr, name),
|
||||
FilterListID: rulelist.URLFilterIDEtcHosts,
|
||||
FilterListID: rulelist.APIIDEtcHosts,
|
||||
})
|
||||
}
|
||||
|
||||
@ -97,7 +97,7 @@ func (d *DNSFilter) hostsRewrites(
|
||||
}
|
||||
rls = append(rls, &ResultRule{
|
||||
Text: fmt.Sprintf("%s %s", addr, host),
|
||||
FilterListID: rulelist.URLFilterIDEtcHosts,
|
||||
FilterListID: rulelist.APIIDEtcHosts,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -76,7 +76,7 @@ func TestDNSFilter_CheckHost_hostsContainer(t *testing.T) {
|
||||
dtyp: dns.TypeA,
|
||||
wantRules: []*filtering.ResultRule{{
|
||||
Text: "1.2.3.4 v4.host.example",
|
||||
FilterListID: rulelist.URLFilterIDEtcHosts,
|
||||
FilterListID: rulelist.APIIDEtcHosts,
|
||||
}},
|
||||
wantResps: []rules.RRValue{addrv4},
|
||||
}, {
|
||||
@ -85,7 +85,7 @@ func TestDNSFilter_CheckHost_hostsContainer(t *testing.T) {
|
||||
dtyp: dns.TypeAAAA,
|
||||
wantRules: []*filtering.ResultRule{{
|
||||
Text: "::1 v6.host.example",
|
||||
FilterListID: rulelist.URLFilterIDEtcHosts,
|
||||
FilterListID: rulelist.APIIDEtcHosts,
|
||||
}},
|
||||
wantResps: []rules.RRValue{addrv6},
|
||||
}, {
|
||||
@ -94,7 +94,7 @@ func TestDNSFilter_CheckHost_hostsContainer(t *testing.T) {
|
||||
dtyp: dns.TypeAAAA,
|
||||
wantRules: []*filtering.ResultRule{{
|
||||
Text: "::ffff:1.2.3.4 mapped.host.example",
|
||||
FilterListID: rulelist.URLFilterIDEtcHosts,
|
||||
FilterListID: rulelist.APIIDEtcHosts,
|
||||
}},
|
||||
wantResps: []rules.RRValue{addrMapped},
|
||||
}, {
|
||||
@ -103,7 +103,7 @@ func TestDNSFilter_CheckHost_hostsContainer(t *testing.T) {
|
||||
dtyp: dns.TypePTR,
|
||||
wantRules: []*filtering.ResultRule{{
|
||||
Text: "1.2.3.4 v4.host.example",
|
||||
FilterListID: rulelist.URLFilterIDEtcHosts,
|
||||
FilterListID: rulelist.APIIDEtcHosts,
|
||||
}},
|
||||
wantResps: []rules.RRValue{"v4.host.example"},
|
||||
}, {
|
||||
@ -112,7 +112,7 @@ func TestDNSFilter_CheckHost_hostsContainer(t *testing.T) {
|
||||
dtyp: dns.TypePTR,
|
||||
wantRules: []*filtering.ResultRule{{
|
||||
Text: "::ffff:1.2.3.4 mapped.host.example",
|
||||
FilterListID: rulelist.URLFilterIDEtcHosts,
|
||||
FilterListID: rulelist.APIIDEtcHosts,
|
||||
}},
|
||||
wantResps: []rules.RRValue{"mapped.host.example"},
|
||||
}, {
|
||||
@ -139,7 +139,7 @@ func TestDNSFilter_CheckHost_hostsContainer(t *testing.T) {
|
||||
dtyp: dns.TypeAAAA,
|
||||
wantRules: []*filtering.ResultRule{{
|
||||
Text: fmt.Sprintf("%s v4.host.example", addrv4),
|
||||
FilterListID: rulelist.URLFilterIDEtcHosts,
|
||||
FilterListID: rulelist.APIIDEtcHosts,
|
||||
}},
|
||||
wantResps: nil,
|
||||
}, {
|
||||
@ -148,7 +148,7 @@ func TestDNSFilter_CheckHost_hostsContainer(t *testing.T) {
|
||||
dtyp: dns.TypeA,
|
||||
wantRules: []*filtering.ResultRule{{
|
||||
Text: fmt.Sprintf("%s v6.host.example", addrv6),
|
||||
FilterListID: rulelist.URLFilterIDEtcHosts,
|
||||
FilterListID: rulelist.APIIDEtcHosts,
|
||||
}},
|
||||
wantResps: nil,
|
||||
}, {
|
||||
@ -169,7 +169,7 @@ func TestDNSFilter_CheckHost_hostsContainer(t *testing.T) {
|
||||
dtyp: dns.TypeA,
|
||||
wantRules: []*filtering.ResultRule{{
|
||||
Text: "4.3.2.1 v4.host.with-dup",
|
||||
FilterListID: rulelist.URLFilterIDEtcHosts,
|
||||
FilterListID: rulelist.APIIDEtcHosts,
|
||||
}},
|
||||
wantResps: []rules.RRValue{addrv4Dup},
|
||||
}}
|
||||
|
||||
@ -401,12 +401,14 @@ func (d *DNSFilter) handleFilteringRefresh(w http.ResponseWriter, r *http.Reques
|
||||
}
|
||||
|
||||
type filterJSON struct {
|
||||
URL string `json:"url"`
|
||||
Name string `json:"name"`
|
||||
LastUpdated string `json:"last_updated,omitempty"`
|
||||
ID rulelist.URLFilterID `json:"id"`
|
||||
RulesCount uint32 `json:"rules_count"`
|
||||
Enabled bool `json:"enabled"`
|
||||
URL string `json:"url"`
|
||||
Name string `json:"name"`
|
||||
LastUpdated string `json:"last_updated,omitempty"`
|
||||
|
||||
ID rulelist.APIID `json:"id"`
|
||||
|
||||
RulesCount uint64 `json:"rules_count"`
|
||||
Enabled bool `json:"enabled"`
|
||||
}
|
||||
|
||||
type filteringConfig struct {
|
||||
@ -419,11 +421,13 @@ type filteringConfig struct {
|
||||
|
||||
func filterToJSON(f FilterYAML) filterJSON {
|
||||
fj := filterJSON{
|
||||
ID: f.ID,
|
||||
Enabled: f.Enabled,
|
||||
URL: f.URL,
|
||||
Name: f.Name,
|
||||
RulesCount: uint32(f.RulesCount),
|
||||
// #nosec G115 -- The overflow is required for backwards compatibility.
|
||||
ID: rulelist.APIID(f.ID),
|
||||
Enabled: f.Enabled,
|
||||
URL: f.URL,
|
||||
Name: f.Name,
|
||||
// #nosec G115 -- The number of rules must not be negative.
|
||||
RulesCount: uint64(f.RulesCount),
|
||||
}
|
||||
|
||||
if !f.LastUpdated.IsZero() {
|
||||
@ -485,8 +489,9 @@ func (d *DNSFilter) handleFilteringConfig(w http.ResponseWriter, r *http.Request
|
||||
}
|
||||
|
||||
type checkHostRespRule struct {
|
||||
Text string `json:"text"`
|
||||
FilterListID rulelist.URLFilterID `json:"filter_list_id"`
|
||||
Text string `json:"text"`
|
||||
|
||||
FilterListID rulelist.APIID `json:"filter_list_id"`
|
||||
}
|
||||
|
||||
type checkHostResp struct {
|
||||
@ -509,7 +514,7 @@ type checkHostResp struct {
|
||||
// FilterID is the ID of the rule's filter list.
|
||||
//
|
||||
// Deprecated: Use Rules[*].FilterListID.
|
||||
FilterID rulelist.URLFilterID `json:"filter_id"`
|
||||
FilterID rulelist.APIID `json:"filter_id"`
|
||||
}
|
||||
|
||||
// handleCheckHost is the handler for the GET /control/filtering/check_host HTTP
|
||||
|
||||
@ -6,8 +6,8 @@ import (
|
||||
"log/slog"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/filtering/rulelist"
|
||||
"github.com/AdguardTeam/golibs/container"
|
||||
"github.com/AdguardTeam/urlfilter/rules"
|
||||
)
|
||||
|
||||
// idGenerator generates filtering-list IDs in a way broadly compatible with the
|
||||
@ -16,15 +16,15 @@ import (
|
||||
// TODO(a.garipov): Get rid of this once we switch completely to the new
|
||||
// rule-list architecture.
|
||||
type idGenerator struct {
|
||||
current *atomic.Int32
|
||||
current *atomic.Uint64
|
||||
logger *slog.Logger
|
||||
}
|
||||
|
||||
// newIDGenerator returns a new ID generator initialized with the given seed
|
||||
// value.
|
||||
func newIDGenerator(seed int32, l *slog.Logger) (g *idGenerator) {
|
||||
// value. l must not be nil.
|
||||
func newIDGenerator(seed uint64, l *slog.Logger) (g *idGenerator) {
|
||||
g = &idGenerator{
|
||||
current: &atomic.Int32{},
|
||||
current: &atomic.Uint64{},
|
||||
logger: l,
|
||||
}
|
||||
|
||||
@ -34,18 +34,18 @@ func newIDGenerator(seed int32, l *slog.Logger) (g *idGenerator) {
|
||||
}
|
||||
|
||||
// next returns the next ID from the generator. It is safe for concurrent use.
|
||||
func (g *idGenerator) next() (id rulelist.URLFilterID) {
|
||||
id32 := g.current.Add(1)
|
||||
if id32 < 0 {
|
||||
panic(fmt.Errorf("invalid current id value %d", id32))
|
||||
func (g *idGenerator) next() (id rules.ListID) {
|
||||
id64 := g.current.Add(1)
|
||||
if id64 == 0 {
|
||||
panic(fmt.Errorf("invalid current id value %d", id64))
|
||||
}
|
||||
|
||||
return rulelist.URLFilterID(id32)
|
||||
return rules.ListID(id64)
|
||||
}
|
||||
|
||||
// fix ensures that flts all have unique IDs.
|
||||
func (g *idGenerator) fix(flts []FilterYAML) {
|
||||
set := container.NewMapSet[rulelist.URLFilterID]()
|
||||
set := container.NewMapSet[rules.ListID]()
|
||||
for i, f := range flts {
|
||||
id := f.ID
|
||||
if id == 0 {
|
||||
|
||||
@ -4,8 +4,8 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghalg"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/filtering/rulelist"
|
||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||
"github.com/AdguardTeam/urlfilter/rules"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
@ -78,7 +78,7 @@ func TestIDGenerator_Fix(t *testing.T) {
|
||||
func assertUniqueIDs(tb testing.TB, flts []FilterYAML) {
|
||||
tb.Helper()
|
||||
|
||||
uc := aghalg.UniqChecker[rulelist.URLFilterID]{}
|
||||
uc := aghalg.UniqChecker[rules.ListID]{}
|
||||
for _, f := range flts {
|
||||
uc.Add(f.ID)
|
||||
}
|
||||
|
||||
152
internal/filtering/result.go
Normal file
152
internal/filtering/result.go
Normal file
@ -0,0 +1,152 @@
|
||||
package filtering
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/netip"
|
||||
"slices"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/filtering/rulelist"
|
||||
"github.com/AdguardTeam/urlfilter/rules"
|
||||
)
|
||||
|
||||
// Result contains the result of a request check. All fields transitively have
|
||||
// omitempty tags so that the query log doesn't become too large.
|
||||
//
|
||||
// TODO(a.garipov): Clarify relationships between fields. Perhaps replace with
|
||||
// a sum type or an interface?
|
||||
type Result struct {
|
||||
// DNSRewriteResult is the $dnsrewrite filter rule result.
|
||||
DNSRewriteResult *DNSRewriteResult `json:",omitempty"`
|
||||
|
||||
// CanonName is the CNAME value from the lookup rewrite result. It is empty
|
||||
// unless Reason is set to Rewritten or RewrittenRule.
|
||||
CanonName string `json:",omitempty"`
|
||||
|
||||
// ServiceName is the name of the blocked service. It is empty unless
|
||||
// Reason is set to FilteredBlockedService.
|
||||
ServiceName string `json:",omitempty"`
|
||||
|
||||
// IPList is the lookup rewrite result. It is empty unless Reason is set to
|
||||
// Rewritten.
|
||||
IPList []netip.Addr `json:",omitempty"`
|
||||
|
||||
// Rules are applied rules. If Rules are not empty, each rule is not nil.
|
||||
Rules []*ResultRule `json:",omitempty"`
|
||||
|
||||
// Reason is the reason for blocking or unblocking the request.
|
||||
Reason Reason `json:",omitempty"`
|
||||
|
||||
// IsFiltered is true if the request is filtered.
|
||||
//
|
||||
// TODO(d.kolyshev): Get rid of this flag.
|
||||
IsFiltered bool `json:",omitempty"`
|
||||
}
|
||||
|
||||
// ResultRule contains information about applied rules.
|
||||
type ResultRule struct {
|
||||
// Text is the text of the rule.
|
||||
Text string `json:",omitempty"`
|
||||
|
||||
// IP is the host IP. It is nil unless the rule uses the /etc/hosts syntax
|
||||
// or the reason is [FilteredSafeSearch].
|
||||
IP netip.Addr `json:",omitzero"`
|
||||
|
||||
// FilterListID is the ID of the rule's filter list.
|
||||
FilterListID rulelist.APIID `json:",omitempty"`
|
||||
}
|
||||
|
||||
// NewResultRule converts an URLFilter rule into a *ResultRule. nr must not be
|
||||
// nil.
|
||||
func NewResultRule(r rules.Rule) (rr *ResultRule) {
|
||||
return &ResultRule{
|
||||
// #nosec G115 -- The overflow is required for backwards
|
||||
// compatibility.
|
||||
FilterListID: rulelist.APIID(r.GetFilterListID()),
|
||||
Text: r.Text(),
|
||||
}
|
||||
}
|
||||
|
||||
// Reason holds an enum detailing why it was filtered or not filtered
|
||||
type Reason int
|
||||
|
||||
const (
|
||||
// NotFilteredNotFound: the host was not find in any checks, default value
|
||||
// for results.
|
||||
NotFilteredNotFound Reason = iota
|
||||
|
||||
// NotFilteredAllowList: the host is explicitly allowed.
|
||||
NotFilteredAllowList
|
||||
|
||||
// NotFilteredError is returned when there was an error during checking.
|
||||
// Reserved, currently unused.
|
||||
NotFilteredError
|
||||
|
||||
// FilteredBlockList: the host was matched to be advertising host.
|
||||
FilteredBlockList
|
||||
|
||||
// FilteredSafeBrowsing: the host was matched to be malicious/phishing.
|
||||
FilteredSafeBrowsing
|
||||
|
||||
// FilteredParental: the host was matched to be outside of parental control
|
||||
// settings.
|
||||
FilteredParental
|
||||
|
||||
// FilteredInvalid: the request was invalid and was not processed.
|
||||
FilteredInvalid
|
||||
|
||||
// FilteredSafeSearch: the host was replaced with safesearch variant.
|
||||
FilteredSafeSearch
|
||||
|
||||
// FilteredBlockedService: the host is blocked by the blocked services
|
||||
// feature.
|
||||
FilteredBlockedService
|
||||
|
||||
// Rewritten is returned when there was a rewrite by a legacy DNS rewrite
|
||||
// rule.
|
||||
Rewritten
|
||||
|
||||
// RewrittenAutoHosts is returned when there was a rewrite by /etc/hosts.
|
||||
RewrittenAutoHosts
|
||||
|
||||
// RewrittenRule is returned when a $dnsrewrite filter rule was applied.
|
||||
//
|
||||
// TODO(a.garipov): Remove [Rewritten] and [RewrittenAutoHosts] by merging
|
||||
// their functionality into RewrittenRule.
|
||||
//
|
||||
// See https://github.com/AdguardTeam/AdGuardHome/issues/2499.
|
||||
RewrittenRule
|
||||
)
|
||||
|
||||
// TODO(a.garipov): Resync with actual code names or replace completely in HTTP
|
||||
// API v1.
|
||||
var reasonNames = []string{
|
||||
NotFilteredNotFound: "NotFilteredNotFound",
|
||||
NotFilteredAllowList: "NotFilteredWhiteList",
|
||||
NotFilteredError: "NotFilteredError",
|
||||
|
||||
FilteredBlockList: "FilteredBlackList",
|
||||
FilteredSafeBrowsing: "FilteredSafeBrowsing",
|
||||
FilteredParental: "FilteredParental",
|
||||
FilteredInvalid: "FilteredInvalid",
|
||||
FilteredSafeSearch: "FilteredSafeSearch",
|
||||
FilteredBlockedService: "FilteredBlockedService",
|
||||
|
||||
Rewritten: "Rewrite",
|
||||
RewrittenAutoHosts: "RewriteEtcHosts",
|
||||
RewrittenRule: "RewriteRule",
|
||||
}
|
||||
|
||||
// type check
|
||||
var _ fmt.Stringer = NotFilteredNotFound
|
||||
|
||||
// String implements the [fmt.Stringer] interface for Reason.
|
||||
func (r Reason) String() (s string) {
|
||||
if r < 0 || int(r) >= len(reasonNames) {
|
||||
return ""
|
||||
}
|
||||
|
||||
return reasonNames[r]
|
||||
}
|
||||
|
||||
// In returns true if reasons include r.
|
||||
func (r Reason) In(reasons ...Reason) (ok bool) { return slices.Contains(reasons, r) }
|
||||
@ -40,7 +40,7 @@ type Config struct {
|
||||
Rewrites []*Item
|
||||
|
||||
// ListID is used as an identifier of the underlying rules list.
|
||||
ListID int
|
||||
ListID rules.ListID
|
||||
}
|
||||
|
||||
// DefaultStorage is the default storage for rewrite rules.
|
||||
@ -61,10 +61,7 @@ type DefaultStorage struct {
|
||||
rewrites []*Item
|
||||
|
||||
// urlFilterID is the synthetic integer identifier for the urlfilter engine.
|
||||
//
|
||||
// TODO(a.garipov): Change the type to a string in module urlfilter and
|
||||
// remove this crutch.
|
||||
urlFilterID int
|
||||
urlFilterID rules.ListID
|
||||
}
|
||||
|
||||
// NewDefaultStorage returns new rewrites storage. conf must not be nil.
|
||||
@ -140,7 +137,7 @@ func (s *DefaultStorage) resolveCNAMEChain(
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if isSelfMatchingWildcard(host, rwAns, rule.RuleText) {
|
||||
if isSelfMatchingWildcard(host, rwAns, rule.Text()) {
|
||||
return nil, rule.DNSRewrite
|
||||
}
|
||||
|
||||
|
||||
@ -13,6 +13,9 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// testListID is the common rule-list ID for tests.
|
||||
const testListID rules.ListID = 1
|
||||
|
||||
func TestNewDefaultStorage(t *testing.T) {
|
||||
items := []*Item{{
|
||||
Domain: "example.com",
|
||||
@ -22,7 +25,7 @@ func TestNewDefaultStorage(t *testing.T) {
|
||||
s, err := NewDefaultStorage(&Config{
|
||||
Logger: slogutil.NewDiscardLogger(),
|
||||
Rewrites: items,
|
||||
ListID: -1,
|
||||
ListID: testListID,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
@ -35,7 +38,7 @@ func TestDefaultStorage_CRUD(t *testing.T) {
|
||||
s, err := NewDefaultStorage(&Config{
|
||||
Logger: slogutil.NewDiscardLogger(),
|
||||
Rewrites: items,
|
||||
ListID: -1,
|
||||
ListID: testListID,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Len(t, s.List(), 0)
|
||||
@ -124,7 +127,7 @@ func TestDefaultStorage_MatchRequest(t *testing.T) {
|
||||
s, err := NewDefaultStorage(&Config{
|
||||
Logger: slogutil.NewDiscardLogger(),
|
||||
Rewrites: items,
|
||||
ListID: -1,
|
||||
ListID: testListID,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
@ -300,7 +303,7 @@ func TestDefaultStorage_MatchRequest_Levels(t *testing.T) {
|
||||
s, err := NewDefaultStorage(&Config{
|
||||
Logger: slogutil.NewDiscardLogger(),
|
||||
Rewrites: items,
|
||||
ListID: -1,
|
||||
ListID: testListID,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
@ -372,7 +375,7 @@ func TestDefaultStorage_MatchRequest_ExceptionCNAME(t *testing.T) {
|
||||
s, err := NewDefaultStorage(&Config{
|
||||
Logger: slogutil.NewDiscardLogger(),
|
||||
Rewrites: items,
|
||||
ListID: -1,
|
||||
ListID: testListID,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
@ -440,7 +443,7 @@ func TestDefaultStorage_MatchRequest_ExceptionIP(t *testing.T) {
|
||||
s, err := NewDefaultStorage(&Config{
|
||||
Logger: slogutil.NewDiscardLogger(),
|
||||
Rewrites: items,
|
||||
ListID: -1,
|
||||
ListID: testListID,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
|
||||
@ -16,6 +16,7 @@ import (
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/ioutil"
|
||||
"github.com/AdguardTeam/urlfilter/filterlist"
|
||||
"github.com/AdguardTeam/urlfilter/rules"
|
||||
"github.com/c2h5oh/datasize"
|
||||
)
|
||||
|
||||
@ -42,7 +43,7 @@ type Filter struct {
|
||||
uid UID
|
||||
|
||||
// urlFilterID is used for working with package urlfilter.
|
||||
urlFilterID URLFilterID
|
||||
urlFilterID rules.ListID
|
||||
|
||||
// rulesCount contains the number of rules in this rule-list filter.
|
||||
rulesCount int
|
||||
@ -72,7 +73,7 @@ type FilterConfig struct {
|
||||
UID UID
|
||||
|
||||
// URLFilterID is used for working with package urlfilter.
|
||||
URLFilterID URLFilterID
|
||||
URLFilterID rules.ListID
|
||||
|
||||
// Enabled, if true, means that this rule-list filter is used for filtering.
|
||||
Enabled bool
|
||||
@ -154,16 +155,15 @@ func (f *Filter) setFromHTTP(
|
||||
) (parseRes *ParseResult, err error) {
|
||||
defer func() { err = errors.Annotate(err, "setting from http: %w") }()
|
||||
|
||||
text, parseRes, err := f.readFromHTTP(ctx, parseBuf, cli, cachePath, maxSize)
|
||||
data, parseRes, err := f.readFromHTTP(ctx, parseBuf, cli, cachePath, maxSize)
|
||||
if err != nil {
|
||||
// Don't wrap the error, because it's informative enough as is.
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TODO(a.garipov): Add filterlist.BytesRuleList.
|
||||
f.ruleList = filterlist.NewString(&filterlist.StringConfig{
|
||||
f.ruleList = filterlist.NewBytes(&filterlist.BytesConfig{
|
||||
ID: f.urlFilterID,
|
||||
RulesText: text,
|
||||
RulesText: data,
|
||||
IgnoreCosmetic: true,
|
||||
})
|
||||
|
||||
@ -179,27 +179,27 @@ func (f *Filter) readFromHTTP(
|
||||
cli *http.Client,
|
||||
cachePath string,
|
||||
maxSize uint64,
|
||||
) (text string, parseRes *ParseResult, err error) {
|
||||
) (data []byte, parseRes *ParseResult, err error) {
|
||||
urlStr := f.url.String()
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, urlStr, nil)
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("making request for http url %q: %w", urlStr, err)
|
||||
return nil, nil, fmt.Errorf("making request for http url %q: %w", urlStr, err)
|
||||
}
|
||||
|
||||
resp, err := cli.Do(req)
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("requesting from http url: %w", err)
|
||||
return nil, nil, fmt.Errorf("requesting from http url: %w", err)
|
||||
}
|
||||
defer func() { err = errors.WithDeferred(err, resp.Body.Close()) }()
|
||||
|
||||
// TODO(a.garipov): Use [agdhttp.CheckStatus] when it's moved to golibs.
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return "", nil, fmt.Errorf("got status code %d, want %d", resp.StatusCode, http.StatusOK)
|
||||
return nil, nil, fmt.Errorf("got status code %d, want %d", resp.StatusCode, http.StatusOK)
|
||||
}
|
||||
|
||||
fltFile, err := aghrenameio.NewPendingFile(cachePath, aghos.DefaultPermFile)
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("creating temp file: %w", err)
|
||||
return nil, nil, fmt.Errorf("creating temp file: %w", err)
|
||||
}
|
||||
defer func() { err = aghrenameio.WithDeferredCleanup(err, fltFile) }()
|
||||
|
||||
@ -210,10 +210,10 @@ func (f *Filter) readFromHTTP(
|
||||
httpBody := ioutil.LimitReader(resp.Body, maxSize)
|
||||
parseRes, err = parser.Parse(mw, httpBody, parseBuf)
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("parsing response from http url %q: %w", urlStr, err)
|
||||
return nil, nil, fmt.Errorf("parsing response from http url %q: %w", urlStr, err)
|
||||
}
|
||||
|
||||
return buf.String(), parseRes, nil
|
||||
return buf.Bytes(), parseRes, nil
|
||||
}
|
||||
|
||||
// setName sets the title using either the already-present name, the given title
|
||||
|
||||
@ -6,7 +6,9 @@ package rulelist
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
"github.com/AdguardTeam/urlfilter/rules"
|
||||
"github.com/c2h5oh/datasize"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
@ -21,26 +23,33 @@ const DefaultRuleBufSize = 1024
|
||||
// DefaultMaxRuleListSize is the default maximum filtering-rule list size.
|
||||
const DefaultMaxRuleListSize = 64 * datasize.MB
|
||||
|
||||
// URLFilterID is a semantic type-alias for IDs used for working with package
|
||||
// urlfilter.
|
||||
type URLFilterID = int
|
||||
// APIID is the type for the rule-list IDs used in the HTTP API.
|
||||
type APIID int64
|
||||
|
||||
// The IDs of built-in filter lists.
|
||||
// The IDs of built-in filter lists for the HTTP API.
|
||||
//
|
||||
// NOTE: Do not change without the need for it and keep in sync with
|
||||
// NOTE: Do not change without the need for it and keep in sync with
|
||||
// client/src/helpers/constants.ts.
|
||||
const (
|
||||
APIIDCustom APIID = 0
|
||||
APIIDEtcHosts APIID = -1
|
||||
APIIDBlockedService APIID = -2
|
||||
APIIDParentalControl APIID = -3
|
||||
APIIDSafeBrowsing APIID = -4
|
||||
APIIDSafeSearch APIID = -5
|
||||
)
|
||||
|
||||
// The IDs of built-in filter lists. The IDs for the blocked-service and the
|
||||
// safe-search filters are chosen so that they equal to their [APIID]
|
||||
// counterparts when converted to it.
|
||||
//
|
||||
// TODO(a.garipov): Add type [URLFilterID] once it is used consistently in
|
||||
// package filtering.
|
||||
// NOTE: Keep in sync with [APIIDCustom] etc.
|
||||
//
|
||||
// TODO(d.kolyshev): Add URLFilterIDLegacyRewrite here and to the UI.
|
||||
const (
|
||||
URLFilterIDCustom URLFilterID = 0
|
||||
URLFilterIDEtcHosts URLFilterID = -1
|
||||
URLFilterIDBlockedService URLFilterID = -2
|
||||
URLFilterIDParentalControl URLFilterID = -3
|
||||
URLFilterIDSafeBrowsing URLFilterID = -4
|
||||
URLFilterIDSafeSearch URLFilterID = -5
|
||||
IDCustom rules.ListID = rules.ListID(APIIDCustom)
|
||||
IDBlockedService rules.ListID = math.MaxUint64 - rules.ListID(-APIIDBlockedService) + 1
|
||||
IDSafeSearch rules.ListID = math.MaxUint64 - rules.ListID(-APIIDSafeSearch) + 1
|
||||
)
|
||||
|
||||
// UID is the type for the unique IDs of filtering-rule lists.
|
||||
|
||||
@ -13,14 +13,16 @@ import (
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/filtering/rulelist"
|
||||
"github.com/AdguardTeam/golibs/netutil/urlutil"
|
||||
"github.com/AdguardTeam/golibs/testutil"
|
||||
"github.com/AdguardTeam/urlfilter/rules"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// testTimeout is the common timeout for tests.
|
||||
const testTimeout = 1 * time.Second
|
||||
|
||||
// testURLFilterID is the common [rulelist.URLFilterID] for tests.
|
||||
const testURLFilterID rulelist.URLFilterID = 1
|
||||
// testURLFilterID is the common rules.ListID for tests.
|
||||
const testURLFilterID rules.ListID = 1
|
||||
|
||||
// testTitle is the common title for tests.
|
||||
const testTitle = "Test Title"
|
||||
@ -42,11 +44,11 @@ const (
|
||||
)
|
||||
|
||||
// urlFilterIDCounter is the atomic integer used to create unique filter IDs.
|
||||
var urlFilterIDCounter = &atomic.Int32{}
|
||||
var urlFilterIDCounter = &atomic.Uint64{}
|
||||
|
||||
// newURLFilterID returns a new unique URLFilterID.
|
||||
func newURLFilterID() (id rulelist.URLFilterID) {
|
||||
return rulelist.URLFilterID(urlFilterIDCounter.Add(1))
|
||||
func newURLFilterID() (id rules.ListID) {
|
||||
return rules.ListID(urlFilterIDCounter.Add(1))
|
||||
}
|
||||
|
||||
// newFilter is a helper for creating new filters in tests. It does not
|
||||
@ -115,3 +117,15 @@ func newStringHTTPServer(s string) (srv *httptest.Server) {
|
||||
require.NoError(pt, err)
|
||||
}))
|
||||
}
|
||||
|
||||
func TestIDs(t *testing.T) {
|
||||
// Use a variable to prevent compilation errors.
|
||||
id := rulelist.IDCustom
|
||||
assert.Equal(t, rulelist.APIIDCustom, rulelist.APIID(id))
|
||||
|
||||
id = rulelist.IDBlockedService
|
||||
assert.Equal(t, rulelist.APIIDBlockedService, rulelist.APIID(id))
|
||||
|
||||
id = rulelist.IDSafeSearch
|
||||
assert.Equal(t, rulelist.APIIDSafeSearch, rulelist.APIID(id))
|
||||
}
|
||||
|
||||
@ -40,11 +40,13 @@ type StorageConfig struct {
|
||||
CacheDir string
|
||||
|
||||
// AllowFilters are the filtering-rule lists used to exclude domain names
|
||||
// from the filtering. Each item must not be nil.
|
||||
// from the filtering. Each item must not be nil and must have unique IDs
|
||||
// between AllowFilters and BlockFilters.
|
||||
AllowFilters []*Filter
|
||||
|
||||
// BlockFilters are the filtering-rule lists used to block domain names.
|
||||
// Each item must not be nil.
|
||||
// Each item must not be nil and must have unique IDs between AllowFilters
|
||||
// and BlockFilters.
|
||||
BlockFilters []*Filter
|
||||
|
||||
// CustomRules contains custom rules of the user. They have priority over
|
||||
@ -62,7 +64,7 @@ func NewStorage(c *StorageConfig) (s *Storage, err error) {
|
||||
custom, err := NewTextEngine(&TextEngineConfig{
|
||||
Name: EngineNameCustom,
|
||||
Rules: c.CustomRules,
|
||||
ID: URLFilterIDCustom,
|
||||
ID: IDCustom,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("creating custom engine: %w", err)
|
||||
|
||||
@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/AdguardTeam/urlfilter"
|
||||
"github.com/AdguardTeam/urlfilter/filterlist"
|
||||
"github.com/AdguardTeam/urlfilter/rules"
|
||||
)
|
||||
|
||||
// TextEngine is a single DNS filter based on a list of rules in text form.
|
||||
@ -35,7 +36,7 @@ type TextEngineConfig struct {
|
||||
Rules []string
|
||||
|
||||
// ID is the ID to use inside a URL-filter engine.
|
||||
ID URLFilterID
|
||||
ID rules.ListID
|
||||
}
|
||||
|
||||
// NewTextEngine returns a new rule-list filtering engine that uses rules
|
||||
|
||||
@ -38,5 +38,5 @@ func TestNewTextEngine(t *testing.T) {
|
||||
require.NotNil(t, fltRes)
|
||||
require.NotNil(t, fltRes.NetworkRule)
|
||||
|
||||
assert.Equal(t, fltRes.NetworkRule.FilterListID, testURLFilterID)
|
||||
assert.Equal(t, fltRes.NetworkRule.GetFilterListID(), testURLFilterID)
|
||||
}
|
||||
|
||||
@ -120,7 +120,7 @@ func NewDefault(ctx context.Context, conf *DefaultConfig) (ss *Default, err erro
|
||||
}
|
||||
|
||||
// TODO(s.chzhen): Move to [Default.InitialRefresh].
|
||||
err = ss.resetEngine(ctx, rulelist.URLFilterIDSafeSearch, conf.ServicesConfig)
|
||||
err = ss.resetEngine(ctx, rulelist.IDSafeSearch, conf.ServicesConfig)
|
||||
if err != nil {
|
||||
// Don't wrap the error, because it's informative enough as is.
|
||||
return nil, err
|
||||
@ -133,7 +133,7 @@ func NewDefault(ctx context.Context, conf *DefaultConfig) (ss *Default, err erro
|
||||
// sets it in ss.
|
||||
func (ss *Default) resetEngine(
|
||||
ctx context.Context,
|
||||
listID int,
|
||||
id rules.ListID,
|
||||
conf filtering.SafeSearchConfig,
|
||||
) (err error) {
|
||||
if !conf.Enabled {
|
||||
@ -151,7 +151,7 @@ func (ss *Default) resetEngine(
|
||||
|
||||
strList := []filterlist.Interface{
|
||||
filterlist.NewString(&filterlist.StringConfig{
|
||||
ID: listID,
|
||||
ID: id,
|
||||
RulesText: sb.String(),
|
||||
IgnoreCosmetic: true,
|
||||
}),
|
||||
@ -260,7 +260,7 @@ func (ss *Default) newResult(
|
||||
}
|
||||
|
||||
res.Rules = []*filtering.ResultRule{{
|
||||
FilterListID: rulelist.URLFilterIDSafeSearch,
|
||||
FilterListID: rulelist.APIIDSafeSearch,
|
||||
IP: ip,
|
||||
}}
|
||||
|
||||
@ -274,12 +274,16 @@ func (ss *Default) newResult(
|
||||
|
||||
// setCacheResult stores data in cache for host. qtype is expected to be either
|
||||
// [dns.TypeA] or [dns.TypeAAAA].
|
||||
//
|
||||
// TODO(a.garipov): Remove gob and use uint64.
|
||||
func (ss *Default) setCacheResult(
|
||||
ctx context.Context,
|
||||
host string,
|
||||
qtype rules.RRType,
|
||||
res filtering.Result,
|
||||
) {
|
||||
// #nosec G115 -- The Unix epoch time is highly unlikely to be negative, and
|
||||
// also see the TODO.
|
||||
expire := uint32(time.Now().Add(ss.cacheTTL).Unix())
|
||||
exp := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(exp, expire)
|
||||
@ -305,6 +309,8 @@ func (ss *Default) setCacheResult(
|
||||
|
||||
// getCachedResult returns stored data from cache for host. qtype is expected
|
||||
// to be either [dns.TypeA] or [dns.TypeAAAA].
|
||||
//
|
||||
// TODO(a.garipov): Remove gob and use uint64.
|
||||
func (ss *Default) getCachedResult(
|
||||
ctx context.Context,
|
||||
host string,
|
||||
@ -318,6 +324,8 @@ func (ss *Default) getCachedResult(
|
||||
}
|
||||
|
||||
exp := binary.BigEndian.Uint32(data[:4])
|
||||
// #nosec G115 -- The Unix epoch time is highly unlikely to be negative, and
|
||||
// also see the TODO.
|
||||
if exp <= uint32(time.Now().Unix()) {
|
||||
ss.cache.Del([]byte(host))
|
||||
|
||||
@ -342,7 +350,7 @@ func (ss *Default) Update(ctx context.Context, conf filtering.SafeSearchConfig)
|
||||
ss.mu.Lock()
|
||||
defer ss.mu.Unlock()
|
||||
|
||||
err = ss.resetEngine(ctx, rulelist.URLFilterIDSafeSearch, conf)
|
||||
err = ss.resetEngine(ctx, rulelist.IDSafeSearch, conf)
|
||||
if err != nil {
|
||||
// Don't wrap the error, because it's informative enough as is.
|
||||
return err
|
||||
|
||||
@ -101,7 +101,7 @@ func TestDefault_CheckHost_yandex(t *testing.T) {
|
||||
|
||||
rule := res.Rules[0]
|
||||
assert.Equal(t, tc.want, rule.IP)
|
||||
assert.Equal(t, rulelist.URLFilterIDSafeSearch, rule.FilterListID)
|
||||
assert.Equal(t, rulelist.APIIDSafeSearch, rule.FilterListID)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@ -8,6 +8,12 @@ type blockedService struct {
|
||||
Name string `json:"name"`
|
||||
IconSVG []byte `json:"icon_svg"`
|
||||
Rules []string `json:"rules"`
|
||||
GroupID string `json:"group_id"`
|
||||
}
|
||||
|
||||
// serviceGroup represents single group of services.
|
||||
type serviceGroup struct {
|
||||
ID string `json:"id"`
|
||||
}
|
||||
|
||||
// blockedServices contains raw blocked service data.
|
||||
@ -20,6 +26,7 @@ var blockedServices = []blockedService{{
|
||||
"||4chan.org^",
|
||||
"||4channel.org^",
|
||||
},
|
||||
GroupID: "social_network",
|
||||
}, {
|
||||
ID: "500px",
|
||||
Name: "500px",
|
||||
@ -28,6 +35,7 @@ var blockedServices = []blockedService{{
|
||||
"||500px.com^",
|
||||
"||500px.org^",
|
||||
},
|
||||
GroupID: "social_network",
|
||||
}, {
|
||||
ID: "9gag",
|
||||
Name: "9GAG",
|
||||
@ -36,6 +44,7 @@ var blockedServices = []blockedService{{
|
||||
"||9cache.com^",
|
||||
"||9gag.com^",
|
||||
},
|
||||
GroupID: "social_network",
|
||||
}, {
|
||||
ID: "activision_blizzard",
|
||||
Name: "Activision Blizzard",
|
||||
@ -48,6 +57,7 @@ var blockedServices = []blockedService{{
|
||||
"||codmwest.com^",
|
||||
"||demonware.net^",
|
||||
},
|
||||
GroupID: "gaming",
|
||||
}, {
|
||||
ID: "aliexpress",
|
||||
Name: "AliExpress",
|
||||
@ -58,6 +68,7 @@ var blockedServices = []blockedService{{
|
||||
"||aliexpress.com^",
|
||||
"||aliexpress.ru^",
|
||||
},
|
||||
GroupID: "shopping",
|
||||
}, {
|
||||
ID: "amazon",
|
||||
Name: "Amazon",
|
||||
@ -265,6 +276,7 @@ var blockedServices = []blockedService{{
|
||||
"||z.cn^",
|
||||
"||zappos^",
|
||||
},
|
||||
GroupID: "shopping",
|
||||
}, {
|
||||
ID: "amazon_streaming",
|
||||
Name: "Amazon Streaming",
|
||||
@ -300,6 +312,7 @@ var blockedServices = []blockedService{{
|
||||
"||primevideo.tv^",
|
||||
"||video.a2z.com^",
|
||||
},
|
||||
GroupID: "streaming",
|
||||
}, {
|
||||
ID: "amino",
|
||||
Name: "Amino",
|
||||
@ -307,6 +320,7 @@ var blockedServices = []blockedService{{
|
||||
Rules: []string{
|
||||
"||aminoapps.com^",
|
||||
},
|
||||
GroupID: "social_network",
|
||||
}, {
|
||||
ID: "apple_streaming",
|
||||
Name: "Apple Streaming",
|
||||
@ -331,6 +345,7 @@ var blockedServices = []blockedService{{
|
||||
"||tv.g.apple.com^",
|
||||
"||tv.v.aaplimg.com^",
|
||||
},
|
||||
GroupID: "streaming",
|
||||
}, {
|
||||
ID: "battle_net",
|
||||
Name: "Battle.net",
|
||||
@ -341,6 +356,7 @@ var blockedServices = []blockedService{{
|
||||
"||bnet.163.com^",
|
||||
"||bnet.cn^",
|
||||
},
|
||||
GroupID: "gaming",
|
||||
}, {
|
||||
ID: "betano",
|
||||
Name: "Betano",
|
||||
@ -354,6 +370,7 @@ var blockedServices = []blockedService{{
|
||||
"||betano.ng^",
|
||||
"||betano.pt^",
|
||||
},
|
||||
GroupID: "gambling",
|
||||
}, {
|
||||
ID: "betfair",
|
||||
Name: "Betfair",
|
||||
@ -366,6 +383,7 @@ var blockedServices = []blockedService{{
|
||||
"||betfair.ro^",
|
||||
"||betfair.se^",
|
||||
},
|
||||
GroupID: "gambling",
|
||||
}, {
|
||||
ID: "betway",
|
||||
Name: "Betway",
|
||||
@ -388,6 +406,7 @@ var blockedServices = []blockedService{{
|
||||
"||betwaysatta.com^",
|
||||
"||vietnambetway88.com^",
|
||||
},
|
||||
GroupID: "gambling",
|
||||
}, {
|
||||
ID: "bigo_live",
|
||||
Name: "Bigo Live",
|
||||
@ -398,6 +417,7 @@ var blockedServices = []blockedService{{
|
||||
"||bigolive.tv^",
|
||||
"||bigovideo.tv^",
|
||||
},
|
||||
GroupID: "streaming",
|
||||
}, {
|
||||
ID: "bilibili",
|
||||
Name: "Bilibili",
|
||||
@ -450,6 +470,7 @@ var blockedServices = []blockedService{{
|
||||
"||mincdn.com^",
|
||||
"||yo9.com^",
|
||||
},
|
||||
GroupID: "streaming",
|
||||
}, {
|
||||
ID: "blaze",
|
||||
Name: "Blaze",
|
||||
@ -460,6 +481,7 @@ var blockedServices = []blockedService{{
|
||||
"||blaze.com^",
|
||||
"||blazecareers.com^",
|
||||
},
|
||||
GroupID: "gambling",
|
||||
}, {
|
||||
ID: "blizzard_entertainment",
|
||||
Name: "Blizzard Entertainment",
|
||||
@ -475,6 +497,7 @@ var blockedServices = []blockedService{{
|
||||
"||bnet.163.com^",
|
||||
"||bnet.cn^",
|
||||
},
|
||||
GroupID: "gaming",
|
||||
}, {
|
||||
ID: "bluesky",
|
||||
Name: "Bluesky",
|
||||
@ -483,6 +506,7 @@ var blockedServices = []blockedService{{
|
||||
"||bsky.app^",
|
||||
"||bsky.social^",
|
||||
},
|
||||
GroupID: "social_network",
|
||||
}, {
|
||||
ID: "box",
|
||||
Name: "Box",
|
||||
@ -493,6 +517,7 @@ var blockedServices = []blockedService{{
|
||||
"||boxcdn.net^",
|
||||
"||boxcloud.com^",
|
||||
},
|
||||
GroupID: "hosting",
|
||||
}, {
|
||||
ID: "canais_globo",
|
||||
Name: "Canais Globo",
|
||||
@ -502,6 +527,7 @@ var blockedServices = []blockedService{{
|
||||
"||globosat.globo.com^",
|
||||
"||gsatmulti.globo.com^",
|
||||
},
|
||||
GroupID: "streaming",
|
||||
}, {
|
||||
ID: "chatgpt",
|
||||
Name: "ChatGPT",
|
||||
@ -512,6 +538,7 @@ var blockedServices = []blockedService{{
|
||||
"||oaiusercontent.com^",
|
||||
"||openai.com^",
|
||||
},
|
||||
GroupID: "ai",
|
||||
}, {
|
||||
ID: "claro",
|
||||
Name: "Claro",
|
||||
@ -540,6 +567,7 @@ var blockedServices = []blockedService{{
|
||||
"||clarovideo.com^",
|
||||
"||usclaro.com^",
|
||||
},
|
||||
GroupID: "streaming",
|
||||
}, {
|
||||
ID: "claude",
|
||||
Name: "Claude",
|
||||
@ -548,6 +576,7 @@ var blockedServices = []blockedService{{
|
||||
"||anthropic.com^",
|
||||
"||claude.ai^",
|
||||
},
|
||||
GroupID: "ai",
|
||||
}, {
|
||||
ID: "cloudflare",
|
||||
Name: "Cloudflare",
|
||||
@ -584,6 +613,7 @@ var blockedServices = []blockedService{{
|
||||
"||warp.plus^",
|
||||
"||workers.dev^",
|
||||
},
|
||||
GroupID: "cdn",
|
||||
}, {
|
||||
ID: "clubhouse",
|
||||
Name: "Clubhouse",
|
||||
@ -592,6 +622,7 @@ var blockedServices = []blockedService{{
|
||||
"||clubhouse.com^",
|
||||
"||clubhouseapi.com^",
|
||||
},
|
||||
GroupID: "social_network",
|
||||
}, {
|
||||
ID: "coolapk",
|
||||
Name: "CoolApk",
|
||||
@ -601,6 +632,7 @@ var blockedServices = []blockedService{{
|
||||
"||coolapkmarket.com^",
|
||||
"||coolapkmarket.net^",
|
||||
},
|
||||
GroupID: "shopping",
|
||||
}, {
|
||||
ID: "crunchyroll",
|
||||
Name: "Crunchyroll",
|
||||
@ -609,6 +641,7 @@ var blockedServices = []blockedService{{
|
||||
"||crunchyroll.com^",
|
||||
"||gccrunchyroll.com^",
|
||||
},
|
||||
GroupID: "streaming",
|
||||
}, {
|
||||
ID: "dailymotion",
|
||||
Name: "Dailymotion",
|
||||
@ -618,6 +651,7 @@ var blockedServices = []blockedService{{
|
||||
"||dm-event.net^",
|
||||
"||dmcdn.net^",
|
||||
},
|
||||
GroupID: "streaming",
|
||||
}, {
|
||||
ID: "deepseek",
|
||||
Name: "DeepSeek",
|
||||
@ -625,6 +659,7 @@ var blockedServices = []blockedService{{
|
||||
Rules: []string{
|
||||
"||deepseek.com^",
|
||||
},
|
||||
GroupID: "ai",
|
||||
}, {
|
||||
ID: "deezer",
|
||||
Name: "Deezer",
|
||||
@ -633,6 +668,7 @@ var blockedServices = []blockedService{{
|
||||
"||deezer.com^",
|
||||
"||dzcdn.net^",
|
||||
},
|
||||
GroupID: "streaming",
|
||||
}, {
|
||||
ID: "directvgo",
|
||||
Name: "DirecTV Go",
|
||||
@ -640,6 +676,7 @@ var blockedServices = []blockedService{{
|
||||
Rules: []string{
|
||||
"||directvgo.com^",
|
||||
},
|
||||
GroupID: "streaming",
|
||||
}, {
|
||||
ID: "discord",
|
||||
Name: "Discord",
|
||||
@ -673,6 +710,7 @@ var blockedServices = []blockedService{{
|
||||
"||discordstatus.com^",
|
||||
"||watchanimeattheoffice.com^",
|
||||
},
|
||||
GroupID: "social_network",
|
||||
}, {
|
||||
ID: "discoveryplus",
|
||||
Name: "Discovery+",
|
||||
@ -681,6 +719,7 @@ var blockedServices = []blockedService{{
|
||||
"||disco-api.com^",
|
||||
"||discoveryplus.com^",
|
||||
},
|
||||
GroupID: "streaming",
|
||||
}, {
|
||||
ID: "disneyplus",
|
||||
Name: "Disney+",
|
||||
@ -695,6 +734,7 @@ var blockedServices = []blockedService{{
|
||||
"||star.playback.edge.bamgrid.com^",
|
||||
"||starplus.com^",
|
||||
},
|
||||
GroupID: "streaming",
|
||||
}, {
|
||||
ID: "douban",
|
||||
Name: "Douban",
|
||||
@ -704,6 +744,7 @@ var blockedServices = []blockedService{{
|
||||
"||douban.fm^",
|
||||
"||doubanio.com^",
|
||||
},
|
||||
GroupID: "social_network",
|
||||
}, {
|
||||
ID: "dropbox",
|
||||
Name: "Dropbox",
|
||||
@ -732,6 +773,7 @@ var blockedServices = []blockedService{{
|
||||
"||dropboxusercontent.com^",
|
||||
"||getdropbox.com^",
|
||||
},
|
||||
GroupID: "hosting",
|
||||
}, {
|
||||
ID: "ebay",
|
||||
Name: "eBay",
|
||||
@ -1058,6 +1100,7 @@ var blockedServices = []blockedService{{
|
||||
"||xxbay.com^",
|
||||
"||yibei.org^",
|
||||
},
|
||||
GroupID: "shopping",
|
||||
}, {
|
||||
ID: "electronic_arts",
|
||||
Name: "Electronic Arts",
|
||||
@ -1070,6 +1113,7 @@ var blockedServices = []blockedService{{
|
||||
"||swtor.com^",
|
||||
"||tnt-ea.com^",
|
||||
},
|
||||
GroupID: "gaming",
|
||||
}, {
|
||||
ID: "epic_games",
|
||||
Name: "Epic Games",
|
||||
@ -1083,6 +1127,7 @@ var blockedServices = []blockedService{{
|
||||
"||easyanticheat.net^",
|
||||
"||epicgames.com^",
|
||||
},
|
||||
GroupID: "gaming",
|
||||
}, {
|
||||
ID: "espn",
|
||||
Name: "ESPN",
|
||||
@ -1106,6 +1151,7 @@ var blockedServices = []blockedService{{
|
||||
"||espncdn.com^",
|
||||
"||espncricinfo.com^",
|
||||
},
|
||||
GroupID: "streaming",
|
||||
}, {
|
||||
ID: "facebook",
|
||||
Name: "Facebook",
|
||||
@ -1555,6 +1601,7 @@ var blockedServices = []blockedService{{
|
||||
"||zuckerberg.com^",
|
||||
"||zuckerberg.net^",
|
||||
},
|
||||
GroupID: "social_network",
|
||||
}, {
|
||||
ID: "fifa",
|
||||
Name: "FIFA",
|
||||
@ -1563,6 +1610,7 @@ var blockedServices = []blockedService{{
|
||||
"||fifa.com^",
|
||||
"||fifaplus.com^",
|
||||
},
|
||||
GroupID: "streaming",
|
||||
}, {
|
||||
ID: "flickr",
|
||||
Name: "Flickr",
|
||||
@ -1575,6 +1623,7 @@ var blockedServices = []blockedService{{
|
||||
"||flickrpro.com^",
|
||||
"||staticflickr.com^",
|
||||
},
|
||||
GroupID: "hosting",
|
||||
}, {
|
||||
ID: "globoplay",
|
||||
Name: "Globoplay",
|
||||
@ -1585,6 +1634,7 @@ var blockedServices = []blockedService{{
|
||||
"||globoplay.com^",
|
||||
"||globoplay.globo.com^",
|
||||
},
|
||||
GroupID: "streaming",
|
||||
}, {
|
||||
ID: "gog",
|
||||
Name: "GOG",
|
||||
@ -1595,6 +1645,7 @@ var blockedServices = []blockedService{{
|
||||
"||gog.com^",
|
||||
"||gogalaxy.com^",
|
||||
},
|
||||
GroupID: "gaming",
|
||||
}, {
|
||||
ID: "hbomax",
|
||||
Name: "HBO Max",
|
||||
@ -1614,6 +1665,7 @@ var blockedServices = []blockedService{{
|
||||
"||max.com^",
|
||||
"||maxgo.com^",
|
||||
},
|
||||
GroupID: "streaming",
|
||||
}, {
|
||||
ID: "hulu",
|
||||
Name: "Hulu",
|
||||
@ -1621,6 +1673,7 @@ var blockedServices = []blockedService{{
|
||||
Rules: []string{
|
||||
"||hulu.com^",
|
||||
},
|
||||
GroupID: "streaming",
|
||||
}, {
|
||||
ID: "icloud_private_relay",
|
||||
Name: "iCloud Private Relay",
|
||||
@ -1630,6 +1683,7 @@ var blockedServices = []blockedService{{
|
||||
"||mask-h2.icloud.com^$dnsrewrite=NXDOMAIN;;",
|
||||
"||mask.icloud.com^$dnsrewrite=NXDOMAIN;;",
|
||||
},
|
||||
GroupID: "privacy",
|
||||
}, {
|
||||
ID: "iheartradio",
|
||||
Name: "iHeartRadio",
|
||||
@ -1647,6 +1701,7 @@ var blockedServices = []blockedService{{
|
||||
"||ihrint.com^",
|
||||
"||ihrstage.com^",
|
||||
},
|
||||
GroupID: "streaming",
|
||||
}, {
|
||||
ID: "imgur",
|
||||
Name: "Imgur",
|
||||
@ -1654,6 +1709,7 @@ var blockedServices = []blockedService{{
|
||||
Rules: []string{
|
||||
"||imgur.com^",
|
||||
},
|
||||
GroupID: "hosting",
|
||||
}, {
|
||||
ID: "instagram",
|
||||
Name: "Instagram",
|
||||
@ -1732,6 +1788,7 @@ var blockedServices = []blockedService{{
|
||||
"||web-instagram.net^",
|
||||
"||wwwinstagram.com^",
|
||||
},
|
||||
GroupID: "social_network",
|
||||
}, {
|
||||
ID: "iqiyi",
|
||||
Name: "iQIYI",
|
||||
@ -1746,6 +1803,7 @@ var blockedServices = []blockedService{{
|
||||
"||qiyipic.com^",
|
||||
"||qy.net^",
|
||||
},
|
||||
GroupID: "streaming",
|
||||
}, {
|
||||
ID: "kakaotalk",
|
||||
Name: "KakaoTalk",
|
||||
@ -1754,6 +1812,7 @@ var blockedServices = []blockedService{{
|
||||
"||kakao.com^",
|
||||
"||kgslb.com^",
|
||||
},
|
||||
GroupID: "messenger",
|
||||
}, {
|
||||
ID: "kik",
|
||||
Name: "Kik",
|
||||
@ -1761,6 +1820,7 @@ var blockedServices = []blockedService{{
|
||||
Rules: []string{
|
||||
"||kik.com^",
|
||||
},
|
||||
GroupID: "messenger",
|
||||
}, {
|
||||
ID: "kook",
|
||||
Name: "KOOK",
|
||||
@ -1769,6 +1829,7 @@ var blockedServices = []blockedService{{
|
||||
"||kaiheila.cn^",
|
||||
"||kookapp.cn^",
|
||||
},
|
||||
GroupID: "social_network",
|
||||
}, {
|
||||
ID: "lazada",
|
||||
Name: "Lazada",
|
||||
@ -1784,6 +1845,7 @@ var blockedServices = []blockedService{{
|
||||
"||lazada.vn^",
|
||||
"||slatic.net^",
|
||||
},
|
||||
GroupID: "shopping",
|
||||
}, {
|
||||
ID: "leagueoflegends",
|
||||
Name: "League of Legends",
|
||||
@ -1795,6 +1857,7 @@ var blockedServices = []blockedService{{
|
||||
"||lolstatic.com^",
|
||||
"||lolusercontent.com^",
|
||||
},
|
||||
GroupID: "gaming",
|
||||
}, {
|
||||
ID: "line",
|
||||
Name: "LINE",
|
||||
@ -1819,6 +1882,7 @@ var blockedServices = []blockedService{{
|
||||
"||lineshoppingseller.com^",
|
||||
"||linetv.tw^",
|
||||
},
|
||||
GroupID: "social_network",
|
||||
}, {
|
||||
ID: "linkedin",
|
||||
Name: "LinkedIn",
|
||||
@ -1841,6 +1905,7 @@ var blockedServices = []blockedService{{
|
||||
"||linkedin.qtlcdn.com^",
|
||||
"||lnkd.in^",
|
||||
},
|
||||
GroupID: "social_network",
|
||||
}, {
|
||||
ID: "lionsgateplus",
|
||||
Name: "Lionsgate+",
|
||||
@ -1849,6 +1914,7 @@ var blockedServices = []blockedService{{
|
||||
"||lionsgateplus.com^",
|
||||
"||starz.com^",
|
||||
},
|
||||
GroupID: "streaming",
|
||||
}, {
|
||||
ID: "looke",
|
||||
Name: "Looke",
|
||||
@ -1857,6 +1923,7 @@ var blockedServices = []blockedService{{
|
||||
"||looke.com.br^",
|
||||
"||ottvs.com.br^",
|
||||
},
|
||||
GroupID: "streaming",
|
||||
}, {
|
||||
ID: "mail_ru",
|
||||
Name: "Mail.ru",
|
||||
@ -1866,6 +1933,7 @@ var blockedServices = []blockedService{{
|
||||
"||mail.ru^",
|
||||
"||mycdn.me^",
|
||||
},
|
||||
GroupID: "social_network",
|
||||
}, {
|
||||
ID: "mastodon",
|
||||
Name: "Mastodon",
|
||||
@ -1971,6 +2039,7 @@ var blockedServices = []blockedService{{
|
||||
"||wien.rocks^",
|
||||
"||wxw.moe^",
|
||||
},
|
||||
GroupID: "social_network",
|
||||
}, {
|
||||
ID: "mercado_libre",
|
||||
Name: "Mercado Libre",
|
||||
@ -1997,6 +2066,7 @@ var blockedServices = []blockedService{{
|
||||
"||mercadolivre.com.br^",
|
||||
"||mlstatic.com^",
|
||||
},
|
||||
GroupID: "shopping",
|
||||
}, {
|
||||
ID: "minecraft",
|
||||
Name: "Minecraft",
|
||||
@ -2006,6 +2076,7 @@ var blockedServices = []blockedService{{
|
||||
"||minecraftservices.com^",
|
||||
"||mojang.com^",
|
||||
},
|
||||
GroupID: "gaming",
|
||||
}, {
|
||||
ID: "nebula",
|
||||
Name: "Nebula",
|
||||
@ -2014,6 +2085,7 @@ var blockedServices = []blockedService{{
|
||||
"||nebula.app^",
|
||||
"||nebula.tv^",
|
||||
},
|
||||
GroupID: "streaming",
|
||||
}, {
|
||||
ID: "netflix",
|
||||
Name: "Netflix",
|
||||
@ -2045,6 +2117,7 @@ var blockedServices = []blockedService{{
|
||||
"||nflxso.net^",
|
||||
"||nflxvideo.net^",
|
||||
},
|
||||
GroupID: "streaming",
|
||||
}, {
|
||||
ID: "nintendo",
|
||||
Name: "Nintendo",
|
||||
@ -2068,6 +2141,7 @@ var blockedServices = []blockedService{{
|
||||
"||nintendoswitch.cn^",
|
||||
"||nintendowifi.net^",
|
||||
},
|
||||
GroupID: "gaming",
|
||||
}, {
|
||||
ID: "nvidia",
|
||||
Name: "Nvidia",
|
||||
@ -2084,6 +2158,7 @@ var blockedServices = []blockedService{{
|
||||
"||nvidianews.com^",
|
||||
"||tegrazone.com^",
|
||||
},
|
||||
GroupID: "software",
|
||||
}, {
|
||||
ID: "odysee",
|
||||
Name: "Odysee",
|
||||
@ -2094,6 +2169,7 @@ var blockedServices = []blockedService{{
|
||||
"||odysee.live^",
|
||||
"||odysee.tv^",
|
||||
},
|
||||
GroupID: "social_network",
|
||||
}, {
|
||||
ID: "ok",
|
||||
Name: "OK.ru",
|
||||
@ -2106,6 +2182,7 @@ var blockedServices = []blockedService{{
|
||||
"||oktech.ru^",
|
||||
"||st.mycdn.me^",
|
||||
},
|
||||
GroupID: "social_network",
|
||||
}, {
|
||||
ID: "olvid",
|
||||
Name: "Olvid",
|
||||
@ -2114,6 +2191,7 @@ var blockedServices = []blockedService{{
|
||||
"||olvid-attachment-chunks.s3.eu-west-3.amazonaws.com^",
|
||||
"||olvid.io^",
|
||||
},
|
||||
GroupID: "messenger",
|
||||
}, {
|
||||
ID: "onlyfans",
|
||||
Name: "OnlyFans",
|
||||
@ -2121,6 +2199,7 @@ var blockedServices = []blockedService{{
|
||||
Rules: []string{
|
||||
"||onlyfans.com^",
|
||||
},
|
||||
GroupID: "social_network",
|
||||
}, {
|
||||
ID: "origin",
|
||||
Name: "Origin",
|
||||
@ -2138,6 +2217,7 @@ var blockedServices = []blockedService{{
|
||||
"||origin.tv^",
|
||||
"||signin.ea.com^",
|
||||
},
|
||||
GroupID: "gaming",
|
||||
}, {
|
||||
ID: "paramountplus",
|
||||
Name: "Paramount Plus",
|
||||
@ -2146,6 +2226,7 @@ var blockedServices = []blockedService{{
|
||||
"||paramountplus.com^",
|
||||
"||pplusstatic.com^",
|
||||
},
|
||||
GroupID: "streaming",
|
||||
}, {
|
||||
ID: "peacock_tv",
|
||||
Name: "Peacock TV",
|
||||
@ -2154,6 +2235,7 @@ var blockedServices = []blockedService{{
|
||||
"||peacock.com^",
|
||||
"||peacocktv.com^",
|
||||
},
|
||||
GroupID: "streaming",
|
||||
}, {
|
||||
ID: "pinterest",
|
||||
Name: "Pinterest",
|
||||
@ -2209,6 +2291,7 @@ var blockedServices = []blockedService{{
|
||||
"||pinterest.vn^",
|
||||
"||pinterestmail.com^",
|
||||
},
|
||||
GroupID: "social_network",
|
||||
}, {
|
||||
ID: "playstation",
|
||||
Name: "PlayStation",
|
||||
@ -2223,6 +2306,7 @@ var blockedServices = []blockedService{{
|
||||
"||sonyentertainmentnetwork.com",
|
||||
"||station.sony.com",
|
||||
},
|
||||
GroupID: "gaming",
|
||||
}, {
|
||||
ID: "plenty_of_fish",
|
||||
Name: "Plenty of Fish",
|
||||
@ -2230,6 +2314,7 @@ var blockedServices = []blockedService{{
|
||||
Rules: []string{
|
||||
"||pof.com^",
|
||||
},
|
||||
GroupID: "dating",
|
||||
}, {
|
||||
ID: "plex",
|
||||
Name: "Plex",
|
||||
@ -2240,6 +2325,7 @@ var blockedServices = []blockedService{{
|
||||
"||plex.tv^",
|
||||
"||plexapp.com^",
|
||||
},
|
||||
GroupID: "streaming",
|
||||
}, {
|
||||
ID: "pluto_tv",
|
||||
Name: "Pluto TV",
|
||||
@ -2247,6 +2333,7 @@ var blockedServices = []blockedService{{
|
||||
Rules: []string{
|
||||
"||pluto.tv^",
|
||||
},
|
||||
GroupID: "streaming",
|
||||
}, {
|
||||
ID: "privacy",
|
||||
Name: "Privacy",
|
||||
@ -2254,6 +2341,7 @@ var blockedServices = []blockedService{{
|
||||
Rules: []string{
|
||||
"||privacy.com.br^",
|
||||
},
|
||||
GroupID: "privacy",
|
||||
}, {
|
||||
ID: "qq",
|
||||
Name: "QQ",
|
||||
@ -2263,6 +2351,7 @@ var blockedServices = []blockedService{{
|
||||
"||qq.com^$denyallow=wx.qq.com|weixin.qq.com",
|
||||
"||url.cn^",
|
||||
},
|
||||
GroupID: "streaming",
|
||||
}, {
|
||||
ID: "rakuten_viki",
|
||||
Name: "Rakuten Viki",
|
||||
@ -2272,6 +2361,7 @@ var blockedServices = []blockedService{{
|
||||
"||viki.com^",
|
||||
"||viki.io^",
|
||||
},
|
||||
GroupID: "streaming",
|
||||
}, {
|
||||
ID: "reddit",
|
||||
Name: "Reddit",
|
||||
@ -2283,6 +2373,7 @@ var blockedServices = []blockedService{{
|
||||
"||redditmedia.com^",
|
||||
"||redditstatic.com^",
|
||||
},
|
||||
GroupID: "social_network",
|
||||
}, {
|
||||
ID: "riot_games",
|
||||
Name: "Riot Games",
|
||||
@ -2295,6 +2386,7 @@ var blockedServices = []blockedService{{
|
||||
"||riotcdn.net^",
|
||||
"||riotgames.com^",
|
||||
},
|
||||
GroupID: "gaming",
|
||||
}, {
|
||||
ID: "roblox",
|
||||
Name: "Roblox",
|
||||
@ -2314,6 +2406,7 @@ var blockedServices = []blockedService{{
|
||||
"||robloxcdn.com^",
|
||||
"||robloxdev.cn^",
|
||||
},
|
||||
GroupID: "gaming",
|
||||
}, {
|
||||
ID: "rockstar_games",
|
||||
Name: "Rockstar Games",
|
||||
@ -2322,6 +2415,7 @@ var blockedServices = []blockedService{{
|
||||
"||rockstargames.com^",
|
||||
"||rsg.sc^",
|
||||
},
|
||||
GroupID: "gaming",
|
||||
}, {
|
||||
ID: "samsung_tv_plus",
|
||||
Name: "Samsung TV Plus",
|
||||
@ -2332,6 +2426,7 @@ var blockedServices = []blockedService{{
|
||||
"||samsungcloud.tv^",
|
||||
"||samsungtvplus.com^",
|
||||
},
|
||||
GroupID: "streaming",
|
||||
}, {
|
||||
ID: "shein",
|
||||
Name: "Shein",
|
||||
@ -2342,6 +2437,7 @@ var blockedServices = []blockedService{{
|
||||
"||shein.se^",
|
||||
"||sheinsz.ltwebstatic.com^",
|
||||
},
|
||||
GroupID: "shopping",
|
||||
}, {
|
||||
ID: "shopee",
|
||||
Name: "Shopee",
|
||||
@ -2368,6 +2464,7 @@ var blockedServices = []blockedService{{
|
||||
"||shopeemobile.com^",
|
||||
"||shp.ee^",
|
||||
},
|
||||
GroupID: "shopping",
|
||||
}, {
|
||||
ID: "signal",
|
||||
Name: "Signal",
|
||||
@ -2376,6 +2473,7 @@ var blockedServices = []blockedService{{
|
||||
"||signal.org^",
|
||||
"||whispersystems.org^",
|
||||
},
|
||||
GroupID: "messenger",
|
||||
}, {
|
||||
ID: "skype",
|
||||
Name: "Skype",
|
||||
@ -2390,6 +2488,7 @@ var blockedServices = []blockedService{{
|
||||
"||skypeassets.net^",
|
||||
"||skypedata.akadns.net^",
|
||||
},
|
||||
GroupID: "messenger",
|
||||
}, {
|
||||
ID: "slack",
|
||||
Name: "Slack",
|
||||
@ -2401,6 +2500,7 @@ var blockedServices = []blockedService{{
|
||||
"||slack.com^",
|
||||
"||slackb.com^",
|
||||
},
|
||||
GroupID: "messenger",
|
||||
}, {
|
||||
ID: "snapchat",
|
||||
Name: "Snapchat",
|
||||
@ -2413,6 +2513,7 @@ var blockedServices = []blockedService{{
|
||||
"||snapchat.com^",
|
||||
"||snapkit.co",
|
||||
},
|
||||
GroupID: "social_network",
|
||||
}, {
|
||||
ID: "soundcloud",
|
||||
Name: "SoundCloud",
|
||||
@ -2421,6 +2522,7 @@ var blockedServices = []blockedService{{
|
||||
"||sndcdn.com^",
|
||||
"||soundcloud.com^",
|
||||
},
|
||||
GroupID: "streaming",
|
||||
}, {
|
||||
ID: "spotify",
|
||||
Name: "Spotify",
|
||||
@ -2448,6 +2550,7 @@ var blockedServices = []blockedService{{
|
||||
"||spotifyforbrands.com^",
|
||||
"||spotifyjobs.com^",
|
||||
},
|
||||
GroupID: "streaming",
|
||||
}, {
|
||||
ID: "spotify_video",
|
||||
Name: "Spotify Video",
|
||||
@ -2460,6 +2563,7 @@ var blockedServices = []blockedService{{
|
||||
"||video-akpcw.spotifycdn.com^",
|
||||
"||video-fa.scdn.co^",
|
||||
},
|
||||
GroupID: "streaming",
|
||||
}, {
|
||||
ID: "steam",
|
||||
Name: "Steam",
|
||||
@ -2500,6 +2604,7 @@ var blockedServices = []blockedService{{
|
||||
"||valvesoftware.com^",
|
||||
"||wmsjsteam.com^",
|
||||
},
|
||||
GroupID: "gaming",
|
||||
}, {
|
||||
ID: "telegram",
|
||||
Name: "Telegram (Web)",
|
||||
@ -2523,6 +2628,7 @@ var blockedServices = []blockedService{{
|
||||
"||tx.me^",
|
||||
"||usercontent.dev^",
|
||||
},
|
||||
GroupID: "messenger",
|
||||
}, {
|
||||
ID: "temu",
|
||||
Name: "Temu",
|
||||
@ -2531,6 +2637,7 @@ var blockedServices = []blockedService{{
|
||||
"||kwcdn.com^",
|
||||
"||temu.com^",
|
||||
},
|
||||
GroupID: "shopping",
|
||||
}, {
|
||||
ID: "tidal",
|
||||
Name: "Tidal",
|
||||
@ -2538,6 +2645,7 @@ var blockedServices = []blockedService{{
|
||||
Rules: []string{
|
||||
"||tidal.com^",
|
||||
},
|
||||
GroupID: "streaming",
|
||||
}, {
|
||||
ID: "tiktok",
|
||||
Name: "TikTok",
|
||||
@ -2577,6 +2685,7 @@ var blockedServices = []blockedService{{
|
||||
"||v*.tiktokcdn-eu.com^",
|
||||
"||zijieapi.com^",
|
||||
},
|
||||
GroupID: "social_network",
|
||||
}, {
|
||||
ID: "tinder",
|
||||
Name: "Tinder",
|
||||
@ -2586,6 +2695,7 @@ var blockedServices = []blockedService{{
|
||||
"||tinder.com^",
|
||||
"||tindersparks.com^",
|
||||
},
|
||||
GroupID: "dating",
|
||||
}, {
|
||||
ID: "tumblr",
|
||||
Name: "Tumblr",
|
||||
@ -2593,6 +2703,7 @@ var blockedServices = []blockedService{{
|
||||
Rules: []string{
|
||||
"||tumblr.com^",
|
||||
},
|
||||
GroupID: "social_network",
|
||||
}, {
|
||||
ID: "twitch",
|
||||
Name: "Twitch",
|
||||
@ -2605,6 +2716,7 @@ var blockedServices = []blockedService{{
|
||||
"||twitchcdn.net^",
|
||||
"||twitchsvc.net^",
|
||||
},
|
||||
GroupID: "streaming",
|
||||
}, {
|
||||
ID: "twitter",
|
||||
Name: "X (formerly Twitter)",
|
||||
@ -2634,6 +2746,7 @@ var blockedServices = []blockedService{{
|
||||
"||vine.co^",
|
||||
"||x.com^",
|
||||
},
|
||||
GroupID: "social_network",
|
||||
}, {
|
||||
ID: "ubisoft",
|
||||
Name: "Ubisoft",
|
||||
@ -2644,6 +2757,7 @@ var blockedServices = []blockedService{{
|
||||
"||ubisoft.org^",
|
||||
"||ubisoftconnect.com^",
|
||||
},
|
||||
GroupID: "gaming",
|
||||
}, {
|
||||
ID: "valorant",
|
||||
Name: "Valorant",
|
||||
@ -2653,6 +2767,7 @@ var blockedServices = []blockedService{{
|
||||
"||valorant.scd.riotcdn.net",
|
||||
"||valorant.secure.dyn.riotcdn.net",
|
||||
},
|
||||
GroupID: "gaming",
|
||||
}, {
|
||||
ID: "viber",
|
||||
Name: "Viber",
|
||||
@ -2660,6 +2775,7 @@ var blockedServices = []blockedService{{
|
||||
Rules: []string{
|
||||
"||viber.com^",
|
||||
},
|
||||
GroupID: "messenger",
|
||||
}, {
|
||||
ID: "vimeo",
|
||||
Name: "Vimeo",
|
||||
@ -2683,6 +2799,7 @@ var blockedServices = []blockedService{{
|
||||
"||vimeoondemand.com^",
|
||||
"||vimeostatus.com^",
|
||||
},
|
||||
GroupID: "streaming",
|
||||
}, {
|
||||
ID: "vk",
|
||||
Name: "VK.com",
|
||||
@ -2709,6 +2826,7 @@ var blockedServices = []blockedService{{
|
||||
"||vkuservideo.com^",
|
||||
"||vkuservideo.net^",
|
||||
},
|
||||
GroupID: "social_network",
|
||||
}, {
|
||||
ID: "voot",
|
||||
Name: "Voot",
|
||||
@ -2716,6 +2834,7 @@ var blockedServices = []blockedService{{
|
||||
Rules: []string{
|
||||
"||voot.com^",
|
||||
},
|
||||
GroupID: "streaming",
|
||||
}, {
|
||||
ID: "wargaming",
|
||||
Name: "Wargaming",
|
||||
@ -2730,6 +2849,7 @@ var blockedServices = []blockedService{{
|
||||
"||worldofwarships.eu^",
|
||||
"||wotblitz.com^",
|
||||
},
|
||||
GroupID: "gaming",
|
||||
}, {
|
||||
ID: "wechat",
|
||||
Name: "WeChat",
|
||||
@ -2741,6 +2861,7 @@ var blockedServices = []blockedService{{
|
||||
"||weixinbridge.com^",
|
||||
"||wx.qq.com^",
|
||||
},
|
||||
GroupID: "messenger",
|
||||
}, {
|
||||
ID: "weibo",
|
||||
Name: "Weibo",
|
||||
@ -2754,6 +2875,7 @@ var blockedServices = []blockedService{{
|
||||
"||weibo.com^",
|
||||
"||weibocdn.com^",
|
||||
},
|
||||
GroupID: "streaming",
|
||||
}, {
|
||||
ID: "whatsapp",
|
||||
Name: "WhatsApp",
|
||||
@ -2771,6 +2893,7 @@ var blockedServices = []blockedService{{
|
||||
"||whatsapp.tv^",
|
||||
"||whatsappbrand.com^",
|
||||
},
|
||||
GroupID: "messenger",
|
||||
}, {
|
||||
ID: "wizz",
|
||||
Name: "Wizz",
|
||||
@ -2780,6 +2903,7 @@ var blockedServices = []blockedService{{
|
||||
"||wizz.chat^",
|
||||
"||wizzapp.com^",
|
||||
},
|
||||
GroupID: "dating",
|
||||
}, {
|
||||
ID: "xboxlive",
|
||||
Name: "Xbox Live",
|
||||
@ -2794,6 +2918,7 @@ var blockedServices = []blockedService{{
|
||||
"||xboxlive.com^",
|
||||
"||xboxservices.com^",
|
||||
},
|
||||
GroupID: "gaming",
|
||||
}, {
|
||||
ID: "xiaohongshu",
|
||||
Name: "Xiaohongshu",
|
||||
@ -2805,6 +2930,7 @@ var blockedServices = []blockedService{{
|
||||
"||xiaohongshu.com^",
|
||||
"||xiaohongshu.net^",
|
||||
},
|
||||
GroupID: "shopping",
|
||||
}, {
|
||||
ID: "youtube",
|
||||
Name: "YouTube",
|
||||
@ -2987,6 +3113,7 @@ var blockedServices = []blockedService{{
|
||||
"||yt.be^",
|
||||
"||ytimg.com^",
|
||||
},
|
||||
GroupID: "streaming",
|
||||
}, {
|
||||
ID: "yy",
|
||||
Name: "YY",
|
||||
@ -2994,6 +3121,7 @@ var blockedServices = []blockedService{{
|
||||
Rules: []string{
|
||||
"||yy.com^",
|
||||
},
|
||||
GroupID: "streaming",
|
||||
}, {
|
||||
ID: "zhihu",
|
||||
Name: "Zhihu",
|
||||
@ -3002,4 +3130,32 @@ var blockedServices = []blockedService{{
|
||||
"||zhihu.com^",
|
||||
"||zhimg.com^",
|
||||
},
|
||||
GroupID: "social_network",
|
||||
}}
|
||||
|
||||
// serviceGroups contains raw service group data.
|
||||
var serviceGroups = []serviceGroup{{
|
||||
ID: "ai",
|
||||
}, {
|
||||
ID: "cdn",
|
||||
}, {
|
||||
ID: "dating",
|
||||
}, {
|
||||
ID: "gambling",
|
||||
}, {
|
||||
ID: "gaming",
|
||||
}, {
|
||||
ID: "hosting",
|
||||
}, {
|
||||
ID: "messenger",
|
||||
}, {
|
||||
ID: "privacy",
|
||||
}, {
|
||||
ID: "shopping",
|
||||
}, {
|
||||
ID: "social_network",
|
||||
}, {
|
||||
ID: "software",
|
||||
}, {
|
||||
ID: "streaming",
|
||||
}}
|
||||
|
||||
@ -525,8 +525,11 @@ func (web *webAPI) handleInstallConfigure(w http.ResponseWriter, r *http.Request
|
||||
registerControlHandlers(web)
|
||||
|
||||
aghhttp.OK(ctx, web.logger, w)
|
||||
if f, ok := w.(http.Flusher); ok {
|
||||
f.Flush()
|
||||
|
||||
rc := http.NewResponseController(w)
|
||||
err = rc.Flush()
|
||||
if err != nil {
|
||||
web.logger.WarnContext(ctx, "flushing response", slogutil.KeyError, err)
|
||||
}
|
||||
|
||||
if !restartHTTP {
|
||||
|
||||
@ -64,7 +64,7 @@ func (web *webAPI) handleVersionJSON(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
err = web.requestVersionInfo(r.Context(), resp, req.Recheck)
|
||||
err = web.requestVersionInfo(ctx, resp, req.Recheck)
|
||||
if err != nil {
|
||||
// Don't wrap the error, because it's informative enough as is.
|
||||
aghhttp.ErrorAndLog(ctx, web.logger, r, w, http.StatusBadGateway, "%s", err)
|
||||
@ -161,8 +161,11 @@ func (web *webAPI) handleUpdate(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
aghhttp.OK(ctx, web.logger, w)
|
||||
if f, ok := w.(http.Flusher); ok {
|
||||
f.Flush()
|
||||
|
||||
rc := http.NewResponseController(w)
|
||||
err = rc.Flush()
|
||||
if err != nil {
|
||||
web.logger.WarnContext(ctx, "flushing response", slogutil.KeyError, err)
|
||||
}
|
||||
|
||||
// The background context is used because the underlying functions wrap it
|
||||
|
||||
@ -188,7 +188,7 @@ func (l *queryLog) decodeResultRuleKey(
|
||||
ent.Result.Rules, vToken = l.decodeVTokenAndAddRule(ctx, key, i, dec, ent.Result.Rules)
|
||||
if n, ok := vToken.(json.Number); ok {
|
||||
id, _ := n.Int64()
|
||||
ent.Result.Rules[i].FilterListID = rulelist.URLFilterID(id)
|
||||
ent.Result.Rules[i].FilterListID = rulelist.APIID(id)
|
||||
}
|
||||
case "IP":
|
||||
ent.Result.Rules, vToken = l.decodeVTokenAndAddRule(ctx, key, i, dec, ent.Result.Rules)
|
||||
@ -643,7 +643,7 @@ var resultHandlers = map[string]logEntryHandler{
|
||||
l++
|
||||
}
|
||||
|
||||
ent.Result.Rules[l-1].FilterListID = rulelist.URLFilterID(id)
|
||||
ent.Result.Rules[l-1].FilterListID = rulelist.APIID(id)
|
||||
|
||||
return nil
|
||||
},
|
||||
|
||||
@ -2,7 +2,11 @@
|
||||
|
||||
<!-- TODO(a.garipov): Reformat in accordance with the KeepAChangelog spec. -->
|
||||
|
||||
## v0.108.0: API changes
|
||||
## v0.107.67: API changes
|
||||
|
||||
- The new field `"groups"` in `GET /control/blocked_services/all` is a list of service group. Groups make it possible to block multiple services with equal `"group_id"` at once.
|
||||
|
||||
- The new field `"group_id"` for each `BlockedService` object in `GET /control/blocked_services/all` indicates which group the service belongs to.
|
||||
|
||||
## v0.107.64: API changes
|
||||
|
||||
|
||||
@ -3012,8 +3012,12 @@
|
||||
'items':
|
||||
'$ref': '#/components/schemas/BlockedService'
|
||||
'type': 'array'
|
||||
'groups':
|
||||
'items':
|
||||
'$ref': '#/components/schemas/ServiceGroup'
|
||||
'required':
|
||||
- 'blocked_services'
|
||||
- 'groups'
|
||||
'type': 'object'
|
||||
'BlockedService':
|
||||
'properties':
|
||||
@ -3036,12 +3040,25 @@
|
||||
'items':
|
||||
'type': 'string'
|
||||
'type': 'array'
|
||||
'group_id':
|
||||
'description': >
|
||||
The ID of the group, that the service belongs to.
|
||||
'type': 'string'
|
||||
'required':
|
||||
- 'icon_svg'
|
||||
- 'id'
|
||||
- 'name'
|
||||
- 'rules'
|
||||
'type': 'object'
|
||||
'ServiceGroup':
|
||||
'properties':
|
||||
'id':
|
||||
'description': >
|
||||
The ID of this group.
|
||||
'type': 'string'
|
||||
'required':
|
||||
- 'id'
|
||||
'type': 'object'
|
||||
'BlockedServicesSchedule':
|
||||
'type': 'object'
|
||||
'properties':
|
||||
|
||||
@ -86,6 +86,12 @@ type blockedService struct {
|
||||
Name string ` + "`" + `json:"name"` + "`" + `
|
||||
IconSVG []byte ` + "`" + `json:"icon_svg"` + "`" + `
|
||||
Rules []string ` + "`" + `json:"rules"` + "`" + `
|
||||
GroupID string ` + "`" + `json:"group_id"` + "`" + `
|
||||
}
|
||||
|
||||
// serviceGroup represents single group of services.
|
||||
type serviceGroup struct {
|
||||
ID string ` + "`" + `json:"id"` + "`" + `
|
||||
}
|
||||
|
||||
// blockedServices contains raw blocked service data.
|
||||
@ -97,6 +103,13 @@ var blockedServices = []blockedService{<% $l := len .BlockedServices %>
|
||||
Rules: []string{<% range $s.Rules %>
|
||||
<% printf "%q" . %>,<% end %>
|
||||
},
|
||||
GroupID: <% printf "%q" $s.Group %>,
|
||||
}<% if isnotlast $i $l %>, <% end %><% end %>}
|
||||
|
||||
// serviceGroups contains raw service group data.
|
||||
var serviceGroups = []serviceGroup{<% $l := len .ServiceGroups %>
|
||||
<%- range $i, $s := .ServiceGroups %>{
|
||||
ID: <% printf "%q" $s.ID %>,
|
||||
}<% if isnotlast $i $l %>, <% end %><% end %>}
|
||||
`
|
||||
|
||||
@ -104,6 +117,7 @@ var blockedServices = []blockedService{<% $l := len .BlockedServices %>
|
||||
// index.
|
||||
type hlServices struct {
|
||||
BlockedServices []*hlServicesService `json:"blocked_services"`
|
||||
ServiceGroups []*hlServicesGroup `json:"groups"`
|
||||
}
|
||||
|
||||
// hlServicesService is the JSON structure for a service in the Hostlists
|
||||
@ -113,4 +127,11 @@ type hlServicesService struct {
|
||||
Name string `json:"name"`
|
||||
IconSVG string `json:"icon_svg"`
|
||||
Rules []string `json:"rules"`
|
||||
Group string `json:"group"`
|
||||
}
|
||||
|
||||
// hlServicesGroup is the JSON structure for a service group in the Hostlists
|
||||
// Registry.
|
||||
type hlServicesGroup struct {
|
||||
ID string `json:"id"`
|
||||
}
|
||||
|
||||
@ -301,7 +301,7 @@ fix_darwin() {
|
||||
|
||||
# Function fix_freebsd performs some fixes to make it work on FreeBSD.
|
||||
fix_freebsd() {
|
||||
if ! [ "$os" = 'freebsd' ]; then
|
||||
if [ "$os" != 'freebsd' ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
|
||||
@ -180,13 +180,10 @@ run_linter gocognit --over='14' \
|
||||
./internal/dhcpd \
|
||||
;
|
||||
|
||||
run_linter gocognit --over='13' \
|
||||
./internal/aghnet/ \
|
||||
;
|
||||
|
||||
run_linter gocognit --over='10' \
|
||||
./internal/aghalg/ \
|
||||
./internal/aghhttp/ \
|
||||
./internal/aghnet/ \
|
||||
./internal/aghos/ \
|
||||
./internal/aghrenameio/ \
|
||||
./internal/aghtest/ \
|
||||
|
||||
@ -17,6 +17,7 @@ import (
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/ioutil"
|
||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||
"github.com/AdguardTeam/golibs/syncutil"
|
||||
)
|
||||
|
||||
// download and save all translations.
|
||||
@ -47,7 +48,7 @@ func (c *twoskyClient) download(ctx context.Context, l *slog.Logger) (err error)
|
||||
dw := &downloadWorker{
|
||||
ctx: ctx,
|
||||
l: l,
|
||||
failed: &sync.Map{},
|
||||
failed: syncutil.NewMap[string, struct{}](),
|
||||
client: &http.Client{
|
||||
Timeout: 10 * time.Second,
|
||||
},
|
||||
@ -72,25 +73,24 @@ func (c *twoskyClient) download(ctx context.Context, l *slog.Logger) (err error)
|
||||
return nil
|
||||
}
|
||||
|
||||
// printFailedLocales prints sorted list of failed downloads, if any.
|
||||
func printFailedLocales(ctx context.Context, l *slog.Logger, failed *sync.Map) {
|
||||
keys := []string{}
|
||||
failed.Range(func(k, _ any) bool {
|
||||
s, ok := k.(string)
|
||||
if !ok {
|
||||
panic("unexpected type")
|
||||
}
|
||||
|
||||
keys = append(keys, s)
|
||||
|
||||
return true
|
||||
})
|
||||
// printFailedLocales prints sorted list of failed downloads, if any. l and
|
||||
// failed must not be nil.
|
||||
func printFailedLocales(
|
||||
ctx context.Context,
|
||||
l *slog.Logger,
|
||||
failed *syncutil.Map[string, struct{}],
|
||||
) {
|
||||
var keys []string
|
||||
for k := range failed.Range {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
|
||||
if len(keys) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
slices.Sort(keys)
|
||||
|
||||
l.InfoContext(ctx, "failed", "locales", keys)
|
||||
}
|
||||
|
||||
@ -100,7 +100,7 @@ func printFailedLocales(ctx context.Context, l *slog.Logger, failed *sync.Map) {
|
||||
type downloadWorker struct {
|
||||
ctx context.Context
|
||||
l *slog.Logger
|
||||
failed *sync.Map
|
||||
failed *syncutil.Map[string, struct{}]
|
||||
client *http.Client
|
||||
uriCh <-chan *url.URL
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user