2023-03-01 13:27:24 +03:00
|
|
|
package home
|
|
|
|
|
|
|
|
import (
|
2023-12-28 17:26:17 +03:00
|
|
|
"encoding"
|
2023-03-01 13:27:24 +03:00
|
|
|
"fmt"
|
2023-04-06 14:12:50 +03:00
|
|
|
"time"
|
2023-03-01 13:27:24 +03:00
|
|
|
|
2023-03-15 14:31:07 +03:00
|
|
|
"github.com/AdguardTeam/AdGuardHome/internal/filtering"
|
2023-04-06 14:12:50 +03:00
|
|
|
"github.com/AdguardTeam/AdGuardHome/internal/filtering/safesearch"
|
2023-03-01 13:27:24 +03:00
|
|
|
"github.com/AdguardTeam/dnsproxy/proxy"
|
2023-05-25 17:45:55 +03:00
|
|
|
"github.com/AdguardTeam/golibs/stringutil"
|
2023-12-28 17:26:17 +03:00
|
|
|
"github.com/google/uuid"
|
2023-03-01 13:27:24 +03:00
|
|
|
)
|
|
|
|
|
2023-12-28 17:26:17 +03:00
|
|
|
// UID is the type for the unique IDs of persistent clients.
|
|
|
|
type UID uuid.UUID
|
|
|
|
|
|
|
|
// NewUID returns a new persistent client UID. Any error returned is an error
|
|
|
|
// from the cryptographic randomness reader.
|
|
|
|
func NewUID() (uid UID, err error) {
|
|
|
|
uuidv7, err := uuid.NewV7()
|
|
|
|
|
|
|
|
return UID(uuidv7), err
|
|
|
|
}
|
|
|
|
|
|
|
|
// type check
|
|
|
|
var _ encoding.TextMarshaler = UID{}
|
|
|
|
|
|
|
|
// MarshalText implements the [encoding.TextMarshaler] for UID.
|
|
|
|
func (uid UID) MarshalText() ([]byte, error) {
|
|
|
|
return uuid.UUID(uid).MarshalText()
|
|
|
|
}
|
|
|
|
|
|
|
|
// type check
|
|
|
|
var _ encoding.TextUnmarshaler = (*UID)(nil)
|
|
|
|
|
|
|
|
// UnmarshalText implements the [encoding.TextUnmarshaler] interface for UID.
|
|
|
|
func (uid *UID) UnmarshalText(data []byte) error {
|
|
|
|
return (*uuid.UUID)(uid).UnmarshalText(data)
|
|
|
|
}
|
|
|
|
|
|
|
|
// persistentClient contains information about persistent clients.
|
|
|
|
type persistentClient struct {
|
2023-11-17 15:51:51 +03:00
|
|
|
// upstreamConfig is the custom upstream configuration for this client. If
|
|
|
|
// it's nil, it has not been initialized yet. If it's non-nil and empty,
|
|
|
|
// there are no valid upstreams. If it's non-nil and non-empty, these
|
|
|
|
// upstream must be used.
|
|
|
|
upstreamConfig *proxy.CustomUpstreamConfig
|
2023-03-01 13:27:24 +03:00
|
|
|
|
2023-11-24 15:20:32 +03:00
|
|
|
// TODO(d.kolyshev): Make safeSearchConf a pointer.
|
2023-03-15 14:31:07 +03:00
|
|
|
safeSearchConf filtering.SafeSearchConfig
|
|
|
|
SafeSearch filtering.SafeSearch
|
|
|
|
|
2023-06-27 18:03:07 +03:00
|
|
|
// BlockedServices is the configuration of blocked services of a client.
|
|
|
|
BlockedServices *filtering.BlockedServices
|
|
|
|
|
2023-03-01 13:27:24 +03:00
|
|
|
Name string
|
|
|
|
|
2023-06-27 18:03:07 +03:00
|
|
|
IDs []string
|
|
|
|
Tags []string
|
|
|
|
Upstreams []string
|
2023-03-01 13:27:24 +03:00
|
|
|
|
2023-12-28 17:26:17 +03:00
|
|
|
// UID is the unique identifier of the persistent client.
|
|
|
|
UID UID
|
|
|
|
|
2023-11-17 15:51:51 +03:00
|
|
|
UpstreamsCacheSize uint32
|
|
|
|
UpstreamsCacheEnabled bool
|
|
|
|
|
2023-03-01 13:27:24 +03:00
|
|
|
UseOwnSettings bool
|
|
|
|
FilteringEnabled bool
|
|
|
|
SafeBrowsingEnabled bool
|
|
|
|
ParentalEnabled bool
|
|
|
|
UseOwnBlockedServices bool
|
2023-04-07 13:17:40 +03:00
|
|
|
IgnoreQueryLog bool
|
|
|
|
IgnoreStatistics bool
|
2023-03-01 13:27:24 +03:00
|
|
|
}
|
|
|
|
|
2023-05-25 17:45:55 +03:00
|
|
|
// ShallowClone returns a deep copy of the client, except upstreamConfig,
|
|
|
|
// safeSearchConf, SafeSearch fields, because it's difficult to copy them.
|
2023-12-28 17:26:17 +03:00
|
|
|
func (c *persistentClient) ShallowClone() (sh *persistentClient) {
|
2023-05-25 17:45:55 +03:00
|
|
|
clone := *c
|
|
|
|
|
2023-06-27 18:03:07 +03:00
|
|
|
clone.BlockedServices = c.BlockedServices.Clone()
|
2023-05-25 17:45:55 +03:00
|
|
|
clone.IDs = stringutil.CloneSlice(c.IDs)
|
|
|
|
clone.Tags = stringutil.CloneSlice(c.Tags)
|
|
|
|
clone.Upstreams = stringutil.CloneSlice(c.Upstreams)
|
|
|
|
|
|
|
|
return &clone
|
|
|
|
}
|
|
|
|
|
2023-03-01 13:27:24 +03:00
|
|
|
// closeUpstreams closes the client-specific upstream config of c if any.
|
2023-12-28 17:26:17 +03:00
|
|
|
func (c *persistentClient) closeUpstreams() (err error) {
|
2023-03-01 13:27:24 +03:00
|
|
|
if c.upstreamConfig != nil {
|
2023-11-17 15:51:51 +03:00
|
|
|
if err = c.upstreamConfig.Close(); err != nil {
|
2023-03-01 13:27:24 +03:00
|
|
|
return fmt.Errorf("closing upstreams of client %q: %w", c.Name, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-04-06 14:12:50 +03:00
|
|
|
// setSafeSearch initializes and sets the safe search filter for this client.
|
2023-12-28 17:26:17 +03:00
|
|
|
func (c *persistentClient) setSafeSearch(
|
2023-04-06 14:12:50 +03:00
|
|
|
conf filtering.SafeSearchConfig,
|
|
|
|
cacheSize uint,
|
|
|
|
cacheTTL time.Duration,
|
|
|
|
) (err error) {
|
|
|
|
ss, err := safesearch.NewDefault(conf, fmt.Sprintf("client %q", c.Name), cacheSize, cacheTTL)
|
|
|
|
if err != nil {
|
|
|
|
// Don't wrap the error, because it's informative enough as is.
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
c.SafeSearch = ss
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|