diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d1dcd2..06a6272 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ The format is **not** based on [Keep a Changelog][kec], since the project **does [kec]: https://keepachangelog.com/en/1.0.0/ [sem]: https://semver.org/spec/v2.0.0.html +## AGDNS-2603 / Build 1114 + +- The new environment variable `PROFILES_CACHE_TYPE` has been added. + ## AGDNS-3491 / Build 1109 - The new environment variable `CATEGORY_FILTER_ENABLED` has been added. diff --git a/doc/debughttp.md b/doc/debughttp.md index e23caab..f20e3c6 100644 --- a/doc/debughttp.md +++ b/doc/debughttp.md @@ -9,6 +9,7 @@ The AdGuard DNS debug HTTP API is served on [`LISTEN_PORT`][env-listen_port] and - [`GET /debug/pprof`](#pprof) - [`POST /debug/api/cache/clear`](#api-cache-clear) - [`POST /debug/api/refresh`](#api-refresh) +- [`POST /debug/panic`](#panic) - [`POST /dnsdb/csv`](#dnsdb-csv) [env-listen_port]: environment.md#LISTEN_PORT @@ -132,6 +133,10 @@ Response body example: } ``` +## `POST /debug/panic` + +A debugging endpoint that forces service panic. + ## `POST /dnsdb/csv` The CSV dump of the current DNSDB statistics. Example of the output: diff --git a/doc/environment.md b/doc/environment.md index 0284d03..8bb1e4b 100644 --- a/doc/environment.md +++ b/doc/environment.md @@ -48,6 +48,7 @@ AdGuard DNS uses [environment variables][wiki-env] to store some of the more sen - [`NODE_NAME`](#NODE_NAME) - [`PROFILES_API_KEY`](#PROFILES_API_KEY) - [`PROFILES_CACHE_PATH`](#PROFILES_CACHE_PATH) +- [`PROFILES_CACHE_TYPE`](#PROFILES_CACHE_TYPE) - [`PROFILES_URL`](#PROFILES_URL) - [`REDIS_DB`](#REDIS_DB) - [`REDIS_HOST`](#REDIS_HOST) @@ -411,7 +412,7 @@ The path to the profile cache file: ```sh protoc\ --decode\ - profiledb.FileCache\ + filecachepb.FileCache\ ./internal/profiledb/internal/filecachepb/filecache.proto\ < /path/to/profilecache.pb ``` @@ -422,6 +423,12 @@ The profile cache is read on start and is later updated on every [full refresh][ [conf-backend-full_refresh_interval]: configuration.md#backend-full_refresh_interval +## `PROFILES_CACHE_TYPE` + +Type of the profile cache. Allowed values are: `default` and `opaque`. + +**Default:** No default value, the variable is required, if [PROFILES_CACHE_PATH](#PROFILES_CACHE_PATH) isn't set to `none` and configuration contains profiles. + ## `PROFILES_MAX_RESP_SIZE` The maximum size of the response from the profiles API in a human-readable format. diff --git a/doc/http.md b/doc/http.md index 2fbc062..eaf8b76 100644 --- a/doc/http.md +++ b/doc/http.md @@ -52,7 +52,8 @@ Example of the output: "node_name": "eu-1.dns.example.com", "server_group_name": "adguard_dns_default", "server_name": "default_dns", - "server_type": "private" + "server_type": "private", + "tls_curve_id": "X25519MLKEM768" } ``` @@ -73,6 +74,8 @@ The `server_type` field can have one of the following values: - `"public"`: A public AdGuard DNS server is used. +The `tls_curve_id` field is the key exchange mechanism used for the connection. If a legacy RSA key exchange is used, this field is empty. + [conf-check-domains]: configuration.md#check-domains ## Linked IP Proxy diff --git a/go.mod b/go.mod index 6772ff1..ee95ae4 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.25.5 require ( // NOTE: Do not change the pseudoversion. github.com/AdguardTeam/AdGuardDNS/internal/dnsserver v0.0.0-00010101000000-000000000000 - github.com/AdguardTeam/golibs v0.35.3 + github.com/AdguardTeam/golibs v0.35.4 github.com/AdguardTeam/urlfilter v0.22.1 github.com/ameshkov/dnscrypt/v2 v2.4.0 github.com/axiomhq/hyperloglog v0.2.5 @@ -22,7 +22,7 @@ require ( github.com/prometheus/client_golang v1.23.2 github.com/prometheus/client_model v0.6.2 github.com/prometheus/common v0.67.2 - github.com/quic-go/quic-go v0.56.0 + github.com/quic-go/quic-go v0.57.1 github.com/stretchr/testify v1.11.1 github.com/viktordanov/golang-lru v0.5.6 go.yaml.in/yaml/v4 v4.0.0-rc.3 @@ -67,7 +67,7 @@ require ( github.com/panjf2000/ants/v2 v2.11.3 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/procfs v0.19.2 // indirect - github.com/quic-go/qpack v0.5.1 // indirect + github.com/quic-go/qpack v0.6.0 // indirect github.com/robfig/cron/v3 v3.0.1 // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/securego/gosec/v2 v2.22.10 // indirect @@ -87,12 +87,12 @@ require ( golang.org/x/exp/typeparams v0.0.0-20251125195548-87e1e737ad39 // indirect golang.org/x/mod v0.30.0 // indirect golang.org/x/sync v0.18.0 // indirect - golang.org/x/telemetry v0.0.0-20251128220624-abf20d0e57ec // indirect + golang.org/x/telemetry v0.0.0-20251203150158-8fff8a5912fc // indirect golang.org/x/term v0.37.0 // indirect golang.org/x/text v0.31.0 // indirect golang.org/x/tools v0.39.0 // indirect golang.org/x/vuln v1.1.4 // indirect - google.golang.org/genai v1.36.0 // indirect + google.golang.org/genai v1.37.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.6.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 531acf2..0b0ddd7 100644 --- a/go.sum +++ b/go.sum @@ -4,8 +4,8 @@ cloud.google.com/go/auth v0.17.0 h1:74yCm7hCj2rUyyAocqnFzsAYXgJhrG26XCFimrc/Kz4= cloud.google.com/go/auth v0.17.0/go.mod h1:6wv/t5/6rOPAX4fJiRjKkJCvswLwdet7G8+UGXt7nCQ= cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs= cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10= -github.com/AdguardTeam/golibs v0.35.3 h1:DI0ffHyL3tFZ2UBEji3Aah7IvFwM5nY5yZoGvs1bnPY= -github.com/AdguardTeam/golibs v0.35.3/go.mod h1:9Y0yqUpwDNyHxCv4AaI42x5+qxYc7k5DWAfxtFOTn8o= +github.com/AdguardTeam/golibs v0.35.4 h1:7uvSIurqlyiKTSwTlefbOM8Bp7swgI+yb3+gL9al1Ac= +github.com/AdguardTeam/golibs v0.35.4/go.mod h1:meFdRqMtG/PLW6LD20MYAlcRbwAVowlbunHgE17xz9s= github.com/AdguardTeam/urlfilter v0.22.1 h1:nC2x0MSNwmTsXMTPfs1Gv6GZXKmK7prlzgjCdnE4fR8= github.com/AdguardTeam/urlfilter v0.22.1/go.mod h1:+wUx7GApNWvFPALjNd5fTLix4PFvQF5Gprx6JDYwxfE= github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= @@ -132,10 +132,10 @@ github.com/prometheus/common v0.67.2 h1:PcBAckGFTIHt2+L3I33uNRTlKTplNzFctXcWhPyA github.com/prometheus/common v0.67.2/go.mod h1:63W3KZb1JOKgcjlIr64WW/LvFGAqKPj0atm+knVGEko= github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws= github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= -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.56.0 h1:q/TW+OLismmXAehgFLczhCDTYB3bFmua4D9lsNBWxvY= -github.com/quic-go/quic-go v0.56.0/go.mod h1:9gx5KsFQtw2oZ6GZTyh+7YEvOxWCL9WZAepnHxgAo6c= +github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8= +github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII= +github.com/quic-go/quic-go v0.57.1 h1:25KAAR9QR8KZrCZRThWMKVAwGoiHIrNbT72ULHTuI10= +github.com/quic-go/quic-go v0.57.1/go.mod h1:ly4QBAjHA2VhdnxhojRsCUOeJwKYg+taDlos92xb1+s= 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= @@ -203,8 +203,8 @@ golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/telemetry v0.0.0-20251128220624-abf20d0e57ec h1:dRVkWZl6bUOp+oxnOe4BuyhWSIPmt29N4ooHarm7Ic8= -golang.org/x/telemetry v0.0.0-20251128220624-abf20d0e57ec/go.mod h1:hKdjCMrbv9skySur+Nek8Hd0uJ0GuxJIoIX2payrIdQ= +golang.org/x/telemetry v0.0.0-20251203150158-8fff8a5912fc h1:bH6xUXay0AIFMElXG2rQ4uiE+7ncwtiOdPfYK1NK2XA= +golang.org/x/telemetry v0.0.0-20251203150158-8fff8a5912fc/go.mod h1:hKdjCMrbv9skySur+Nek8Hd0uJ0GuxJIoIX2payrIdQ= golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= @@ -221,8 +221,8 @@ golang.org/x/vuln v1.1.4 h1:Ju8QsuyhX3Hk8ma3CesTbO8vfJD9EvUBgHvkxHBzj0I= golang.org/x/vuln v1.1.4/go.mod h1:F+45wmU18ym/ca5PLTPLsSzr2KppzswxPP603ldA67s= 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/genai v1.36.0 h1:sJCIjqTAmwrtAIaemtTiKkg2TO1RxnYEusTmEQ3nGxM= -google.golang.org/genai v1.36.0/go.mod h1:A3kkl0nyBjyFlNjgxIwKq70julKbIxpSxqKO5gw/gmk= +google.golang.org/genai v1.37.0 h1:dgp71k1wQ+/+APdZrN3LFgAGnVnr5IdTF1Oj0Dg+BQc= +google.golang.org/genai v1.37.0/go.mod h1:A3kkl0nyBjyFlNjgxIwKq70julKbIxpSxqKO5gw/gmk= google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 h1:gRkg/vSppuSQoDjxyiGfN4Upv/h/DQmIR10ZU8dh4Ww= google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= diff --git a/go.work.sum b/go.work.sum index c4df943..075f7a3 100644 --- a/go.work.sum +++ b/go.work.sum @@ -540,6 +540,7 @@ github.com/AdguardTeam/golibs v0.31.2/go.mod h1:DzCfc0HFaaKv7sV17gZnSMUiHRtUJ1yp github.com/AdguardTeam/golibs v0.32.7/go.mod h1:bE8KV1zqTzgZjmjFyBJ9f9O5DEKO717r7e57j1HclJA= github.com/AdguardTeam/golibs v0.32.11 h1:75EquS8SWvzsM3JFJY0359ZBw66jDjAegteHzh9nSw8= github.com/AdguardTeam/golibs v0.32.11/go.mod h1:LXr0gqqZuVpt+L+bP3Nnr0/CecLmm3rxkdgyyW5JXXM= +github.com/AdguardTeam/golibs v0.35.3/go.mod h1:9Y0yqUpwDNyHxCv4AaI42x5+qxYc7k5DWAfxtFOTn8o= github.com/AdguardTeam/gomitmproxy v0.2.0 h1:rvCOf17pd1/CnMyMQW891zrEiIQBpQ8cIGjKN9pinUU= github.com/AdguardTeam/gomitmproxy v0.2.1 h1:p9gr8Er1TYvf+7ic81Ax1sZ62UNCsMTZNbm7tC59S9o= github.com/AdguardTeam/gomitmproxy v0.2.1/go.mod h1:Qdv0Mktnzer5zpdpi5rAwixNJzW2FN91LjKJCkVbYGU= @@ -1387,6 +1388,7 @@ github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoG github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= github.com/pseudomuto/protoc-gen-doc v1.3.2/go.mod h1:y5+P6n3iGrbKG+9O04V5ld71in3v/bX88wUwgt+U8EA= github.com/pseudomuto/protokit v0.2.0/go.mod h1:2PdH30hxVHsup8KpBTOXTBeMVhJZVio3Q8ViKSAXT0Q= +github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8= github.com/quic-go/qtls-go1-20 v0.3.3/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= github.com/quic-go/quic-go v0.38.0/go.mod h1:MPCuRq7KBK2hNcfKj/1iD1BGuN3eAYMeNxp3T42LRUg= github.com/quic-go/quic-go v0.39.4/go.mod h1:T09QsDQWjLiQ74ZmacDfqZmhY/NLnw5BC40MANNNZ1Q= @@ -2239,6 +2241,8 @@ golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ= golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s= golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s= +golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= diff --git a/internal/backendpb/dns_grpc.pb.go b/internal/backendpb/dns_grpc.pb.go index fcd09a4..2bfb5c9 100644 --- a/internal/backendpb/dns_grpc.pb.go +++ b/internal/backendpb/dns_grpc.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.5.1 +// - protoc-gen-go-grpc v1.6.0 // - protoc v6.33.1 // source: dns.proto @@ -144,13 +144,13 @@ type DNSServiceServer interface { type UnimplementedDNSServiceServer struct{} func (UnimplementedDNSServiceServer) GetDNSProfiles(*DNSProfilesRequest, grpc.ServerStreamingServer[DNSProfile]) error { - return status.Errorf(codes.Unimplemented, "method GetDNSProfiles not implemented") + return status.Error(codes.Unimplemented, "method GetDNSProfiles not implemented") } func (UnimplementedDNSServiceServer) SaveDevicesBillingStat(grpc.ClientStreamingServer[DeviceBillingStat, emptypb.Empty]) error { - return status.Errorf(codes.Unimplemented, "method SaveDevicesBillingStat not implemented") + return status.Error(codes.Unimplemented, "method SaveDevicesBillingStat not implemented") } func (UnimplementedDNSServiceServer) CreateDeviceByHumanId(context.Context, *CreateDeviceRequest) (*CreateDeviceResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method CreateDeviceByHumanId not implemented") + return nil, status.Error(codes.Unimplemented, "method CreateDeviceByHumanId not implemented") } func (UnimplementedDNSServiceServer) mustEmbedUnimplementedDNSServiceServer() {} func (UnimplementedDNSServiceServer) testEmbeddedByValue() {} @@ -163,7 +163,7 @@ type UnsafeDNSServiceServer interface { } func RegisterDNSServiceServer(s grpc.ServiceRegistrar, srv DNSServiceServer) { - // If the following call pancis, it indicates UnimplementedDNSServiceServer was + // If the following call panics, it indicates UnimplementedDNSServiceServer was // embedded by pointer and is nil. This will cause panics if an // unimplemented method is ever invoked, so we test this at initialization // time to prevent it from happening at runtime later due to I/O. @@ -298,10 +298,10 @@ type RateLimitServiceServer interface { type UnimplementedRateLimitServiceServer struct{} func (UnimplementedRateLimitServiceServer) GetRateLimitSettings(context.Context, *RateLimitSettingsRequest) (*RateLimitSettingsResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetRateLimitSettings not implemented") + return nil, status.Error(codes.Unimplemented, "method GetRateLimitSettings not implemented") } func (UnimplementedRateLimitServiceServer) GetGlobalAccessSettings(context.Context, *GlobalAccessSettingsRequest) (*GlobalAccessSettingsResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetGlobalAccessSettings not implemented") + return nil, status.Error(codes.Unimplemented, "method GetGlobalAccessSettings not implemented") } func (UnimplementedRateLimitServiceServer) mustEmbedUnimplementedRateLimitServiceServer() {} func (UnimplementedRateLimitServiceServer) testEmbeddedByValue() {} @@ -314,7 +314,7 @@ type UnsafeRateLimitServiceServer interface { } func RegisterRateLimitServiceServer(s grpc.ServiceRegistrar, srv RateLimitServiceServer) { - // If the following call pancis, it indicates UnimplementedRateLimitServiceServer was + // If the following call panics, it indicates UnimplementedRateLimitServiceServer was // embedded by pointer and is nil. This will cause panics if an // unimplemented method is ever invoked, so we test this at initialization // time to prevent it from happening at runtime later due to I/O. @@ -460,10 +460,10 @@ type RemoteKVServiceServer interface { type UnimplementedRemoteKVServiceServer struct{} func (UnimplementedRemoteKVServiceServer) Get(context.Context, *RemoteKVGetRequest) (*RemoteKVGetResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method Get not implemented") + return nil, status.Error(codes.Unimplemented, "method Get not implemented") } func (UnimplementedRemoteKVServiceServer) Set(context.Context, *RemoteKVSetRequest) (*RemoteKVSetResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method Set not implemented") + return nil, status.Error(codes.Unimplemented, "method Set not implemented") } func (UnimplementedRemoteKVServiceServer) mustEmbedUnimplementedRemoteKVServiceServer() {} func (UnimplementedRemoteKVServiceServer) testEmbeddedByValue() {} @@ -476,7 +476,7 @@ type UnsafeRemoteKVServiceServer interface { } func RegisterRemoteKVServiceServer(s grpc.ServiceRegistrar, srv RemoteKVServiceServer) { - // If the following call pancis, it indicates UnimplementedRemoteKVServiceServer was + // If the following call panics, it indicates UnimplementedRemoteKVServiceServer was // embedded by pointer and is nil. This will cause panics if an // unimplemented method is ever invoked, so we test this at initialization // time to prevent it from happening at runtime later due to I/O. @@ -601,7 +601,7 @@ type CustomDomainServiceServer interface { type UnimplementedCustomDomainServiceServer struct{} func (UnimplementedCustomDomainServiceServer) GetCustomDomainCertificate(context.Context, *CustomDomainCertificateRequest) (*CustomDomainCertificateResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetCustomDomainCertificate not implemented") + return nil, status.Error(codes.Unimplemented, "method GetCustomDomainCertificate not implemented") } func (UnimplementedCustomDomainServiceServer) mustEmbedUnimplementedCustomDomainServiceServer() {} func (UnimplementedCustomDomainServiceServer) testEmbeddedByValue() {} @@ -614,7 +614,7 @@ type UnsafeCustomDomainServiceServer interface { } func RegisterCustomDomainServiceServer(s grpc.ServiceRegistrar, srv CustomDomainServiceServer) { - // If the following call pancis, it indicates UnimplementedCustomDomainServiceServer was + // If the following call panics, it indicates UnimplementedCustomDomainServiceServer was // embedded by pointer and is nil. This will cause panics if an // unimplemented method is ever invoked, so we test this at initialization // time to prevent it from happening at runtime later due to I/O. @@ -711,7 +711,7 @@ type SessionTicketServiceServer interface { type UnimplementedSessionTicketServiceServer struct{} func (UnimplementedSessionTicketServiceServer) GetSessionTickets(context.Context, *SessionTicketRequest) (*SessionTicketResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetSessionTickets not implemented") + return nil, status.Error(codes.Unimplemented, "method GetSessionTickets not implemented") } func (UnimplementedSessionTicketServiceServer) mustEmbedUnimplementedSessionTicketServiceServer() {} func (UnimplementedSessionTicketServiceServer) testEmbeddedByValue() {} @@ -724,7 +724,7 @@ type UnsafeSessionTicketServiceServer interface { } func RegisterSessionTicketServiceServer(s grpc.ServiceRegistrar, srv SessionTicketServiceServer) { - // If the following call pancis, it indicates UnimplementedSessionTicketServiceServer was + // If the following call panics, it indicates UnimplementedSessionTicketServiceServer was // embedded by pointer and is nil. This will cause panics if an // unimplemented method is ever invoked, so we test this at initialization // time to prevent it from happening at runtime later due to I/O. diff --git a/internal/cmd/builder.go b/internal/cmd/builder.go index da226b1..d90287c 100644 --- a/internal/cmd/builder.go +++ b/internal/cmd/builder.go @@ -1542,6 +1542,7 @@ func (b *builder) initProfileDB(ctx context.Context) (err error) { ErrColl: b.errColl, ProfileMetrics: profileMtrc, Metrics: profDBMtrc, + Opaque: b.env.ProfilesCacheType == profileCacheTypeOpaque, Storage: strg, CacheFilePath: b.env.ProfilesCachePath, CacheFileIvl: time.Duration(b.env.ProfilesCacheIvl), diff --git a/internal/cmd/env.go b/internal/cmd/env.go index 7d9e47f..8bc9432 100644 --- a/internal/cmd/env.go +++ b/internal/cmd/env.go @@ -28,6 +28,16 @@ import ( "github.com/getsentry/sentry-go" ) +const ( + // profileCacheTypeDefault is a profile cache type that uses protobuf + // Open Struct API. + profileCacheTypeDefault = "default" + + // profileCacheTypeOpaque is a profile cache type that uses protobuf opaque + // API. + profileCacheTypeOpaque = "opaque" +) + // environment represents the configuration that is kept in the environment. // // TODO(e.burkov, a.garipov): Name variables more consistently. @@ -80,6 +90,7 @@ type environment struct { SessionTicketType string `env:"SESSION_TICKET_TYPE"` StandardAccessAPIKey string `env:"STANDARD_ACCESS_API_KEY"` StandardAccessType string `env:"STANDARD_ACCESS_TYPE"` + ProfilesCacheType string `env:"PROFILES_CACHE_TYPE"` // TODO(a.garipov): Consider renaming to "WEB_STATIC_PATH" or something // similar. @@ -482,6 +493,22 @@ func (envs *environment) validateProfilesConf(profilesEnabled bool) (err error) validate.Positive("PROFILES_CACHE_INTERVAL", envs.ProfilesCacheIvl), ) + if envs.ProfilesCachePath == "none" { + return errors.Join(errs...) + } + + errs = append(errs, validate.NotEmpty("PROFILES_CACHE_TYPE", envs.ProfilesCacheType)) + + switch typ := envs.ProfilesCacheType; typ { + case + profileCacheTypeDefault, + profileCacheTypeOpaque, + "": + default: + err = fmt.Errorf("env PROFILES_CACHE_TYPE: %w: %q", errors.ErrBadEnumValue, typ) + errs = append(errs, err) + } + return errors.Join(errs...) } diff --git a/internal/debugsvc/route.go b/internal/debugsvc/route.go index 8950840..ebda942 100644 --- a/internal/debugsvc/route.go +++ b/internal/debugsvc/route.go @@ -5,16 +5,21 @@ import ( "net/http" "github.com/AdguardTeam/AdGuardDNS/internal/agdhttp" + "github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/logutil/slogutil" "github.com/AdguardTeam/golibs/netutil/httputil" "github.com/prometheus/client_golang/prometheus/promhttp" ) +// ErrDebugPanic is a default error for panic handler. +const ErrDebugPanic errors.Error = "debug panic" + // Path pattern constants. const ( PathPatternDNSDBCSV = "/dnsdb/csv" PathPatternDebugAPICache = "/debug/api/cache/clear" PathPatternDebugAPIRefresh = "/debug/api/refresh" + PathPatternDebugPanic = "/debug/panic" PathPatternHealthCheck = "/health-check" PathPatternMetrics = "/metrics" ) @@ -24,6 +29,7 @@ const ( routePatternDNSDBCSV = http.MethodPost + " " + PathPatternDNSDBCSV routePatternDebugAPICache = http.MethodPost + " " + PathPatternDebugAPICache routePatternDebugAPIRefresh = http.MethodPost + " " + PathPatternDebugAPIRefresh + routePatternDebugPanic = http.MethodPost + " " + PathPatternDebugPanic routePatternHealthCheck = http.MethodGet + " " + PathPatternHealthCheck routePatternMetrics = http.MethodGet + " " + PathPatternMetrics ) @@ -47,6 +53,7 @@ func (svc *Service) route(c *Config) { infoLogMw := httputil.NewLogMiddleware(l, slog.LevelInfo) router.Handle(routePatternDebugAPIRefresh, infoLogMw.Wrap(svc.refrHdlr)) router.Handle(routePatternDebugAPICache, infoLogMw.Wrap(svc.cacheHdlr)) + router.Handle(routePatternDebugPanic, infoLogMw.Wrap(httputil.PanicHandler(ErrDebugPanic))) } if srv := svc.servers[c.DNSDBAddr]; srv != nil { diff --git a/internal/dnscheck/remotekv.go b/internal/dnscheck/remotekv.go index 489325d..f70fb1e 100644 --- a/internal/dnscheck/remotekv.go +++ b/internal/dnscheck/remotekv.go @@ -2,6 +2,7 @@ package dnscheck import ( "context" + "crypto/tls" "encoding/json" "fmt" "log/slog" @@ -14,6 +15,7 @@ import ( "github.com/AdguardTeam/AdGuardDNS/internal/agd" "github.com/AdguardTeam/AdGuardDNS/internal/agdhttp" "github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg" + "github.com/AdguardTeam/AdGuardDNS/internal/dnsserver" "github.com/AdguardTeam/AdGuardDNS/internal/errcoll" "github.com/AdguardTeam/AdGuardDNS/internal/remotekv" "github.com/AdguardTeam/AdGuardDNS/internal/remotekv/consulkv" @@ -113,7 +115,8 @@ func NewRemoteKV(c *RemoteKVConfig) (dc *RemoteKV) { // type check var _ Interface = (*RemoteKV)(nil) -// Check implements the Interface interface for *RemoteKV. +// Check implements the Interface interface for *RemoteKV. ctx must contain +// request info (retrieved by [dnsserver.MustRequestInfoFromContext]). func (dc *RemoteKV) Check( ctx context.Context, req *dns.Msg, @@ -142,7 +145,7 @@ func (dc *RemoteKV) Check( return dc.resp(ri, req) } - inf := dc.newInfo(ri) + inf := dc.newInfo(ctx, ri) b, err := json.Marshal(inf) if err != nil { return nil, fmt.Errorf("encoding value for key %q for remote kv: %w", randomID, err) @@ -178,8 +181,9 @@ const ( ) // newInfo returns an information record with all available data about the -// server and the request. ri must not be nil. -func (dc *RemoteKV) newInfo(ri *agd.RequestInfo) (inf *info) { +// server and the request. ri must not be nil. ctx must contain request info +// (retrieved by [dnsserver.MustRequestInfoFromContext]). +func (dc *RemoteKV) newInfo(ctx context.Context, ri *agd.RequestInfo) (inf *info) { srvInfo := ri.ServerInfo srvType := serverTypePublic @@ -188,15 +192,16 @@ func (dc *RemoteKV) newInfo(ri *agd.RequestInfo) (inf *info) { } inf = &info{ + ClientIP: ri.RemoteIP, + ServerGroupName: srvInfo.GroupName, ServerName: srvInfo.Name, ServerType: srvType, - Protocol: srvInfo.Protocol.String(), NodeLocation: dc.nodeLocation, NodeName: dc.nodeName, - - ClientIP: ri.RemoteIP, + Protocol: srvInfo.Protocol.String(), + TLSCurveID: tlsCurveID(ctx), } if p, d := ri.DeviceData(); p != nil { @@ -207,6 +212,23 @@ func (dc *RemoteKV) newInfo(ri *agd.RequestInfo) (inf *info) { return inf } +// tlsCurveID returns the TLS curve ID string representation from the request +// context. ctx must contain request info (retrieved by +// [dnsserver.MustRequestInfoFromContext]). +func tlsCurveID(ctx context.Context) (curveIDStr string) { + srvReqInfo := dnsserver.MustRequestInfoFromContext(ctx) + if srvReqInfo.TLS == nil { + return "" + } + + curveID := srvReqInfo.TLS.CurveID + if curveID != tls.CurveID(0) { + return curveID.String() + } + + return "" +} + // resp returns the corresponding response. // // TODO(e.burkov): Inspect the reason for using different message constructors @@ -343,7 +365,8 @@ type info struct { ServerName agd.ServerName `json:"server_name"` ServerType serverType `json:"server_type"` - Protocol string `json:"protocol"` NodeLocation string `json:"node_location"` NodeName string `json:"node_name"` + Protocol string `json:"protocol"` + TLSCurveID string `json:"tls_curve_id"` } diff --git a/internal/dnscheck/remotekv_test.go b/internal/dnscheck/remotekv_test.go index 2006af5..a4876f8 100644 --- a/internal/dnscheck/remotekv_test.go +++ b/internal/dnscheck/remotekv_test.go @@ -2,6 +2,7 @@ package dnscheck_test import ( "context" + "crypto/tls" "encoding/json" "net" "net/http" @@ -16,6 +17,7 @@ import ( "github.com/AdguardTeam/AdGuardDNS/internal/agdtest" "github.com/AdguardTeam/AdGuardDNS/internal/dnscheck" "github.com/AdguardTeam/AdGuardDNS/internal/dnsmsg" + "github.com/AdguardTeam/AdGuardDNS/internal/dnsserver" "github.com/AdguardTeam/AdGuardDNS/internal/remotekv" "github.com/AdguardTeam/golibs/logutil/slogutil" "github.com/AdguardTeam/golibs/netutil/urlutil" @@ -44,6 +46,7 @@ func TestConsul_ServeHTTP(t *testing.T) { "node_name": "some-node-name", "client_ip": "1.2.3.4", "server_type": "private", + "tls_curve_id": "X25519", } conf := &dnscheck.RemoteKVConfig{ @@ -59,6 +62,11 @@ func TestConsul_ServeHTTP(t *testing.T) { dnsCk := dnscheck.NewRemoteKV(conf) ctx := context.Background() + ctx = dnsserver.ContextWithRequestInfo(ctx, &dnsserver.RequestInfo{ + TLS: &tls.ConnectionState{ + CurveID: tls.X25519, + }, + }) var resp *dns.Msg resp, err := dnsCk.Check( @@ -187,6 +195,11 @@ func TestConsul_Check(t *testing.T) { dnsCk := dnscheck.NewRemoteKV(conf) ctx := context.Background() + ctx = dnsserver.ContextWithRequestInfo(ctx, &dnsserver.RequestInfo{ + TLS: &tls.ConnectionState{ + CurveID: tls.X25519, + }, + }) for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { diff --git a/internal/dnsserver/context.go b/internal/dnsserver/context.go index 69cf8b1..7822f45 100644 --- a/internal/dnsserver/context.go +++ b/internal/dnsserver/context.go @@ -2,6 +2,7 @@ package dnsserver import ( "context" + "crypto/tls" "fmt" "net/url" "time" @@ -78,6 +79,11 @@ func MustServerInfoFromContext(ctx context.Context) (si *ServerInfo) { // RequestInfo is a structure that contains basic request information. It is // attached to every context.Context linked to processing a DNS request. type RequestInfo struct { + // TLS is the TLS connection state. It is set only if the protocol of the + // server is either DoQ, DoT or DoH. It must not be nil if the protocol is + // DoQ or DoT. + TLS *tls.ConnectionState + // URL is the request URL. It is set only if the protocol of the server is // DoH. URL *url.URL @@ -88,13 +94,6 @@ type RequestInfo struct { // StartTime is the request's start time. It's never zero value. StartTime time.Time - - // TLSServerName is the original, non-lowercased server name field of the - // client's TLS hello request. It is set only if the protocol of the server - // is either DoQ, DoT or DoH. - // - // TODO(ameshkov): use r.TLS with DoH3 (see addRequestInfo). - TLSServerName string } // ContextWithRequestInfo attaches RequestInfo to the specified context. ri diff --git a/internal/dnsserver/dnsservertest/handler.go b/internal/dnsserver/dnsservertest/handler.go index 0eedd51..e92c8d2 100644 --- a/internal/dnsserver/dnsservertest/handler.go +++ b/internal/dnsserver/dnsservertest/handler.go @@ -27,8 +27,8 @@ func NewDefaultHandlerWithCount(recordsCount int) (h dnsserver.Handler) { // Check that necessary context keys are set. si := dnsserver.MustServerInfoFromContext(ctx) ri := dnsserver.MustRequestInfoFromContext(ctx) - if si.Proto.IsStdEncrypted() && ri.TLSServerName == "" { - return errors.Error("client info does not contain server name") + if si.Proto.IsStdEncrypted() && ri.TLS == nil { + return errors.Error("client info does not contain tls connection info") } ans := make(SectionAnswer, 0, recordsCount) diff --git a/internal/dnsserver/go.mod b/internal/dnsserver/go.mod index c2fca1d..c25d3a4 100644 --- a/internal/dnsserver/go.mod +++ b/internal/dnsserver/go.mod @@ -3,7 +3,7 @@ module github.com/AdguardTeam/AdGuardDNS/internal/dnsserver go 1.25.5 require ( - github.com/AdguardTeam/golibs v0.35.3 + github.com/AdguardTeam/golibs v0.35.4 github.com/ameshkov/dnscrypt/v2 v2.4.0 github.com/ameshkov/dnsstamps v1.0.3 github.com/bluele/gcache v0.0.2 @@ -12,7 +12,7 @@ require ( github.com/panjf2000/ants/v2 v2.11.3 github.com/patrickmn/go-cache v2.1.1-0.20191004192108-46f407853014+incompatible github.com/prometheus/client_golang v1.23.2 - github.com/quic-go/quic-go v0.56.0 + github.com/quic-go/quic-go v0.57.1 github.com/stretchr/testify v1.11.1 golang.org/x/net v0.47.0 golang.org/x/sys v0.38.0 @@ -28,7 +28,7 @@ require ( github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.67.2 // indirect github.com/prometheus/procfs v0.19.2 // indirect - github.com/quic-go/qpack v0.5.1 // indirect + github.com/quic-go/qpack v0.6.0 // indirect github.com/robfig/cron/v3 v3.0.1 // indirect go.uber.org/mock v0.6.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect diff --git a/internal/dnsserver/go.sum b/internal/dnsserver/go.sum index 156888a..b5343c5 100644 --- a/internal/dnsserver/go.sum +++ b/internal/dnsserver/go.sum @@ -1,4 +1,5 @@ -github.com/AdguardTeam/golibs v0.35.3 h1:DI0ffHyL3tFZ2UBEji3Aah7IvFwM5nY5yZoGvs1bnPY= +github.com/AdguardTeam/golibs v0.35.4 h1:7uvSIurqlyiKTSwTlefbOM8Bp7swgI+yb3+gL9al1Ac= +github.com/AdguardTeam/golibs v0.35.4/go.mod h1:meFdRqMtG/PLW6LD20MYAlcRbwAVowlbunHgE17xz9s= github.com/ameshkov/dnscrypt/v2 v2.4.0 h1:if6ZG2cuQmcP2TwSY+D0+8+xbPfoatufGlOQTMNkI9o= github.com/ameshkov/dnscrypt/v2 v2.4.0/go.mod h1:WpEFV2uhebXb8Jhes/5/fSdpmhGV8TL22RDaeWwV6hI= github.com/ameshkov/dnsstamps v1.0.3 h1:Srzik+J9mivH1alRACTbys2xOxs0lRH9qnTA7Y1OYVo= @@ -35,10 +36,13 @@ github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UH github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= github.com/prometheus/common v0.67.2 h1:PcBAckGFTIHt2+L3I33uNRTlKTplNzFctXcWhPyAEN8= +github.com/prometheus/common v0.67.2/go.mod h1:63W3KZb1JOKgcjlIr64WW/LvFGAqKPj0atm+knVGEko= github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws= -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.56.0 h1:q/TW+OLismmXAehgFLczhCDTYB3bFmua4D9lsNBWxvY= +github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= +github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8= +github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII= +github.com/quic-go/quic-go v0.57.1 h1:25KAAR9QR8KZrCZRThWMKVAwGoiHIrNbT72ULHTuI10= +github.com/quic-go/quic-go v0.57.1/go.mod h1:ly4QBAjHA2VhdnxhojRsCUOeJwKYg+taDlos92xb1+s= 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= @@ -52,14 +56,23 @@ go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= +golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 h1:mgKeJMpvi0yx/sU5GsxQ7p6s2wtOnGAHZWCHUM4KGzY= +golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546/go.mod h1:j/pmGrbnkbPtQfxEe5D0VQhZC6qKbfKifgD0oM7sR70= golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= +golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= +golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= +golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= +golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= +golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= +golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= +golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/internal/dnsserver/serverdnstcp.go b/internal/dnsserver/serverdnstcp.go index 3bfdc04..40010de 100644 --- a/internal/dnsserver/serverdnstcp.go +++ b/internal/dnsserver/serverdnstcp.go @@ -183,7 +183,8 @@ func (s *ServerDNS) acceptTCPMsg( StartTime: time.Now(), } if cs, ok := conn.(tlsConnectionStater); ok { - ri.TLSServerName = cs.ConnectionState().ServerName + tlsConnState := cs.ConnectionState() + ri.TLS = &tlsConnState } reqCtx, reqCancel := s.requestContext(context.Background()) diff --git a/internal/dnsserver/serverhttps.go b/internal/dnsserver/serverhttps.go index 3eca3c8..25735e0 100644 --- a/internal/dnsserver/serverhttps.go +++ b/internal/dnsserver/serverhttps.go @@ -563,12 +563,9 @@ func addRequestInfo(parent context.Context, r *http.Request) (ctx context.Contex ctx = parent ri := &RequestInfo{ - StartTime: time.Now(), + TLS: r.TLS, URL: netutil.CloneURL(r.URL), - } - - if r.TLS != nil { - ri.TLSServerName = r.TLS.ServerName + StartTime: time.Now(), } if username, pass, ok := r.BasicAuth(); ok { diff --git a/internal/dnsserver/serverhttps_test.go b/internal/dnsserver/serverhttps_test.go index 68258dd..d542b7d 100644 --- a/internal/dnsserver/serverhttps_test.go +++ b/internal/dnsserver/serverhttps_test.go @@ -106,7 +106,11 @@ func TestServerHTTPS_integration_serveRequests(t *testing.T) { t.Run(tc.name, func(t *testing.T) { t.Parallel() - tlsConfig := dnsservertest.CreateServerTLSConfig("example.org") + var tlsConfig *tls.Config + if tc.tls { + tlsConfig = dnsservertest.CreateServerTLSConfig("example.org") + } + srv, err := dnsservertest.RunLocalHTTPSServer( dnsservertest.NewDefaultHandler(), tlsConfig, diff --git a/internal/dnsserver/serverquic.go b/internal/dnsserver/serverquic.go index 4329309..041e188 100644 --- a/internal/dnsserver/serverquic.go +++ b/internal/dnsserver/serverquic.go @@ -364,9 +364,10 @@ func (s *ServerQUIC) serveQUICConn(ctx context.Context, conn *quic.Conn) (err er return err } + tlsConnState := conn.ConnectionState().TLS ri := &RequestInfo{ - StartTime: time.Now(), - TLSServerName: conn.ConnectionState().TLS.ServerName, + TLS: &tlsConnState, + StartTime: time.Now(), } reqCtx, reqCancel := s.requestContext(context.Background()) diff --git a/internal/dnssvc/integration_test.go b/internal/dnssvc/integration_test.go index 03ec393..11cb155 100644 --- a/internal/dnssvc/integration_test.go +++ b/internal/dnssvc/integration_test.go @@ -359,10 +359,9 @@ func TestService_Wrap(t *testing.T) { clientAddr, ) - ctx = dnsserver.ContextWithRequestInfo(ctx, &dnsserver.RequestInfo{ - StartTime: time.Now(), - TLSServerName: dnssvctest.DeviceIDSrvName, - }) + ctx = dnsserver.ContextWithRequestInfo(ctx, dnssvctest.NewRequestInfo( + dnssvctest.DeviceIDSrvName, + )) err := svc.Handle(ctx, dnssvctest.ServerGroupName, dnssvctest.ServerName, rw, req) require.NoError(t, err) @@ -428,10 +427,9 @@ func TestService_Wrap(t *testing.T) { clientAddr, ) - ctx = dnsserver.ContextWithRequestInfo(ctx, &dnsserver.RequestInfo{ - StartTime: time.Now(), - TLSServerName: dnssvctest.DeviceIDSrvName, - }) + ctx = dnsserver.ContextWithRequestInfo(ctx, dnssvctest.NewRequestInfo( + dnssvctest.DeviceIDSrvName, + )) err := svc.Handle(ctx, dnssvctest.ServerGroupName, dnssvctest.ServerName, rw, req) require.NoError(t, err) diff --git a/internal/dnssvc/internal/devicefinder/device_test.go b/internal/dnssvc/internal/devicefinder/device_test.go index 53bb539..b498804 100644 --- a/internal/dnssvc/internal/devicefinder/device_test.go +++ b/internal/dnssvc/internal/devicefinder/device_test.go @@ -216,9 +216,9 @@ func TestDefault_Find_byHumanID(t *testing.T) { }) ctx := testutil.ContextWithTimeout(t, dnssvctest.Timeout) - ctx = dnsserver.ContextWithRequestInfo(ctx, &dnsserver.RequestInfo{ - TLSServerName: extIDStr + "." + dnssvctest.DomainForDevices, - }) + ctx = dnsserver.ContextWithRequestInfo(ctx, dnssvctest.NewRequestInfo( + extIDStr+"."+dnssvctest.DomainForDevices, + )) got := df.Find(ctx, reqNormal, dnssvctest.ClientAddrPort, dnssvctest.ServerAddrPort) require.Equal(t, resAuto, got) diff --git a/internal/dnssvc/internal/devicefinder/devicedata.go b/internal/dnssvc/internal/devicefinder/devicedata.go index 94729b9..a26c67d 100644 --- a/internal/dnssvc/internal/devicefinder/devicedata.go +++ b/internal/dnssvc/internal/devicefinder/devicedata.go @@ -125,16 +125,22 @@ func (f *Default) deviceDataFromEncrypted( ctx context.Context, srvReqInfo *dnsserver.RequestInfo, ) (dd deviceData, err error) { - var customDomain string - var requiredProfileIDs []agd.ProfileID - if cliSrvName := strings.ToLower(srvReqInfo.TLSServerName); cliSrvName != "" { - customDomain, requiredProfileIDs = f.customDomainDB.Match(ctx, cliSrvName) - if customDomain != "" { - f.metrics.IncrementCustomDomainRequests(ctx, customDomain) - } + cliSrvName := "" + if srvReqInfo.TLS != nil { + cliSrvName = srvReqInfo.TLS.ServerName } - dd, err = f.deviceDataFromSrvReqInfo(ctx, srvReqInfo, customDomain) + customDomain := "" + var requiredProfileIDs []agd.ProfileID + if cliSrvName != "" { + customDomain, requiredProfileIDs = f.customDomainDB.Match(ctx, strings.ToLower(cliSrvName)) + } + + if customDomain != "" { + f.metrics.IncrementCustomDomainRequests(ctx, customDomain) + } + + dd, err = f.deviceDataFromSrvReqInfo(ctx, srvReqInfo, customDomain, cliSrvName) if err != nil { return nil, fmt.Errorf("extracting device data: %w", err) } @@ -159,11 +165,12 @@ func (f *Default) deviceDataFromEncrypted( // Any returned errors will have the underlying type of [*deviceDataError]. // // If customDomain is not empty, it must be a domain name or wildcard matching -// srvReqInfo.TLSServerName. +// srvReqInfo.TLS.ServerName. srvReqInfo must not be nil. func (f *Default) deviceDataFromSrvReqInfo( ctx context.Context, srvReqInfo *dnsserver.RequestInfo, customDomain string, + cliSrvName string, ) (dd deviceData, err error) { if f.srv.Protocol == agd.ProtoDoH { dd, err = f.deviceDataForDoH(srvReqInfo) @@ -196,7 +203,7 @@ func (f *Default) deviceDataFromSrvReqInfo( customDomain = strings.TrimPrefix(customDomain, "*.") - dd, err = f.deviceDataFromCliSrvName(ctx, srvReqInfo.TLSServerName, customDomain) + dd, err = f.deviceDataFromCliSrvName(ctx, cliSrvName, customDomain) if err != nil { return nil, newDeviceDataError(err, "tls server name") } diff --git a/internal/dnssvc/internal/devicefinder/devicedata_test.go b/internal/dnssvc/internal/devicefinder/devicedata_test.go index 31edb4a..967c1a3 100644 --- a/internal/dnssvc/internal/devicefinder/devicedata_test.go +++ b/internal/dnssvc/internal/devicefinder/devicedata_test.go @@ -2,6 +2,7 @@ package devicefinder_test import ( "context" + "crypto/tls" "net/url" "path" "slices" @@ -104,11 +105,15 @@ func TestDefault_Find_DoHAuth(t *testing.T) { ProfileDB: profDB, }) + tlsConnState := &tls.ConnectionState{ + ServerName: dnssvctest.DomainForDevices, + } + ctx := testutil.ContextWithTimeout(t, dnssvctest.Timeout) ctx = dnsserver.ContextWithRequestInfo(ctx, &dnsserver.RequestInfo{ - TLSServerName: dnssvctest.DomainForDevices, - URL: tc.reqURL, - Userinfo: tc.reqURL.User, + TLS: tlsConnState, + URL: tc.reqURL, + Userinfo: tc.reqURL.User, }) got := df.Find(ctx, reqNormal, dnssvctest.ClientAddrPort, dnssvctest.ServerAddrPort) @@ -198,9 +203,12 @@ func TestDefault_Find_DoHAuthOnly(t *testing.T) { DeviceDomains: []string{dnssvctest.DomainForDevices}, }) + tlsConnState := &tls.ConnectionState{ + ServerName: tc.cliSrvName, + } srvReqInfo := &dnsserver.RequestInfo{ - TLSServerName: tc.cliSrvName, - URL: tc.reqURL, + TLS: tlsConnState, + URL: tc.reqURL, } if tc.reqURL != nil { srvReqInfo.Userinfo = tc.reqURL.User @@ -297,10 +305,13 @@ func TestDefault_Find_DoH(t *testing.T) { ProfileDB: profDB, }) + tlsConnState := &tls.ConnectionState{ + ServerName: dnssvctest.DomainForDevices, + } ctx := testutil.ContextWithTimeout(t, dnssvctest.Timeout) ctx = dnsserver.ContextWithRequestInfo(ctx, &dnsserver.RequestInfo{ - TLSServerName: dnssvctest.DomainForDevices, - URL: tc.reqURL, + TLS: tlsConnState, + URL: tc.reqURL, }) got := df.Find(ctx, reqNormal, dnssvctest.ClientAddrPort, dnssvctest.ServerAddrPort) @@ -388,10 +399,14 @@ func TestDefault_Find_stdEncrypted(t *testing.T) { DeviceDomains: tc.deviceDomains, }) + tlsConnState := &tls.ConnectionState{ + ServerName: tc.cliSrvName, + } + ctx := testutil.ContextWithTimeout(t, dnssvctest.Timeout) ctx = dnsserver.ContextWithRequestInfo(ctx, &dnsserver.RequestInfo{ - TLSServerName: tc.cliSrvName, - URL: sd.reqURL, + TLS: tlsConnState, + URL: sd.reqURL, }) got := df.Find(ctx, reqNormal, dnssvctest.ClientAddrPort, dnssvctest.ServerAddrPort) @@ -559,9 +574,7 @@ func TestDefault_Find_customDomainDoT(t *testing.T) { }) ctx := testutil.ContextWithTimeout(t, dnssvctest.Timeout) - ctx = dnsserver.ContextWithRequestInfo(ctx, &dnsserver.RequestInfo{ - TLSServerName: tc.cliSrvName, - }) + ctx = dnsserver.ContextWithRequestInfo(ctx, dnssvctest.NewRequestInfo(tc.cliSrvName)) got := df.Find(ctx, reqNormal, dnssvctest.ClientAddrPort, dnssvctest.ServerAddrPort) assertEqualResult(t, tc.wantRes, got) diff --git a/internal/dnssvc/internal/devicefinder/devicefinder_test.go b/internal/dnssvc/internal/devicefinder/devicefinder_test.go index 4e67f66..d473b5f 100644 --- a/internal/dnssvc/internal/devicefinder/devicefinder_test.go +++ b/internal/dnssvc/internal/devicefinder/devicefinder_test.go @@ -3,6 +3,7 @@ package devicefinder_test import ( "cmp" "context" + "crypto/tls" "net/netip" "net/url" "os" @@ -356,11 +357,9 @@ func BenchmarkDefault(b *testing.B) { ProfileDB: profDB, DeviceDomains: []string{dnssvctest.DomainForDevices}, }, - req: reqNormal, - srvReqInfo: &dnsserver.RequestInfo{ - TLSServerName: dnssvctest.DeviceIDSrvName, - }, - name: "dot", + req: reqNormal, + srvReqInfo: dnssvctest.NewRequestInfo(dnssvctest.DeviceIDSrvName), + name: "dot", }, { conf: &devicefinder.Config{ ProfileDB: profDB, @@ -368,7 +367,9 @@ func BenchmarkDefault(b *testing.B) { }, req: reqNormal, srvReqInfo: &dnsserver.RequestInfo{ - TLSServerName: dnssvctest.DeviceIDSrvName, + TLS: &tls.ConnectionState{ + ServerName: dnssvctest.DeviceIDSrvName, + }, URL: &url.URL{ Path: dnsserver.PathDoH, }, @@ -381,7 +382,9 @@ func BenchmarkDefault(b *testing.B) { }, req: reqNormal, srvReqInfo: &dnsserver.RequestInfo{ - TLSServerName: dnssvctest.DomainForDevices, + TLS: &tls.ConnectionState{ + ServerName: dnssvctest.DomainForDevices, + }, URL: &url.URL{ Path: path.Join(dnsserver.PathDoH, dnssvctest.DeviceIDStr), }, @@ -441,14 +444,14 @@ func BenchmarkDefault(b *testing.B) { // Most recent results: // - // goos: linux - // goarch: amd64 - // pkg: github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal/devicefinder - // cpu: AMD Ryzen 7 PRO 4750U with Radeon Graphics - // BenchmarkDefault/dot-16 2654976 406.5 ns/op 32 B/op 2 allocs/op - // BenchmarkDefault/doh_domain-16 1560818 758.5 ns/op 80 B/op 4 allocs/op - // BenchmarkDefault/doh_path-16 1922390 639.2 ns/op 96 B/op 4 allocs/op - // BenchmarkDefault/dns_edns-16 3430594 396.1 ns/op 40 B/op 3 allocs/op - // BenchmarkDefault/dns_laddr-16 6179818 206.0 ns/op 16 B/op 1 allocs/op - // BenchmarkDefault/dns_raddr-16 6360699 184.4 ns/op 16 B/op 1 allocs/op + // goos: darwin + // goarch: arm64 + // pkg: github.com/AdguardTeam/AdGuardDNS/internal/dnssvc/internal/devicefinder + // cpu: Apple M1 Pro + // BenchmarkDefault/dot-8 6804558 164.8 ns/op 32 B/op 2 allocs/op + // BenchmarkDefault/doh_domain-8 5155173 233.5 ns/op 80 B/op 4 allocs/op + // BenchmarkDefault/doh_path-8 6002018 197.6 ns/op 96 B/op 4 allocs/op + // BenchmarkDefault/dns_edns-8 12959406 91.83 ns/op 40 B/op 3 allocs/op + // BenchmarkDefault/dns_laddr-8 26600607 44.65 ns/op 16 B/op 1 allocs/op + // BenchmarkDefault/dns_raddr-8 28741998 42.14 ns/op 16 B/op 1 allocs/op } diff --git a/internal/dnssvc/internal/devicefinder/humanid_test.go b/internal/dnssvc/internal/devicefinder/humanid_test.go index 7db0aac..4219b28 100644 --- a/internal/dnssvc/internal/devicefinder/humanid_test.go +++ b/internal/dnssvc/internal/devicefinder/humanid_test.go @@ -58,9 +58,9 @@ func TestDefault_Find_humanID(t *testing.T) { }) ctx := testutil.ContextWithTimeout(t, dnssvctest.Timeout) - ctx = dnsserver.ContextWithRequestInfo(ctx, &dnsserver.RequestInfo{ - TLSServerName: tc.in + "." + dnssvctest.DomainForDevices, - }) + ctx = dnsserver.ContextWithRequestInfo(ctx, dnssvctest.NewRequestInfo( + tc.in+"."+dnssvctest.DomainForDevices, + )) got := df.Find(ctx, reqNormal, dnssvctest.ClientAddrPort, dnssvctest.ServerAddrPort) assertEqualResult(t, tc.wantRes, got) diff --git a/internal/dnssvc/internal/dnssvctest/dnssvctest.go b/internal/dnssvc/internal/dnssvctest/dnssvctest.go index b992e05..d5d02c6 100644 --- a/internal/dnssvc/internal/dnssvctest/dnssvctest.go +++ b/internal/dnssvc/internal/dnssvctest/dnssvctest.go @@ -9,6 +9,7 @@ import ( "time" "github.com/AdguardTeam/AdGuardDNS/internal/agd" + "github.com/AdguardTeam/AdGuardDNS/internal/dnsserver" "github.com/AdguardTeam/AdGuardDNS/internal/filter" "github.com/miekg/dns" ) @@ -169,3 +170,13 @@ func NewServer( return srv } + +// NewRequestInfo returns a new *dnsserver.RequestInfo for tests. +func NewRequestInfo(tlsSrvName string) (ri *dnsserver.RequestInfo) { + return &dnsserver.RequestInfo{ + TLS: &tls.ConnectionState{ + ServerName: tlsSrvName, + }, + StartTime: time.Now(), + } +} diff --git a/internal/errcoll/sentry.go b/internal/errcoll/sentry.go index 4210bca..56e639b 100644 --- a/internal/errcoll/sentry.go +++ b/internal/errcoll/sentry.go @@ -216,7 +216,12 @@ func tagsFromCtx(ctx context.Context) (tags sentryTags) { } if ri, ok := dnsserver.RequestInfoFromContext(ctx); ok { - tags["dns_client_tls_server_name"] = toASCII(ri.TLSServerName) + tlsSrvName := "" + if ri.TLS != nil { + tlsSrvName = ri.TLS.ServerName + } + tags["dns_client_tls_server_name"] = toASCII(tlsSrvName) + if ri.URL != nil { // Provide only the path and the query to fit into Sentry's 200 // characters limit. diff --git a/internal/profiledb/config.go b/internal/profiledb/config.go index 68d9bcf..24e66b5 100644 --- a/internal/profiledb/config.go +++ b/internal/profiledb/config.go @@ -65,4 +65,8 @@ type Config struct { // the purposes of custom ratelimiting. Responses over this estimate are // counted as several responses. It must be positive. ResponseSizeEstimate datasize.ByteSize + + // Opaque determines whether the profile cache will use the protobuf opaque + // API. + Opaque bool } diff --git a/internal/profiledb/default.go b/internal/profiledb/default.go index 2a466bb..20415ed 100644 --- a/internal/profiledb/default.go +++ b/internal/profiledb/default.go @@ -6,7 +6,6 @@ import ( "log/slog" "maps" "net/netip" - "path/filepath" "slices" "sync" "time" @@ -14,6 +13,7 @@ import ( "github.com/AdguardTeam/AdGuardDNS/internal/agd" "github.com/AdguardTeam/AdGuardDNS/internal/errcoll" "github.com/AdguardTeam/AdGuardDNS/internal/profiledb/internal" + "github.com/AdguardTeam/AdGuardDNS/internal/profiledb/internal/filecacheopb" "github.com/AdguardTeam/AdGuardDNS/internal/profiledb/internal/filecachepb" "github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/logutil/slogutil" @@ -127,7 +127,15 @@ func New(c *Config) (db *Default, err error) { var cacheStorage internal.FileCacheStorage if c.CacheFilePath == "none" { cacheStorage = internal.EmptyFileCacheStorage{} - } else if ext := filepath.Ext(c.CacheFilePath); ext == ".pb" { + } else if c.Opaque { + cacheStorage = filecacheopb.New(&filecacheopb.Config{ + Logger: c.Logger.With("cache_type", "opb"), + BaseCustomLogger: c.BaseCustomLogger, + ProfileAccessConstructor: c.ProfileAccessConstructor, + CacheFilePath: c.CacheFilePath, + ResponseSizeEstimate: c.ResponseSizeEstimate, + }) + } else { cacheStorage = filecachepb.New(&filecachepb.Config{ Logger: c.Logger.With("cache_type", "pb"), BaseCustomLogger: c.BaseCustomLogger, @@ -135,8 +143,6 @@ func New(c *Config) (db *Default, err error) { CacheFilePath: c.CacheFilePath, ResponseSizeEstimate: c.ResponseSizeEstimate, }) - } else { - return nil, fmt.Errorf("file %q is not protobuf", c.CacheFilePath) } db = &Default{ diff --git a/internal/profiledb/internal/fcpb/fc.pb.go b/internal/profiledb/internal/fcpb/fc.pb.go index efd0c7b..ee142f6 100644 --- a/internal/profiledb/internal/fcpb/fc.pb.go +++ b/internal/profiledb/internal/fcpb/fc.pb.go @@ -1433,6 +1433,7 @@ func (x *FilterConfig) GetSafeBrowsing() *FilterConfig_SafeBrowsing { return nil } +// Deprecated: Marked as deprecated in fc.proto. func (x *FilterConfig) GetCategoryFilter() *FilterConfig_CategoryFilter { if x != nil { return x.xxx_hidden_CategoryFilter @@ -1456,6 +1457,7 @@ func (x *FilterConfig) SetSafeBrowsing(v *FilterConfig_SafeBrowsing) { x.xxx_hidden_SafeBrowsing = v } +// Deprecated: Marked as deprecated in fc.proto. func (x *FilterConfig) SetCategoryFilter(v *FilterConfig_CategoryFilter) { x.xxx_hidden_CategoryFilter = v } @@ -1488,6 +1490,7 @@ func (x *FilterConfig) HasSafeBrowsing() bool { return x.xxx_hidden_SafeBrowsing != nil } +// Deprecated: Marked as deprecated in fc.proto. func (x *FilterConfig) HasCategoryFilter() bool { if x == nil { return false @@ -1511,6 +1514,7 @@ func (x *FilterConfig) ClearSafeBrowsing() { x.xxx_hidden_SafeBrowsing = nil } +// Deprecated: Marked as deprecated in fc.proto. func (x *FilterConfig) ClearCategoryFilter() { x.xxx_hidden_CategoryFilter = nil } @@ -1518,10 +1522,11 @@ func (x *FilterConfig) ClearCategoryFilter() { type FilterConfig_builder struct { _ [0]func() // Prevents comparability and use of unkeyed literals for the builder. - Custom *FilterConfig_Custom - Parental *FilterConfig_Parental - RuleList *FilterConfig_RuleList - SafeBrowsing *FilterConfig_SafeBrowsing + Custom *FilterConfig_Custom + Parental *FilterConfig_Parental + RuleList *FilterConfig_RuleList + SafeBrowsing *FilterConfig_SafeBrowsing + // Deprecated: Marked as deprecated in fc.proto. CategoryFilter *FilterConfig_CategoryFilter } @@ -2670,13 +2675,14 @@ func (b0 FilterConfig_Custom_builder) Build() *FilterConfig_Custom { } type FilterConfig_Parental struct { - state protoimpl.MessageState `protogen:"opaque.v1"` - xxx_hidden_PauseSchedule *FilterConfig_Schedule `protobuf:"bytes,1,opt,name=pause_schedule,json=pauseSchedule,proto3"` - xxx_hidden_BlockedServices []string `protobuf:"bytes,2,rep,name=blocked_services,json=blockedServices,proto3"` - xxx_hidden_Enabled bool `protobuf:"varint,3,opt,name=enabled,proto3"` - xxx_hidden_AdultBlockingEnabled bool `protobuf:"varint,4,opt,name=adult_blocking_enabled,json=adultBlockingEnabled,proto3"` - xxx_hidden_SafeSearchGeneralEnabled bool `protobuf:"varint,5,opt,name=safe_search_general_enabled,json=safeSearchGeneralEnabled,proto3"` - xxx_hidden_SafeSearchYoutubeEnabled bool `protobuf:"varint,6,opt,name=safe_search_youtube_enabled,json=safeSearchYoutubeEnabled,proto3"` + state protoimpl.MessageState `protogen:"opaque.v1"` + xxx_hidden_PauseSchedule *FilterConfig_Schedule `protobuf:"bytes,1,opt,name=pause_schedule,json=pauseSchedule,proto3"` + xxx_hidden_CategoryFilter *FilterConfig_CategoryFilter `protobuf:"bytes,7,opt,name=category_filter,json=categoryFilter,proto3"` + xxx_hidden_BlockedServices []string `protobuf:"bytes,2,rep,name=blocked_services,json=blockedServices,proto3"` + xxx_hidden_Enabled bool `protobuf:"varint,3,opt,name=enabled,proto3"` + xxx_hidden_AdultBlockingEnabled bool `protobuf:"varint,4,opt,name=adult_blocking_enabled,json=adultBlockingEnabled,proto3"` + xxx_hidden_SafeSearchGeneralEnabled bool `protobuf:"varint,5,opt,name=safe_search_general_enabled,json=safeSearchGeneralEnabled,proto3"` + xxx_hidden_SafeSearchYoutubeEnabled bool `protobuf:"varint,6,opt,name=safe_search_youtube_enabled,json=safeSearchYoutubeEnabled,proto3"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -2713,6 +2719,13 @@ func (x *FilterConfig_Parental) GetPauseSchedule() *FilterConfig_Schedule { return nil } +func (x *FilterConfig_Parental) GetCategoryFilter() *FilterConfig_CategoryFilter { + if x != nil { + return x.xxx_hidden_CategoryFilter + } + return nil +} + func (x *FilterConfig_Parental) GetBlockedServices() []string { if x != nil { return x.xxx_hidden_BlockedServices @@ -2752,6 +2765,10 @@ func (x *FilterConfig_Parental) SetPauseSchedule(v *FilterConfig_Schedule) { x.xxx_hidden_PauseSchedule = v } +func (x *FilterConfig_Parental) SetCategoryFilter(v *FilterConfig_CategoryFilter) { + x.xxx_hidden_CategoryFilter = v +} + func (x *FilterConfig_Parental) SetBlockedServices(v []string) { x.xxx_hidden_BlockedServices = v } @@ -2779,14 +2796,26 @@ func (x *FilterConfig_Parental) HasPauseSchedule() bool { return x.xxx_hidden_PauseSchedule != nil } +func (x *FilterConfig_Parental) HasCategoryFilter() bool { + if x == nil { + return false + } + return x.xxx_hidden_CategoryFilter != nil +} + func (x *FilterConfig_Parental) ClearPauseSchedule() { x.xxx_hidden_PauseSchedule = nil } +func (x *FilterConfig_Parental) ClearCategoryFilter() { + x.xxx_hidden_CategoryFilter = nil +} + type FilterConfig_Parental_builder struct { _ [0]func() // Prevents comparability and use of unkeyed literals for the builder. PauseSchedule *FilterConfig_Schedule + CategoryFilter *FilterConfig_CategoryFilter BlockedServices []string Enabled bool AdultBlockingEnabled bool @@ -2799,6 +2828,7 @@ func (b0 FilterConfig_Parental_builder) Build() *FilterConfig_Parental { b, x := &b0, m0 _, _ = b, x x.xxx_hidden_PauseSchedule = b.PauseSchedule + x.xxx_hidden_CategoryFilter = b.CategoryFilter x.xxx_hidden_BlockedServices = b.BlockedServices x.xxx_hidden_Enabled = b.Enabled x.xxx_hidden_AdultBlockingEnabled = b.AdultBlockingEnabled @@ -3396,19 +3426,19 @@ const file_fc_proto_rawDesc = "" + "\fStatePending\x122\n" + "\x06expire\x18\x01 \x01(\v2\x1a.google.protobuf.TimestampR\x06expire\x12&\n" + "\x0fwell_known_path\x18\x02 \x01(\tR\rwellKnownPathB\a\n" + - "\x05state\"\xf2\n" + - "\n" + + "\x05state\"\xc2\v\n" + "\fFilterConfig\x121\n" + "\x06custom\x18\x01 \x01(\v2\x19.fcpb.FilterConfig.CustomR\x06custom\x127\n" + "\bparental\x18\x02 \x01(\v2\x1b.fcpb.FilterConfig.ParentalR\bparental\x128\n" + "\trule_list\x18\x03 \x01(\v2\x1b.fcpb.FilterConfig.RuleListR\bruleList\x12D\n" + - "\rsafe_browsing\x18\x04 \x01(\v2\x1f.fcpb.FilterConfig.SafeBrowsingR\fsafeBrowsing\x12J\n" + - "\x0fcategory_filter\x18\x05 \x01(\v2!.fcpb.FilterConfig.CategoryFilterR\x0ecategoryFilter\x1aD\n" + + "\rsafe_browsing\x18\x04 \x01(\v2\x1f.fcpb.FilterConfig.SafeBrowsingR\fsafeBrowsing\x12N\n" + + "\x0fcategory_filter\x18\x05 \x01(\v2!.fcpb.FilterConfig.CategoryFilterB\x02\x18\x01R\x0ecategoryFilter\x1aD\n" + "\x06Custom\x12\x14\n" + "\x05rules\x18\x03 \x03(\tR\x05rules\x12\x18\n" + - "\aenabled\x18\x04 \x01(\bR\aenabledJ\x04\b\x01\x10\x02J\x04\b\x02\x10\x03\x1a\xc7\x02\n" + + "\aenabled\x18\x04 \x01(\bR\aenabledJ\x04\b\x01\x10\x02J\x04\b\x02\x10\x03\x1a\x93\x03\n" + "\bParental\x12B\n" + - "\x0epause_schedule\x18\x01 \x01(\v2\x1b.fcpb.FilterConfig.ScheduleR\rpauseSchedule\x12)\n" + + "\x0epause_schedule\x18\x01 \x01(\v2\x1b.fcpb.FilterConfig.ScheduleR\rpauseSchedule\x12J\n" + + "\x0fcategory_filter\x18\a \x01(\v2!.fcpb.FilterConfig.CategoryFilterR\x0ecategoryFilter\x12)\n" + "\x10blocked_services\x18\x02 \x03(\tR\x0fblockedServices\x12\x18\n" + "\aenabled\x18\x03 \x01(\bR\aenabled\x124\n" + "\x16adult_blocking_enabled\x18\x04 \x01(\bR\x14adultBlockingEnabled\x12=\n" + @@ -3539,19 +3569,20 @@ var file_fc_proto_depIdxs = []int32{ 24, // 33: fcpb.CustomDomainConfig.StateCurrent.not_after:type_name -> google.protobuf.Timestamp 24, // 34: fcpb.CustomDomainConfig.StatePending.expire:type_name -> google.protobuf.Timestamp 19, // 35: fcpb.FilterConfig.Parental.pause_schedule:type_name -> fcpb.FilterConfig.Schedule - 20, // 36: fcpb.FilterConfig.Schedule.week:type_name -> fcpb.FilterConfig.WeeklySchedule - 5, // 37: fcpb.FilterConfig.WeeklySchedule.mon:type_name -> fcpb.DayInterval - 5, // 38: fcpb.FilterConfig.WeeklySchedule.tue:type_name -> fcpb.DayInterval - 5, // 39: fcpb.FilterConfig.WeeklySchedule.wed:type_name -> fcpb.DayInterval - 5, // 40: fcpb.FilterConfig.WeeklySchedule.thu:type_name -> fcpb.DayInterval - 5, // 41: fcpb.FilterConfig.WeeklySchedule.fri:type_name -> fcpb.DayInterval - 5, // 42: fcpb.FilterConfig.WeeklySchedule.sat:type_name -> fcpb.DayInterval - 5, // 43: fcpb.FilterConfig.WeeklySchedule.sun:type_name -> fcpb.DayInterval - 44, // [44:44] is the sub-list for method output_type - 44, // [44:44] is the sub-list for method input_type - 44, // [44:44] is the sub-list for extension type_name - 44, // [44:44] is the sub-list for extension extendee - 0, // [0:44] is the sub-list for field type_name + 23, // 36: fcpb.FilterConfig.Parental.category_filter:type_name -> fcpb.FilterConfig.CategoryFilter + 20, // 37: fcpb.FilterConfig.Schedule.week:type_name -> fcpb.FilterConfig.WeeklySchedule + 5, // 38: fcpb.FilterConfig.WeeklySchedule.mon:type_name -> fcpb.DayInterval + 5, // 39: fcpb.FilterConfig.WeeklySchedule.tue:type_name -> fcpb.DayInterval + 5, // 40: fcpb.FilterConfig.WeeklySchedule.wed:type_name -> fcpb.DayInterval + 5, // 41: fcpb.FilterConfig.WeeklySchedule.thu:type_name -> fcpb.DayInterval + 5, // 42: fcpb.FilterConfig.WeeklySchedule.fri:type_name -> fcpb.DayInterval + 5, // 43: fcpb.FilterConfig.WeeklySchedule.sat:type_name -> fcpb.DayInterval + 5, // 44: fcpb.FilterConfig.WeeklySchedule.sun:type_name -> fcpb.DayInterval + 45, // [45:45] is the sub-list for method output_type + 45, // [45:45] is the sub-list for method input_type + 45, // [45:45] is the sub-list for extension type_name + 45, // [45:45] is the sub-list for extension extendee + 0, // [0:45] is the sub-list for field type_name } func init() { file_fc_proto_init() } diff --git a/internal/profiledb/internal/fcpb/fc.proto b/internal/profiledb/internal/fcpb/fc.proto index 555d733..6d65bfd 100644 --- a/internal/profiledb/internal/fcpb/fc.proto +++ b/internal/profiledb/internal/fcpb/fc.proto @@ -97,6 +97,7 @@ message FilterConfig { message Parental { Schedule pause_schedule = 1; + CategoryFilter category_filter = 7; repeated string blocked_services = 2; bool enabled = 3; bool adult_blocking_enabled = 4; @@ -139,7 +140,7 @@ message FilterConfig { Parental parental = 2; RuleList rule_list = 3; SafeBrowsing safe_browsing = 4; - CategoryFilter category_filter = 5; + CategoryFilter category_filter = 5 [deprecated=true]; } message DayInterval { diff --git a/internal/profiledb/internal/filecacheopb/profile.go b/internal/profiledb/internal/filecacheopb/profile.go index 302956f..c5cdad5 100644 --- a/internal/profiledb/internal/filecacheopb/profile.go +++ b/internal/profiledb/internal/filecacheopb/profile.go @@ -173,12 +173,19 @@ func configClientToInternal( } // categoryFilterToInternal converts filter config's protobuf category filter -// structure to internal one. If pbCatFlt is nil, returns a disabled config. -func categoryFilterToInternal( - pbCatFlt *fcpb.FilterConfig_CategoryFilter, -) (c *filter.ConfigCategories) { +// structure to internal one. If categories filter is not specified, returns a +// disabled config. +func categoryFilterToInternal(pbFltConf *fcpb.FilterConfig) (c *filter.ConfigCategories) { + pbCatFlt := pbFltConf.GetParental().GetCategoryFilter() if pbCatFlt == nil { - return &filter.ConfigCategories{} + // TODO(d.kolyshev): Remove after moving deprecated profile categories + // in [internal/profiledb/internal.FileCacheVersion] 19. + // + //lint:ignore SA1019 Use deprecated field for compatibility. + pbCatFlt = pbFltConf.GetCategoryFilter() + if pbCatFlt == nil { + return &filter.ConfigCategories{} + } } // Consider the categories to have been prevalidated. @@ -198,7 +205,7 @@ func configParentalToInternal( parental := pbFltConf.GetParental() return &filter.ConfigParental{ - Categories: categoryFilterToInternal(pbFltConf.GetCategoryFilter()), + Categories: categoryFilterToInternal(pbFltConf), PauseSchedule: schedule, // Consider blocked-service IDs to have been prevalidated. BlockedServices: agdprotobuf.UnsafelyConvertStrSlice[string, filter.BlockedServiceID]( @@ -615,8 +622,17 @@ func filterConfigToProtobuf(c *filter.ConfigClient) (fc *fcpb.FilterConfig) { Enabled: c.Custom.Enabled, }.Build() + categoryFilter := fcpb.FilterConfig_CategoryFilter_builder{ + Ids: agdprotobuf.UnsafelyConvertStrSlice[ + filter.CategoryID, + string, + ](c.Parental.Categories.IDs), + Enabled: c.Parental.Categories.Enabled, + }.Build() + parental := fcpb.FilterConfig_Parental_builder{ - PauseSchedule: scheduleToProtobuf(c.Parental.PauseSchedule), + PauseSchedule: scheduleToProtobuf(c.Parental.PauseSchedule), + CategoryFilter: categoryFilter, BlockedServices: agdprotobuf.UnsafelyConvertStrSlice[filter.BlockedServiceID, string]( c.Parental.BlockedServices, ), @@ -637,20 +653,11 @@ func filterConfigToProtobuf(c *filter.ConfigClient) (fc *fcpb.FilterConfig) { NewlyRegisteredDomainsEnabled: c.SafeBrowsing.NewlyRegisteredDomainsEnabled, }.Build() - categories := fcpb.FilterConfig_CategoryFilter_builder{ - Ids: agdprotobuf.UnsafelyConvertStrSlice[ - filter.CategoryID, - string, - ](c.Parental.Categories.IDs), - Enabled: c.Parental.Categories.Enabled, - }.Build() - return fcpb.FilterConfig_builder{ - Custom: custom, - Parental: parental, - RuleList: ruleList, - SafeBrowsing: safeBrowsing, - CategoryFilter: categories, + Custom: custom, + Parental: parental, + RuleList: ruleList, + SafeBrowsing: safeBrowsing, }.Build() } diff --git a/internal/profiledb/internal/filecachepb/filecache.pb.go b/internal/profiledb/internal/filecachepb/filecache.pb.go index 9d8f229..8757d40 100644 --- a/internal/profiledb/internal/filecachepb/filecache.pb.go +++ b/internal/profiledb/internal/filecachepb/filecache.pb.go @@ -636,11 +636,12 @@ func (*CustomDomainConfig_StateCurrent_) isCustomDomainConfig_State() {} func (*CustomDomainConfig_StatePending_) isCustomDomainConfig_State() {} type FilterConfig struct { - state protoimpl.MessageState `protogen:"open.v1"` - Custom *FilterConfig_Custom `protobuf:"bytes,1,opt,name=custom,proto3" json:"custom,omitempty"` - Parental *FilterConfig_Parental `protobuf:"bytes,2,opt,name=parental,proto3" json:"parental,omitempty"` - RuleList *FilterConfig_RuleList `protobuf:"bytes,3,opt,name=rule_list,json=ruleList,proto3" json:"rule_list,omitempty"` - SafeBrowsing *FilterConfig_SafeBrowsing `protobuf:"bytes,4,opt,name=safe_browsing,json=safeBrowsing,proto3" json:"safe_browsing,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + Custom *FilterConfig_Custom `protobuf:"bytes,1,opt,name=custom,proto3" json:"custom,omitempty"` + Parental *FilterConfig_Parental `protobuf:"bytes,2,opt,name=parental,proto3" json:"parental,omitempty"` + RuleList *FilterConfig_RuleList `protobuf:"bytes,3,opt,name=rule_list,json=ruleList,proto3" json:"rule_list,omitempty"` + SafeBrowsing *FilterConfig_SafeBrowsing `protobuf:"bytes,4,opt,name=safe_browsing,json=safeBrowsing,proto3" json:"safe_browsing,omitempty"` + // Deprecated: Marked as deprecated in filecache.proto. CategoryFilter *FilterConfig_CategoryFilter `protobuf:"bytes,5,opt,name=category_filter,json=categoryFilter,proto3" json:"category_filter,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache @@ -704,6 +705,7 @@ func (x *FilterConfig) GetSafeBrowsing() *FilterConfig_SafeBrowsing { return nil } +// Deprecated: Marked as deprecated in filecache.proto. func (x *FilterConfig) GetCategoryFilter() *FilterConfig_CategoryFilter { if x != nil { return x.CategoryFilter @@ -1458,13 +1460,14 @@ func (x *FilterConfig_Custom) GetEnabled() bool { } type FilterConfig_Parental struct { - state protoimpl.MessageState `protogen:"open.v1"` - PauseSchedule *FilterConfig_Schedule `protobuf:"bytes,1,opt,name=pause_schedule,json=pauseSchedule,proto3" json:"pause_schedule,omitempty"` - BlockedServices []string `protobuf:"bytes,2,rep,name=blocked_services,json=blockedServices,proto3" json:"blocked_services,omitempty"` - Enabled bool `protobuf:"varint,3,opt,name=enabled,proto3" json:"enabled,omitempty"` - AdultBlockingEnabled bool `protobuf:"varint,4,opt,name=adult_blocking_enabled,json=adultBlockingEnabled,proto3" json:"adult_blocking_enabled,omitempty"` - SafeSearchGeneralEnabled bool `protobuf:"varint,5,opt,name=safe_search_general_enabled,json=safeSearchGeneralEnabled,proto3" json:"safe_search_general_enabled,omitempty"` - SafeSearchYoutubeEnabled bool `protobuf:"varint,6,opt,name=safe_search_youtube_enabled,json=safeSearchYoutubeEnabled,proto3" json:"safe_search_youtube_enabled,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + PauseSchedule *FilterConfig_Schedule `protobuf:"bytes,1,opt,name=pause_schedule,json=pauseSchedule,proto3" json:"pause_schedule,omitempty"` + CategoryFilter *FilterConfig_CategoryFilter `protobuf:"bytes,7,opt,name=category_filter,json=categoryFilter,proto3" json:"category_filter,omitempty"` + BlockedServices []string `protobuf:"bytes,2,rep,name=blocked_services,json=blockedServices,proto3" json:"blocked_services,omitempty"` + Enabled bool `protobuf:"varint,3,opt,name=enabled,proto3" json:"enabled,omitempty"` + AdultBlockingEnabled bool `protobuf:"varint,4,opt,name=adult_blocking_enabled,json=adultBlockingEnabled,proto3" json:"adult_blocking_enabled,omitempty"` + SafeSearchGeneralEnabled bool `protobuf:"varint,5,opt,name=safe_search_general_enabled,json=safeSearchGeneralEnabled,proto3" json:"safe_search_general_enabled,omitempty"` + SafeSearchYoutubeEnabled bool `protobuf:"varint,6,opt,name=safe_search_youtube_enabled,json=safeSearchYoutubeEnabled,proto3" json:"safe_search_youtube_enabled,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -1506,6 +1509,13 @@ func (x *FilterConfig_Parental) GetPauseSchedule() *FilterConfig_Schedule { return nil } +func (x *FilterConfig_Parental) GetCategoryFilter() *FilterConfig_CategoryFilter { + if x != nil { + return x.CategoryFilter + } + return nil +} + func (x *FilterConfig_Parental) GetBlockedServices() []string { if x != nil { return x.BlockedServices @@ -1911,18 +1921,19 @@ const file_filecache_proto_rawDesc = "" + "\fStatePending\x122\n" + "\x06expire\x18\x01 \x01(\v2\x1a.google.protobuf.TimestampR\x06expire\x12&\n" + "\x0fwell_known_path\x18\x02 \x01(\tR\rwellKnownPathB\a\n" + - "\x05state\"\xd4\v\n" + + "\x05state\"\xab\f\n" + "\fFilterConfig\x128\n" + "\x06custom\x18\x01 \x01(\v2 .filecachepb.FilterConfig.CustomR\x06custom\x12>\n" + "\bparental\x18\x02 \x01(\v2\".filecachepb.FilterConfig.ParentalR\bparental\x12?\n" + "\trule_list\x18\x03 \x01(\v2\".filecachepb.FilterConfig.RuleListR\bruleList\x12K\n" + - "\rsafe_browsing\x18\x04 \x01(\v2&.filecachepb.FilterConfig.SafeBrowsingR\fsafeBrowsing\x12Q\n" + - "\x0fcategory_filter\x18\x05 \x01(\v2(.filecachepb.FilterConfig.CategoryFilterR\x0ecategoryFilter\x1aD\n" + + "\rsafe_browsing\x18\x04 \x01(\v2&.filecachepb.FilterConfig.SafeBrowsingR\fsafeBrowsing\x12U\n" + + "\x0fcategory_filter\x18\x05 \x01(\v2(.filecachepb.FilterConfig.CategoryFilterB\x02\x18\x01R\x0ecategoryFilter\x1aD\n" + "\x06Custom\x12\x14\n" + "\x05rules\x18\x03 \x03(\tR\x05rules\x12\x18\n" + - "\aenabled\x18\x04 \x01(\bR\aenabledJ\x04\b\x01\x10\x02J\x04\b\x02\x10\x03\x1a\xce\x02\n" + + "\aenabled\x18\x04 \x01(\bR\aenabledJ\x04\b\x01\x10\x02J\x04\b\x02\x10\x03\x1a\xa1\x03\n" + "\bParental\x12I\n" + - "\x0epause_schedule\x18\x01 \x01(\v2\".filecachepb.FilterConfig.ScheduleR\rpauseSchedule\x12)\n" + + "\x0epause_schedule\x18\x01 \x01(\v2\".filecachepb.FilterConfig.ScheduleR\rpauseSchedule\x12Q\n" + + "\x0fcategory_filter\x18\a \x01(\v2(.filecachepb.FilterConfig.CategoryFilterR\x0ecategoryFilter\x12)\n" + "\x10blocked_services\x18\x02 \x03(\tR\x0fblockedServices\x12\x18\n" + "\aenabled\x18\x03 \x01(\bR\aenabled\x124\n" + "\x16adult_blocking_enabled\x18\x04 \x01(\bR\x14adultBlockingEnabled\x12=\n" + @@ -2065,19 +2076,20 @@ var file_filecache_proto_depIdxs = []int32{ 24, // 33: filecachepb.CustomDomainConfig.StateCurrent.not_after:type_name -> google.protobuf.Timestamp 24, // 34: filecachepb.CustomDomainConfig.StatePending.expire:type_name -> google.protobuf.Timestamp 19, // 35: filecachepb.FilterConfig.Parental.pause_schedule:type_name -> filecachepb.FilterConfig.Schedule - 20, // 36: filecachepb.FilterConfig.Schedule.week:type_name -> filecachepb.FilterConfig.WeeklySchedule - 5, // 37: filecachepb.FilterConfig.WeeklySchedule.mon:type_name -> filecachepb.DayInterval - 5, // 38: filecachepb.FilterConfig.WeeklySchedule.tue:type_name -> filecachepb.DayInterval - 5, // 39: filecachepb.FilterConfig.WeeklySchedule.wed:type_name -> filecachepb.DayInterval - 5, // 40: filecachepb.FilterConfig.WeeklySchedule.thu:type_name -> filecachepb.DayInterval - 5, // 41: filecachepb.FilterConfig.WeeklySchedule.fri:type_name -> filecachepb.DayInterval - 5, // 42: filecachepb.FilterConfig.WeeklySchedule.sat:type_name -> filecachepb.DayInterval - 5, // 43: filecachepb.FilterConfig.WeeklySchedule.sun:type_name -> filecachepb.DayInterval - 44, // [44:44] is the sub-list for method output_type - 44, // [44:44] is the sub-list for method input_type - 44, // [44:44] is the sub-list for extension type_name - 44, // [44:44] is the sub-list for extension extendee - 0, // [0:44] is the sub-list for field type_name + 23, // 36: filecachepb.FilterConfig.Parental.category_filter:type_name -> filecachepb.FilterConfig.CategoryFilter + 20, // 37: filecachepb.FilterConfig.Schedule.week:type_name -> filecachepb.FilterConfig.WeeklySchedule + 5, // 38: filecachepb.FilterConfig.WeeklySchedule.mon:type_name -> filecachepb.DayInterval + 5, // 39: filecachepb.FilterConfig.WeeklySchedule.tue:type_name -> filecachepb.DayInterval + 5, // 40: filecachepb.FilterConfig.WeeklySchedule.wed:type_name -> filecachepb.DayInterval + 5, // 41: filecachepb.FilterConfig.WeeklySchedule.thu:type_name -> filecachepb.DayInterval + 5, // 42: filecachepb.FilterConfig.WeeklySchedule.fri:type_name -> filecachepb.DayInterval + 5, // 43: filecachepb.FilterConfig.WeeklySchedule.sat:type_name -> filecachepb.DayInterval + 5, // 44: filecachepb.FilterConfig.WeeklySchedule.sun:type_name -> filecachepb.DayInterval + 45, // [45:45] is the sub-list for method output_type + 45, // [45:45] is the sub-list for method input_type + 45, // [45:45] is the sub-list for extension type_name + 45, // [45:45] is the sub-list for extension extendee + 0, // [0:45] is the sub-list for field type_name } func init() { file_filecache_proto_init() } diff --git a/internal/profiledb/internal/filecachepb/filecache.proto b/internal/profiledb/internal/filecachepb/filecache.proto index fb4fd54..94ce0db 100644 --- a/internal/profiledb/internal/filecachepb/filecache.proto +++ b/internal/profiledb/internal/filecachepb/filecache.proto @@ -96,6 +96,7 @@ message FilterConfig { message Parental { Schedule pause_schedule = 1; + CategoryFilter category_filter = 7; repeated string blocked_services = 2; bool enabled = 3; bool adult_blocking_enabled = 4; @@ -138,7 +139,7 @@ message FilterConfig { Parental parental = 2; RuleList rule_list = 3; SafeBrowsing safe_browsing = 4; - CategoryFilter category_filter = 5; + CategoryFilter category_filter = 5 [deprecated=true]; } message DayInterval { diff --git a/internal/profiledb/internal/filecachepb/filecachepb.go b/internal/profiledb/internal/filecachepb/filecachepb.go index 5fdc340..48cc34b 100644 --- a/internal/profiledb/internal/filecachepb/filecachepb.go +++ b/internal/profiledb/internal/filecachepb/filecachepb.go @@ -138,7 +138,7 @@ func (x *Profile) toInternal( Enabled: pbFltConf.Custom.Enabled, }, Parental: &filter.ConfigParental{ - Categories: categoryFilterToInternal(pbFltConf.CategoryFilter), + Categories: categoriesToInternal(pbFltConf), PauseSchedule: schedule, // Consider blocked-service IDs to have been prevalidated. BlockedServices: agdprotobuf.UnsafelyConvertStrSlice[string, filter.BlockedServiceID]( @@ -193,22 +193,33 @@ func (x *Profile) toInternal( }, nil } -// categoryFilterToInternal converts filter config's protobuf category filter -// structure to internal one. If pbCatFlt is nil, returns a disabled config. -func categoryFilterToInternal( - pbCatFlt *FilterConfig_CategoryFilter, -) (c *filter.ConfigCategories) { - if pbCatFlt == nil { +// categoriesToInternal converts filter config's protobuf category filter to +// internal one. pbFltConf must not be nil. +func categoriesToInternal(pbFltConf *FilterConfig) (c *filter.ConfigCategories) { + pbCatFltr := pbFltConf.Parental.CategoryFilter + if pbCatFltr == nil && pbFltConf.CategoryFilter != nil { + // TODO(d.kolyshev): Remove after moving deprecated profile categories + // in [internal/profiledb/internal.FileCacheVersion] 19. + pbCatFltr = pbFltConf.CategoryFilter + } + + return pbCatFltr.toInternal() +} + +// toInternal converts filter config's protobuf category filter structure to +// internal one. If x is nil, returns a disabled config. +func (x *FilterConfig_CategoryFilter) toInternal() (c *filter.ConfigCategories) { + if x == nil { return &filter.ConfigCategories{ Enabled: false, } } // Consider the categories to have been prevalidated. - ids := agdprotobuf.UnsafelyConvertStrSlice[string, filter.CategoryID](pbCatFlt.GetIds()) + ids := agdprotobuf.UnsafelyConvertStrSlice[string, filter.CategoryID](x.GetIds()) return &filter.ConfigCategories{ IDs: ids, - Enabled: pbCatFlt.GetEnabled(), + Enabled: x.GetEnabled(), } } @@ -676,21 +687,21 @@ func filterConfigToProtobuf(c *filter.ConfigClient) (fc *FilterConfig) { rules = agdprotobuf.UnsafelyConvertStrSlice[filter.RuleText, string](c.Custom.Filter.Rules()) } + parentalCategories := &FilterConfig_CategoryFilter{ + Ids: agdprotobuf.UnsafelyConvertStrSlice[filter.CategoryID, string]( + c.Parental.Categories.IDs, + ), + Enabled: c.Parental.Categories.Enabled, + } + return &FilterConfig{ - // TODO(a.garipov): Move to parental. - CategoryFilter: &FilterConfig_CategoryFilter{ - Enabled: c.Parental.Categories.Enabled, - Ids: agdprotobuf.UnsafelyConvertStrSlice[ - filter.CategoryID, - string, - ](c.Parental.Categories.IDs), - }, Custom: &FilterConfig_Custom{ Rules: rules, Enabled: c.Custom.Enabled, }, Parental: &FilterConfig_Parental{ - PauseSchedule: scheduleToProtobuf(c.Parental.PauseSchedule), + PauseSchedule: scheduleToProtobuf(c.Parental.PauseSchedule), + CategoryFilter: parentalCategories, BlockedServices: agdprotobuf.UnsafelyConvertStrSlice[filter.BlockedServiceID, string]( c.Parental.BlockedServices, ),