AdGuardHome/internal/filtering/blocked.go

216 lines
5.3 KiB
Go
Raw Normal View History

package filtering
import (
2019-07-23 10:16:36 +01:00
"encoding/json"
2023-07-03 12:10:40 +01:00
"fmt"
2019-07-23 10:16:36 +01:00
"net/http"
2024-03-12 14:45:11 +00:00
"slices"
2023-07-03 12:10:40 +01:00
"time"
2019-07-23 10:16:36 +01:00
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
2024-04-02 18:22:19 +01:00
"github.com/AdguardTeam/AdGuardHome/internal/filtering/rulelist"
2023-07-03 12:10:40 +01:00
"github.com/AdguardTeam/AdGuardHome/internal/schedule"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/urlfilter/rules"
)
2022-09-07 16:03:18 +01:00
// 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() {
2022-11-02 13:18:02 +00:00
l := len(blockedServices)
2022-09-07 16:03:18 +01:00
serviceIDs = make([]string, l)
serviceRules = make(map[string][]*rules.NetworkRule, l)
2022-11-02 13:18:02 +00:00
for i, s := range blockedServices {
netRules := make([]*rules.NetworkRule, 0, len(s.Rules))
for _, text := range s.Rules {
2024-04-02 18:22:19 +01:00
rule, err := rules.NewNetworkRule(text, rulelist.URLFilterIDBlockedService)
if err != nil {
2022-11-02 13:18:02 +00:00
log.Error("parsing blocked service %q rule %q: %s", s.ID, text, err)
2022-09-07 16:03:18 +01:00
continue
}
2022-09-07 16:03:18 +01:00
netRules = append(netRules, rule)
}
2022-09-07 16:03:18 +01:00
2022-11-02 13:18:02 +00:00
serviceIDs[i] = s.ID
serviceRules[s.ID] = netRules
}
2022-09-07 16:03:18 +01:00
slices.Sort(serviceIDs)
log.Debug("filtering: initialized %d services", l)
}
2023-07-03 12:10:40 +01:00
// BlockedServices is the configuration of blocked services.
type BlockedServices struct {
// Schedule is blocked services schedule for every day of the week.
2023-09-07 15:13:48 +01:00
Schedule *schedule.Weekly `json:"schedule" yaml:"schedule"`
2022-09-29 15:36:01 +01:00
2023-07-03 12:10:40 +01:00
// IDs is the names of blocked services.
2023-09-07 15:13:48 +01:00
IDs []string `json:"ids" yaml:"ids"`
2023-07-03 12:10:40 +01:00
}
// Clone returns a deep copy of blocked services.
func (s *BlockedServices) Clone() (c *BlockedServices) {
if s == nil {
return nil
}
return &BlockedServices{
Schedule: s.Schedule.Clone(),
IDs: slices.Clone(s.IDs),
}
}
// Validate returns an error if blocked services contain unknown service ID. s
// must not be nil.
func (s *BlockedServices) Validate() (err error) {
for _, id := range s.IDs {
_, ok := serviceRules[id]
if !ok {
return fmt.Errorf("unknown blocked-service %q", id)
}
}
return nil
}
// ApplyBlockedServices - set blocked services settings for this DNS request
2023-07-03 12:10:40 +01:00
func (d *DNSFilter) ApplyBlockedServices(setts *Settings) {
2023-09-07 15:13:48 +01:00
d.confMu.RLock()
defer d.confMu.RUnlock()
2023-07-03 12:10:40 +01:00
setts.ServicesRules = []ServiceEntry{}
2022-09-29 15:36:01 +01:00
2023-09-07 15:13:48 +01:00
bsvc := d.conf.BlockedServices
2023-07-03 12:10:40 +01:00
// TODO(s.chzhen): Use startTime from [dnsforward.dnsContext].
if !bsvc.Schedule.Contains(time.Now()) {
d.ApplyBlockedServicesList(setts, bsvc.IDs)
}
2023-07-03 12:10:40 +01:00
}
2022-09-29 15:36:01 +01:00
2023-07-03 12:10:40 +01:00
// ApplyBlockedServicesList appends filtering rules to the settings.
func (d *DNSFilter) ApplyBlockedServicesList(setts *Settings, list []string) {
for _, name := range list {
rules, ok := serviceRules[name]
if !ok {
log.Error("unknown service name: %s", name)
2022-09-29 15:36:01 +01:00
continue
}
2022-09-29 15:36:01 +01:00
setts.ServicesRules = append(setts.ServicesRules, ServiceEntry{
Name: name,
Rules: rules,
})
}
}
2019-07-23 10:16:36 +01:00
2022-11-02 13:18:02 +00:00
func (d *DNSFilter) handleBlockedServicesIDs(w http.ResponseWriter, r *http.Request) {
2023-09-07 15:13:48 +01:00
aghhttp.WriteJSONResponseOK(w, r, serviceIDs)
2022-11-02 13:18:02 +00:00
}
2022-09-07 16:03:18 +01:00
2022-11-02 13:18:02 +00:00
func (d *DNSFilter) handleBlockedServicesAll(w http.ResponseWriter, r *http.Request) {
2023-09-07 15:13:48 +01:00
aghhttp.WriteJSONResponseOK(w, r, struct {
2022-11-02 13:18:02 +00:00
BlockedServices []blockedService `json:"blocked_services"`
}{
BlockedServices: blockedServices,
})
2022-09-07 16:03:18 +01:00
}
2023-09-07 15:13:48 +01:00
// handleBlockedServicesList is the handler for the GET
// /control/blocked_services/list HTTP API.
//
// Deprecated: Use handleBlockedServicesGet.
func (d *DNSFilter) handleBlockedServicesList(w http.ResponseWriter, r *http.Request) {
2023-09-07 15:13:48 +01:00
var list []string
func() {
d.confMu.Lock()
defer d.confMu.Unlock()
2019-07-23 10:16:36 +01:00
2023-09-07 15:13:48 +01:00
list = d.conf.BlockedServices.IDs
}()
aghhttp.WriteJSONResponseOK(w, r, list)
2019-07-23 10:16:36 +01:00
}
2023-09-07 15:13:48 +01:00
// handleBlockedServicesSet is the handler for the POST
// /control/blocked_services/set HTTP API.
//
// Deprecated: Use handleBlockedServicesUpdate.
func (d *DNSFilter) handleBlockedServicesSet(w http.ResponseWriter, r *http.Request) {
2019-07-23 10:16:36 +01:00
list := []string{}
err := json.NewDecoder(r.Body).Decode(&list)
if err != nil {
aghhttp.Error(r, w, http.StatusBadRequest, "json.Decode: %s", err)
2019-07-23 10:16:36 +01:00
return
}
2023-09-07 15:13:48 +01:00
func() {
d.confMu.Lock()
defer d.confMu.Unlock()
d.conf.BlockedServices.IDs = list
log.Debug("Updated blocked services list: %d", len(list))
}()
d.conf.ConfigModified()
}
// handleBlockedServicesGet is the handler for the GET
// /control/blocked_services/get HTTP API.
func (d *DNSFilter) handleBlockedServicesGet(w http.ResponseWriter, r *http.Request) {
var bsvc *BlockedServices
func() {
d.confMu.RLock()
defer d.confMu.RUnlock()
bsvc = d.conf.BlockedServices.Clone()
}()
aghhttp.WriteJSONResponseOK(w, r, bsvc)
}
// handleBlockedServicesUpdate is the handler for the PUT
// /control/blocked_services/update HTTP API.
func (d *DNSFilter) handleBlockedServicesUpdate(w http.ResponseWriter, r *http.Request) {
bsvc := &BlockedServices{}
err := json.NewDecoder(r.Body).Decode(bsvc)
if err != nil {
aghhttp.Error(r, w, http.StatusBadRequest, "json.Decode: %s", err)
return
}
err = bsvc.Validate()
if err != nil {
aghhttp.Error(r, w, http.StatusUnprocessableEntity, "validating: %s", err)
return
}
if bsvc.Schedule == nil {
bsvc.Schedule = schedule.EmptyWeekly()
}
func() {
d.confMu.Lock()
defer d.confMu.Unlock()
d.conf.BlockedServices = bsvc
}()
2019-07-23 10:16:36 +01:00
2023-09-07 15:13:48 +01:00
log.Debug("updated blocked services schedule: %d", len(bsvc.IDs))
2019-07-23 10:16:36 +01:00
2023-09-07 15:13:48 +01:00
d.conf.ConfigModified()
2019-07-23 10:16:36 +01:00
}