From 0f2a9f262e5cf021ef5e58e65e92da1288e9da13 Mon Sep 17 00:00:00 2001 From: RoboMagus <68224306+RoboMagus@users.noreply.github.com> Date: Mon, 25 Apr 2022 09:41:31 +0200 Subject: [PATCH 1/3] Add '/blocked_services/services' API --- AGHTechDoc.md | 13 +++++++++++++ client/src/actions/services.js | 15 +++++++++++++++ client/src/api/Api.js | 7 +++++++ client2/src/lib/apis/blockedServices.ts | 12 ++++++++++++ internal/filtering/blocked.go | 16 ++++++++++++++++ openapi/openapi.yaml | 13 +++++++++++++ 6 files changed, 76 insertions(+) diff --git a/AGHTechDoc.md b/AGHTechDoc.md index 4758a0da..8f69e5bd 100644 --- a/AGHTechDoc.md +++ b/AGHTechDoc.md @@ -1355,6 +1355,19 @@ Internally, all supported services are stored as a map: service name -> list of rules +### API: Get blocked services list of available services + +Request: + + GET /control/blocked_services/services + +Response: + + 200 OK + + [ "name1", ... ] + + ### API: Get blocked services list Request: diff --git a/client/src/actions/services.js b/client/src/actions/services.js index 1c95e3a1..650aa330 100644 --- a/client/src/actions/services.js +++ b/client/src/actions/services.js @@ -2,6 +2,21 @@ import { createAction } from 'redux-actions'; import apiClient from '../api/Api'; import { addErrorToast, addSuccessToast } from './toasts'; +export const getBlockedServicesAvailableServicesRequest = createAction('GET_BLOCKED_SERVICES_AVAILABLE_SERVICES_REQUEST'); +export const getBlockedServicesAvailableServicesFailure = createAction('GET_BLOCKED_SERVICES_AVAILABLE_SERVICES_FAILURE'); +export const getBlockedServicesAvailableServicesSuccess = createAction('GET_BLOCKED_SERVICES_AVAILABLE_SERVICES_SUCCESS'); + +export const getBlockedServicesAvailableServices = () => async (dispatch) => { + dispatch(getBlockedServicesAvailableServicesRequest()); + try { + const data = await apiClient.getBlockedServicesAvailableServices(); + dispatch(getBlockedServicesAvailableServicesSuccess(data)); + } catch (error) { + dispatch(addErrorToast({ error })); + dispatch(getBlockedServicesAvailableServicesFailure()); + } +}; + export const getBlockedServicesRequest = createAction('GET_BLOCKED_SERVICES_REQUEST'); export const getBlockedServicesFailure = createAction('GET_BLOCKED_SERVICES_FAILURE'); export const getBlockedServicesSuccess = createAction('GET_BLOCKED_SERVICES_SUCCESS'); diff --git a/client/src/api/Api.js b/client/src/api/Api.js index 1f6b2832..625da9e0 100644 --- a/client/src/api/Api.js +++ b/client/src/api/Api.js @@ -481,10 +481,17 @@ class Api { } // Blocked services + BLOCKED_SERVICES_SERVICES = { path: 'blocked_services/services', method: 'GET' }; + BLOCKED_SERVICES_LIST = { path: 'blocked_services/list', method: 'GET' }; BLOCKED_SERVICES_SET = { path: 'blocked_services/set', method: 'POST' }; + getBlockedServicesAvailableServices() { + const { path, method } = this.BLOCKED_SERVICES_SERVICES; + return this.makeRequest(path, method); + } + getBlockedServices() { const { path, method } = this.BLOCKED_SERVICES_LIST; return this.makeRequest(path, method); diff --git a/client2/src/lib/apis/blockedServices.ts b/client2/src/lib/apis/blockedServices.ts index 381a236d..7daa3344 100644 --- a/client2/src/lib/apis/blockedServices.ts +++ b/client2/src/lib/apis/blockedServices.ts @@ -1,6 +1,18 @@ // This file was autogenerated. Please do not change. // All changes will be overwrited on commit. export default class BlockedServicesApi { + static async blockedServicesAvailableServices(): Promise { + return await fetch(`/control/blocked_services/services`, { + method: 'GET', + }).then(async (res) => { + if (res.status === 200) { + return res.json(); + } else { + return new Error(String(res.status)); + } + }) + } + static async blockedServicesList(): Promise { return await fetch(`/control/blocked_services/list`, { method: 'GET', diff --git a/internal/filtering/blocked.go b/internal/filtering/blocked.go index 1d165cf4..bf990de9 100644 --- a/internal/filtering/blocked.go +++ b/internal/filtering/blocked.go @@ -331,6 +331,21 @@ func (d *DNSFilter) ApplyBlockedServices(setts *Settings, list []string, global } } +func (d *DNSFilter) handleBlockedServicesAvailableServices(w http.ResponseWriter, r *http.Request) { + var list []string + for _, v := range serviceRulesArray { + list = append(list, s.name) + } + + w.Header().Set("Content-Type", "application/json") + err := json.NewEncoder(w).Encode(list) + if err != nil { + aghhttp.Error(r, w, http.StatusInternalServerError, "json.Encode: %s", err) + + return + } +} + func (d *DNSFilter) handleBlockedServicesList(w http.ResponseWriter, r *http.Request) { d.confLock.RLock() list := d.Config.BlockedServices @@ -365,6 +380,7 @@ func (d *DNSFilter) handleBlockedServicesSet(w http.ResponseWriter, r *http.Requ // registerBlockedServicesHandlers - register HTTP handlers func (d *DNSFilter) registerBlockedServicesHandlers() { + d.Config.HTTPRegister(http.MethodGet, "/control/blocked_services/services", d.handleBlockedServicesAvailableServices) d.Config.HTTPRegister(http.MethodGet, "/control/blocked_services/list", d.handleBlockedServicesList) d.Config.HTTPRegister(http.MethodPost, "/control/blocked_services/set", d.handleBlockedServicesSet) } diff --git a/openapi/openapi.yaml b/openapi/openapi.yaml index 8b21a01f..19193151 100644 --- a/openapi/openapi.yaml +++ b/openapi/openapi.yaml @@ -874,6 +874,19 @@ 'summary': 'Set (dis)allowed clients, blocked hosts, etc.' 'tags': - 'clients' + '/blocked_services/services': + 'get': + 'tags': + - 'blocked_services' + 'operationId': 'blockedServicesAvailableServices' + 'summary': 'Get available services to use for blocking' + 'responses': + '200': + 'description': 'OK.' + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/BlockedServicesArray' '/blocked_services/list': 'get': 'tags': From fa76ad2a3c3b8efd91a03aacbc9439eff350f8b9 Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Thu, 25 Aug 2022 18:44:19 +0300 Subject: [PATCH 2/3] filtering: imp code --- CHANGELOG.md | 8 ++++- internal/filtering/blocked.go | 52 +++++++++++++++++++++------------ internal/filtering/filtering.go | 8 +++-- internal/filtering/rewrites.go | 7 ++--- 4 files changed, 48 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b5edd91b..ca77782c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,11 @@ and this project adheres to - Weaker cipher suites that use the CBC (cipher block chaining) mode of operation have been disabled ([#2993]). +### Added + +- A new HTTP API, `GET /control/blocked_services/services`, that lists all + available blocked services ([#4535]). + ### Deprecated - Ports 784 and 8853 for DNS-over-QUIC in Docker images. Users who still serve @@ -34,6 +39,7 @@ and this project adheres to - Unnecessary logging of non-critical statistics errors ([#4850]). [#2993]: https://github.com/AdguardTeam/AdGuardHome/issues/2993 +[#4535]: https://github.com/AdguardTeam/AdGuardHome/issues/4535 [#4745]: https://github.com/AdguardTeam/AdGuardHome/issues/4745 [#4850]: https://github.com/AdguardTeam/AdGuardHome/issues/4850 @@ -59,7 +65,7 @@ See also the [v0.107.11 GitHub milestone][ms-v0.107.11]. ### Changed -- DNS-over-QUIC connections now use keptalive. +- DNS-over-QUIC connections now use keepalive. ### Fixed diff --git a/internal/filtering/blocked.go b/internal/filtering/blocked.go index 41e8ad04..203407f2 100644 --- a/internal/filtering/blocked.go +++ b/internal/filtering/blocked.go @@ -7,19 +7,21 @@ import ( "github.com/AdguardTeam/AdGuardHome/internal/aghhttp" "github.com/AdguardTeam/golibs/log" "github.com/AdguardTeam/urlfilter/rules" + "golang.org/x/exp/slices" ) -var serviceRules map[string][]*rules.NetworkRule // service name -> filtering rules - +// svc represents a single blocked service. type svc struct { name string rules []string } +// servicesData contains raw blocked service data. +// // Keep in sync with: -// client/src/helpers/constants.js -// client/src/components/ui/Icons.js -var serviceRulesArray = []svc{{ +// - client/src/helpers/constants.js +// - client/src/components/ui/Icons.js +var servicesData = []svc{{ name: "whatsapp", rules: []string{ "||wa.me^", @@ -365,21 +367,38 @@ var serviceRulesArray = []svc{{ }, }} -// convert array to map +// serviceRules maps a service ID to its filtering rules. +var serviceRules map[string][]*rules.NetworkRule + +// serviceIDs contains service IDs sorted alphabetically. +var serviceIDs []string + +// initBlockedServices initializes package-level blocked service data. func initBlockedServices() { - serviceRules = make(map[string][]*rules.NetworkRule) - for _, s := range serviceRulesArray { - netRules := []*rules.NetworkRule{} + l := len(servicesData) + serviceIDs = make([]string, l) + serviceRules = make(map[string][]*rules.NetworkRule, l) + + for i, s := range servicesData { + netRules := make([]*rules.NetworkRule, 0, len(s.rules)) for _, text := range s.rules { rule, err := rules.NewNetworkRule(text, BlockedSvcsListID) if err != nil { - log.Error("rules.NewNetworkRule: %s rule: %s", err, text) + log.Error("parsing blocked service %q rule %q: %s", s.name, text, err) + continue } + netRules = append(netRules, rule) } + + serviceIDs[i] = s.name serviceRules[s.name] = netRules } + + slices.Sort(serviceIDs) + + log.Debug("filtering: initialized %d services", l) } // BlockedSvcKnown - return TRUE if a blocked service name is known @@ -411,16 +430,11 @@ func (d *DNSFilter) ApplyBlockedServices(setts *Settings, list []string, global } } -func (d *DNSFilter) handleBlockedServicesAvailableServices(w http.ResponseWriter, r *http.Request) { - var list []string - for _, v := range serviceRulesArray { - list = append(list, s.name) - } - +func (d *DNSFilter) handleBlockedServicesAvailableServices(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") - err := json.NewEncoder(w).Encode(list) + err := json.NewEncoder(w).Encode(serviceIDs) if err != nil { - aghhttp.Error(r, w, http.StatusInternalServerError, "json.Encode: %s", err) + aghhttp.Error(r, w, http.StatusInternalServerError, "encoding available services: %s", err) return } @@ -434,7 +448,7 @@ func (d *DNSFilter) handleBlockedServicesList(w http.ResponseWriter, r *http.Req w.Header().Set("Content-Type", "application/json") err := json.NewEncoder(w).Encode(list) if err != nil { - aghhttp.Error(r, w, http.StatusInternalServerError, "json.Encode: %s", err) + aghhttp.Error(r, w, http.StatusInternalServerError, "encoding services: %s", err) return } diff --git a/internal/filtering/filtering.go b/internal/filtering/filtering.go index 4a3e6b28..4d438dfe 100644 --- a/internal/filtering/filtering.go +++ b/internal/filtering/filtering.go @@ -296,9 +296,11 @@ func cloneRewrites(entries []*LegacyRewrite) (clone []*LegacyRewrite) { return clone } -// SetFilters - set new filters (synchronously or asynchronously) -// When filters are set asynchronously, the old filters continue working until the new filters are ready. -// In this case the caller must ensure that the old filter files are intact. +// SetFilters sets new filters, synchronously or asynchronously. When filters +// are set asynchronously, the old filters continue working until the new +// filters are ready. +// +// In this case the caller must ensure that the old filter files are intact. func (d *DNSFilter) SetFilters(blockFilters, allowFilters []Filter, async bool) error { if async { params := filtersInitializerParams{ diff --git a/internal/filtering/rewrites.go b/internal/filtering/rewrites.go index dab4c034..c1557158 100644 --- a/internal/filtering/rewrites.go +++ b/internal/filtering/rewrites.go @@ -130,10 +130,9 @@ func matchDomainWildcard(host, wildcard string) (ok bool) { // // The sorting priority: // -// A and AAAA > CNAME -// wildcard > exact -// lower level wildcard > higher level wildcard -// +// 1. A and AAAA > CNAME +// 2. wildcard > exact +// 3. lower level wildcard > higher level wildcard type rewritesSorted []*LegacyRewrite // Len implements the sort.Interface interface for legacyRewritesSorted. From 986124948a21b5dfebb0bd6a9f948911b0a4b938 Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Thu, 25 Aug 2022 18:58:49 +0300 Subject: [PATCH 3/3] all: imp client, add api chlog --- client/src/api/Api.js | 2 +- openapi/CHANGELOG.md | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/client/src/api/Api.js b/client/src/api/Api.js index 625da9e0..d5693bfe 100644 --- a/client/src/api/Api.js +++ b/client/src/api/Api.js @@ -491,7 +491,7 @@ class Api { const { path, method } = this.BLOCKED_SERVICES_SERVICES; return this.makeRequest(path, method); } - + getBlockedServices() { const { path, method } = this.BLOCKED_SERVICES_LIST; return this.makeRequest(path, method); diff --git a/openapi/CHANGELOG.md b/openapi/CHANGELOG.md index 1e2852be..fbbe7169 100644 --- a/openapi/CHANGELOG.md +++ b/openapi/CHANGELOG.md @@ -4,6 +4,15 @@ ## v0.108.0: API changes +## v0.107.12: API changes + +### `GET /control/blocked_services/services` + +* The new `GET /control/blocked_services/services` HTTP API allows inspecting + all available services. + +## v0.107.7: API changes + ### The new optional field `"ecs"` in `QueryLogItem` * The new optional field `"ecs"` in `GET /control/querylog` contains the IP