Pull request 2187: upd-golibs

Squashed commit of the following:

commit 63c14cf0eb395f58149f5a82ff1389353f7f8127
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Tue Apr 2 20:10:10 2024 +0300

    all: imp code, docs

commit 185ccdd1d9f5acc8376fabeac647f6fddcf108b5
Merge: b6ca80a9f d4fff41b3
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Tue Apr 2 20:04:23 2024 +0300

    Merge branch 'master' into upd-golibs

commit b6ca80a9f639394758cc9000345c132a713c183c
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Tue Apr 2 20:01:10 2024 +0300

    all: upd to tags

commit 474f62319befbe22cf1bccd2320cd0d3da1629b1
Author: Ainar Garipov <a.garipov@adguard.com>
Date:   Tue Mar 26 16:33:45 2024 +0300

    all: upd golibs
This commit is contained in:
Ainar Garipov 2024-04-03 13:44:51 +03:00
parent d4fff41b3a
commit 5cc05e2c4b
21 changed files with 101 additions and 202 deletions

4
go.mod
View file

@ -3,8 +3,8 @@ module github.com/AdguardTeam/AdGuardHome
go 1.21.8 go 1.21.8
require ( require (
github.com/AdguardTeam/dnsproxy v0.66.0 github.com/AdguardTeam/dnsproxy v0.67.0
github.com/AdguardTeam/golibs v0.20.2 github.com/AdguardTeam/golibs v0.21.0
github.com/AdguardTeam/urlfilter v0.18.0 github.com/AdguardTeam/urlfilter v0.18.0
github.com/NYTimes/gziphandler v1.1.1 github.com/NYTimes/gziphandler v1.1.1
github.com/ameshkov/dnscrypt/v2 v2.2.7 github.com/ameshkov/dnscrypt/v2 v2.2.7

8
go.sum
View file

@ -1,7 +1,7 @@
github.com/AdguardTeam/dnsproxy v0.66.0 h1:RyUbyDxRSXBFjVG1l2/4HV3I98DtfIgpnZkgXkgHKnc= github.com/AdguardTeam/dnsproxy v0.67.0 h1:7oKfcA8sm9d1N4qvhsNmQWBX4+fs3sX4cAnERmBXEbw=
github.com/AdguardTeam/dnsproxy v0.66.0/go.mod h1:ZThEXbMUlP1RxfwtNW30ItPAHE6OF4YFygK8qjU/cvY= github.com/AdguardTeam/dnsproxy v0.67.0/go.mod h1:XLfD6IpSplUZZ+f5vhWSJW1mp4wm+KkHWiMo9w7U1Ls=
github.com/AdguardTeam/golibs v0.20.2 h1:9gThBFyuELf2ohRnUNeQGQsVBYI7YslaRLUFwVaUj8E= github.com/AdguardTeam/golibs v0.21.0 h1:0swWyNaHTmT7aMwffKd9d54g4wBd8Oaj0fl+5l/PRdE=
github.com/AdguardTeam/golibs v0.20.2/go.mod h1:/votX6WK1PdcZ3T2kBOPjPCGmfhlKixhI6ljYrFRPvI= github.com/AdguardTeam/golibs v0.21.0/go.mod h1:/votX6WK1PdcZ3T2kBOPjPCGmfhlKixhI6ljYrFRPvI=
github.com/AdguardTeam/urlfilter v0.18.0 h1:ZZzwODC/ADpjJSODxySrrUnt/fvOCfGFaCW6j+wsGfQ= github.com/AdguardTeam/urlfilter v0.18.0 h1:ZZzwODC/ADpjJSODxySrrUnt/fvOCfGFaCW6j+wsGfQ=
github.com/AdguardTeam/urlfilter v0.18.0/go.mod h1:IXxBwedLiZA2viyHkaFxY/8mjub0li2PXRg8a3d9Z1s= github.com/AdguardTeam/urlfilter v0.18.0/go.mod h1:IXxBwedLiZA2viyHkaFxY/8mjub0li2PXRg8a3d9Z1s=
github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I=

View file

@ -1,10 +1,7 @@
package aghnet package aghnet
import ( import (
"fmt"
"strings" "strings"
"github.com/AdguardTeam/golibs/stringutil"
) )
// NormalizeDomain returns a lowercased version of host without the final dot, // NormalizeDomain returns a lowercased version of host without the final dot,
@ -19,25 +16,3 @@ func NormalizeDomain(host string) (norm string) {
return strings.ToLower(strings.TrimSuffix(host, ".")) return strings.ToLower(strings.TrimSuffix(host, "."))
} }
// NewDomainNameSet returns nil and error, if list has duplicate or empty domain
// name. Otherwise returns a set, which contains domain names normalized using
// [NormalizeDomain].
func NewDomainNameSet(list []string) (set *stringutil.Set, err error) {
set = stringutil.NewSet()
for i, host := range list {
if host == "" {
return nil, fmt.Errorf("at index %d: hostname is empty", i)
}
host = NormalizeDomain(host)
if set.Has(host) {
return nil, fmt.Errorf("duplicate hostname %q at index %d", host, i)
}
set.Add(host)
}
return set, nil
}

View file

@ -1,59 +0,0 @@
package aghnet_test
import (
"testing"
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
"github.com/AdguardTeam/golibs/testutil"
"github.com/stretchr/testify/assert"
)
func TestNewDomainNameSet(t *testing.T) {
t.Parallel()
testCases := []struct {
name string
wantErrMsg string
in []string
}{{
name: "nil",
wantErrMsg: "",
in: nil,
}, {
name: "success",
wantErrMsg: "",
in: []string{
"Domain.Example",
".",
},
}, {
name: "dups",
wantErrMsg: `duplicate hostname "domain.example" at index 1`,
in: []string{
"Domain.Example",
"domain.example",
},
}, {
name: "bad_domain",
wantErrMsg: "at index 0: hostname is empty",
in: []string{
"",
},
}}
for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
set, err := aghnet.NewDomainNameSet(tc.in)
testutil.AssertErrorMsg(t, tc.wantErrMsg, err)
if err != nil {
return
}
for _, host := range tc.in {
assert.Truef(t, set.Has(aghnet.NormalizeDomain(host)), "%q not matched", host)
}
})
}
}

View file

@ -5,8 +5,8 @@ import (
"io" "io"
"io/fs" "io/fs"
"github.com/AdguardTeam/golibs/container"
"github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/stringutil"
) )
// FileWalker is the signature of a function called for files in the file tree. // FileWalker is the signature of a function called for files in the file tree.
@ -56,7 +56,7 @@ func checkFile(
// srcSet. srcSet must be non-nil. // srcSet. srcSet must be non-nil.
func handlePatterns( func handlePatterns(
fsys fs.FS, fsys fs.FS,
srcSet *stringutil.Set, srcSet *container.MapSet[string],
patterns ...string, patterns ...string,
) (sub []string, err error) { ) (sub []string, err error) {
sub = make([]string, 0, len(patterns)) sub = make([]string, 0, len(patterns))
@ -87,7 +87,7 @@ func handlePatterns(
func (fw FileWalker) Walk(fsys fs.FS, initial ...string) (ok bool, err error) { func (fw FileWalker) Walk(fsys fs.FS, initial ...string) (ok bool, err error) {
// The slice of sources keeps the order in which the files are walked since // The slice of sources keeps the order in which the files are walked since
// srcSet.Values() returns strings in undefined order. // srcSet.Values() returns strings in undefined order.
srcSet := stringutil.NewSet() srcSet := container.NewMapSet[string]()
var src []string var src []string
src, err = handlePatterns(fsys, srcSet, initial...) src, err = handlePatterns(fsys, srcSet, initial...)
if err != nil { if err != nil {

View file

@ -6,10 +6,10 @@ import (
"io/fs" "io/fs"
"path/filepath" "path/filepath"
"github.com/AdguardTeam/golibs/container"
"github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log" "github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/osutil" "github.com/AdguardTeam/golibs/osutil"
"github.com/AdguardTeam/golibs/stringutil"
"github.com/fsnotify/fsnotify" "github.com/fsnotify/fsnotify"
) )
@ -46,7 +46,7 @@ type osWatcher struct {
events chan event events chan event
// files is the set of tracked files. // files is the set of tracked files.
files *stringutil.Set files *container.MapSet[string]
} }
// osWatcherPref is a prefix for logging and wrapping errors in osWathcer's // osWatcherPref is a prefix for logging and wrapping errors in osWathcer's
@ -67,7 +67,7 @@ func NewOSWritesWatcher() (w FSWatcher, err error) {
return &osWatcher{ return &osWatcher{
watcher: watcher, watcher: watcher,
events: make(chan event, 1), events: make(chan event, 1),
files: stringutil.NewSet(), files: container.NewMapSet[string](),
}, nil }, nil
} }

View file

@ -12,10 +12,10 @@ import (
"github.com/AdguardTeam/AdGuardHome/internal/filtering" "github.com/AdguardTeam/AdGuardHome/internal/filtering"
"github.com/AdguardTeam/AdGuardHome/internal/filtering/safesearch" "github.com/AdguardTeam/AdGuardHome/internal/filtering/safesearch"
"github.com/AdguardTeam/dnsproxy/proxy" "github.com/AdguardTeam/dnsproxy/proxy"
"github.com/AdguardTeam/golibs/container"
"github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log" "github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/netutil" "github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/stringutil"
"github.com/google/uuid" "github.com/google/uuid"
) )
@ -98,7 +98,7 @@ type Persistent struct {
} }
// SetTags sets the tags if they are known, otherwise logs an unknown tag. // SetTags sets the tags if they are known, otherwise logs an unknown tag.
func (c *Persistent) SetTags(tags []string, known *stringutil.Set) { func (c *Persistent) SetTags(tags []string, known *container.MapSet[string]) {
for _, t := range tags { for _, t := range tags {
if !known.Has(t) { if !known.Has(t) {
log.Info("skipping unknown tag %q", t) log.Info("skipping unknown tag %q", t)

View file

@ -5,10 +5,12 @@ import (
"fmt" "fmt"
"net/http" "net/http"
"net/netip" "net/netip"
"slices"
"strings" "strings"
"github.com/AdguardTeam/AdGuardHome/internal/aghalg" "github.com/AdguardTeam/AdGuardHome/internal/aghalg"
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp" "github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
"github.com/AdguardTeam/golibs/container"
"github.com/AdguardTeam/golibs/log" "github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/stringutil" "github.com/AdguardTeam/golibs/stringutil"
"github.com/AdguardTeam/urlfilter" "github.com/AdguardTeam/urlfilter"
@ -16,22 +18,19 @@ import (
"github.com/AdguardTeam/urlfilter/rules" "github.com/AdguardTeam/urlfilter/rules"
) )
// unit is a convenient alias for struct{}
type unit = struct{}
// accessManager controls IP and client blocking that takes place before all // accessManager controls IP and client blocking that takes place before all
// other processing. An accessManager is safe for concurrent use. // other processing. An accessManager is safe for concurrent use.
type accessManager struct { type accessManager struct {
allowedIPs map[netip.Addr]unit allowedIPs *container.MapSet[netip.Addr]
blockedIPs map[netip.Addr]unit blockedIPs *container.MapSet[netip.Addr]
allowedClientIDs *stringutil.Set allowedClientIDs *container.MapSet[string]
blockedClientIDs *stringutil.Set blockedClientIDs *container.MapSet[string]
// TODO(s.chzhen): Use [aghnet.IgnoreEngine]. // TODO(s.chzhen): Use [aghnet.IgnoreEngine].
blockedHostsEng *urlfilter.DNSEngine blockedHostsEng *urlfilter.DNSEngine
// TODO(a.garipov): Create a type for a set of IP networks. // TODO(a.garipov): Create a type for an efficient tree set of IP networks.
allowedNets []netip.Prefix allowedNets []netip.Prefix
blockedNets []netip.Prefix blockedNets []netip.Prefix
} }
@ -40,15 +39,15 @@ type accessManager struct {
// which may be an IP address, a CIDR, or a ClientID. // which may be an IP address, a CIDR, or a ClientID.
func processAccessClients( func processAccessClients(
clientStrs []string, clientStrs []string,
ips map[netip.Addr]unit, ips *container.MapSet[netip.Addr],
nets *[]netip.Prefix, nets *[]netip.Prefix,
clientIDs *stringutil.Set, clientIDs *container.MapSet[string],
) (err error) { ) (err error) {
for i, s := range clientStrs { for i, s := range clientStrs {
var ip netip.Addr var ip netip.Addr
var ipnet netip.Prefix var ipnet netip.Prefix
if ip, err = netip.ParseAddr(s); err == nil { if ip, err = netip.ParseAddr(s); err == nil {
ips[ip] = unit{} ips.Add(ip)
} else if ipnet, err = netip.ParsePrefix(s); err == nil { } else if ipnet, err = netip.ParsePrefix(s); err == nil {
*nets = append(*nets, ipnet) *nets = append(*nets, ipnet)
} else { } else {
@ -67,11 +66,11 @@ func processAccessClients(
// newAccessCtx creates a new accessCtx. // newAccessCtx creates a new accessCtx.
func newAccessCtx(allowed, blocked, blockedHosts []string) (a *accessManager, err error) { func newAccessCtx(allowed, blocked, blockedHosts []string) (a *accessManager, err error) {
a = &accessManager{ a = &accessManager{
allowedIPs: map[netip.Addr]unit{}, allowedIPs: container.NewMapSet[netip.Addr](),
blockedIPs: map[netip.Addr]unit{}, blockedIPs: container.NewMapSet[netip.Addr](),
allowedClientIDs: stringutil.NewSet(), allowedClientIDs: container.NewMapSet[string](),
blockedClientIDs: stringutil.NewSet(), blockedClientIDs: container.NewMapSet[string](),
} }
err = processAccessClients(allowed, a.allowedIPs, &a.allowedNets, a.allowedClientIDs) err = processAccessClients(allowed, a.allowedIPs, &a.allowedNets, a.allowedClientIDs)
@ -109,7 +108,7 @@ func newAccessCtx(allowed, blocked, blockedHosts []string) (a *accessManager, er
// allowlistMode returns true if this *accessCtx is in the allowlist mode. // allowlistMode returns true if this *accessCtx is in the allowlist mode.
func (a *accessManager) allowlistMode() (ok bool) { func (a *accessManager) allowlistMode() (ok bool) {
return len(a.allowedIPs) != 0 || a.allowedClientIDs.Len() != 0 || len(a.allowedNets) != 0 return a.allowedIPs.Len() != 0 || a.allowedClientIDs.Len() != 0 || len(a.allowedNets) != 0
} }
// isBlockedClientID returns true if the ClientID should be blocked. // isBlockedClientID returns true if the ClientID should be blocked.
@ -152,7 +151,7 @@ func (a *accessManager) isBlockedIP(ip netip.Addr) (blocked bool, rule string) {
ipnets = a.allowedNets ipnets = a.allowedNets
} }
if _, ok := ips[ip]; ok { if ips.Has(ip) {
return blocked, ip.String() return blocked, ip.String()
} }
@ -176,9 +175,9 @@ func (s *Server) accessListJSON() (j accessListJSON) {
defer s.serverLock.RUnlock() defer s.serverLock.RUnlock()
return accessListJSON{ return accessListJSON{
AllowedClients: stringutil.CloneSlice(s.conf.AllowedClients), AllowedClients: slices.Clone(s.conf.AllowedClients),
DisallowedClients: stringutil.CloneSlice(s.conf.DisallowedClients), DisallowedClients: slices.Clone(s.conf.DisallowedClients),
BlockedHosts: stringutil.CloneSlice(s.conf.BlockedHosts), BlockedHosts: slices.Clone(s.conf.BlockedHosts),
} }
} }

View file

@ -19,6 +19,7 @@ import (
"github.com/AdguardTeam/AdGuardHome/internal/filtering" "github.com/AdguardTeam/AdGuardHome/internal/filtering"
"github.com/AdguardTeam/dnsproxy/proxy" "github.com/AdguardTeam/dnsproxy/proxy"
"github.com/AdguardTeam/dnsproxy/upstream" "github.com/AdguardTeam/dnsproxy/upstream"
"github.com/AdguardTeam/golibs/container"
"github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log" "github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/netutil" "github.com/AdguardTeam/golibs/netutil"
@ -461,26 +462,27 @@ func (s *Server) prepareIpsetListSettings() (err error) {
// unspecPorts if its address is unspecified. // unspecPorts if its address is unspecified.
func collectListenAddr( func collectListenAddr(
addrPort netip.AddrPort, addrPort netip.AddrPort,
addrs map[netip.AddrPort]unit, addrs *container.MapSet[netip.AddrPort],
unspecPorts map[uint16]unit, unspecPorts *container.MapSet[uint16],
) { ) {
if addrPort == (netip.AddrPort{}) { if addrPort == (netip.AddrPort{}) {
return return
} }
addrs[addrPort] = unit{} addrs.Add(addrPort)
if addrPort.Addr().IsUnspecified() { if addrPort.Addr().IsUnspecified() {
unspecPorts[addrPort.Port()] = unit{} unspecPorts.Add(addrPort.Port())
} }
} }
// collectDNSAddrs returns configured set of listening addresses. It also // collectDNSAddrs returns configured set of listening addresses. It also
// returns a set of ports of each unspecified listening address. // returns a set of ports of each unspecified listening address.
func (conf *ServerConfig) collectDNSAddrs() (addrs mapAddrPortSet, unspecPorts map[uint16]unit) { func (conf *ServerConfig) collectDNSAddrs() (
// TODO(e.burkov): Perhaps, we shouldn't allocate as much memory, since the addrs *container.MapSet[netip.AddrPort],
// TCP and UDP listening addresses are currently the same. unspecPorts *container.MapSet[uint16],
addrs = make(map[netip.AddrPort]unit, len(conf.TCPListenAddrs)+len(conf.UDPListenAddrs)) ) {
unspecPorts = map[uint16]unit{} addrs = container.NewMapSet[netip.AddrPort]()
unspecPorts = container.NewMapSet[uint16]()
for _, laddr := range conf.TCPListenAddrs { for _, laddr := range conf.TCPListenAddrs {
collectListenAddr(laddr.AddrPort(), addrs, unspecPorts) collectListenAddr(laddr.AddrPort(), addrs, unspecPorts)
@ -511,26 +513,12 @@ type emptyAddrPortSet struct{}
// Has implements the [addrPortSet] interface for [emptyAddrPortSet]. // Has implements the [addrPortSet] interface for [emptyAddrPortSet].
func (emptyAddrPortSet) Has(_ netip.AddrPort) (ok bool) { return false } func (emptyAddrPortSet) Has(_ netip.AddrPort) (ok bool) { return false }
// mapAddrPortSet is the [addrPortSet] containing values of [netip.AddrPort] as
// keys of a map.
type mapAddrPortSet map[netip.AddrPort]unit
// type check
var _ addrPortSet = mapAddrPortSet{}
// Has implements the [addrPortSet] interface for [mapAddrPortSet].
func (m mapAddrPortSet) Has(addrPort netip.AddrPort) (ok bool) {
_, ok = m[addrPort]
return ok
}
// combinedAddrPortSet is the [addrPortSet] defined by some IP addresses along // combinedAddrPortSet is the [addrPortSet] defined by some IP addresses along
// with ports, any combination of which is considered being in the set. // with ports, any combination of which is considered being in the set.
type combinedAddrPortSet struct { type combinedAddrPortSet struct {
// TODO(e.burkov): Use sorted slices in combination with binary search. // TODO(e.burkov): Use container.SliceSet when available.
ports map[uint16]unit ports *container.MapSet[uint16]
addrs []netip.Addr addrs *container.MapSet[netip.Addr]
} }
// type check // type check
@ -538,9 +526,7 @@ var _ addrPortSet = (*combinedAddrPortSet)(nil)
// Has implements the [addrPortSet] interface for [*combinedAddrPortSet]. // Has implements the [addrPortSet] interface for [*combinedAddrPortSet].
func (m *combinedAddrPortSet) Has(addrPort netip.AddrPort) (ok bool) { func (m *combinedAddrPortSet) Has(addrPort netip.AddrPort) (ok bool) {
_, ok = m.ports[addrPort.Port()] return m.ports.Has(addrPort.Port()) && m.addrs.Has(addrPort.Addr())
return ok && slices.Contains(m.addrs, addrPort.Addr())
} }
// filterOut filters out all the upstreams that match um. It returns all the // filterOut filters out all the upstreams that match um. It returns all the
@ -578,11 +564,11 @@ func filterOutAddrs(upsConf *proxy.UpstreamConfig, set addrPortSet) (err error)
func (conf *ServerConfig) ourAddrsSet() (m addrPortSet, err error) { func (conf *ServerConfig) ourAddrsSet() (m addrPortSet, err error) {
addrs, unspecPorts := conf.collectDNSAddrs() addrs, unspecPorts := conf.collectDNSAddrs()
switch { switch {
case len(addrs) == 0: case addrs.Len() == 0:
log.Debug("dnsforward: no listen addresses") log.Debug("dnsforward: no listen addresses")
return emptyAddrPortSet{}, nil return emptyAddrPortSet{}, nil
case len(unspecPorts) == 0: case unspecPorts.Len() == 0:
log.Debug("dnsforward: filtering out addresses %s", addrs) log.Debug("dnsforward: filtering out addresses %s", addrs)
return addrs, nil return addrs, nil
@ -598,7 +584,7 @@ func (conf *ServerConfig) ourAddrsSet() (m addrPortSet, err error) {
return &combinedAddrPortSet{ return &combinedAddrPortSet{
ports: unspecPorts, ports: unspecPorts,
addrs: ifaceAddrs, addrs: container.NewMapSet(ifaceAddrs...),
}, nil }, nil
} }
} }

View file

@ -308,13 +308,13 @@ func (s *Server) WriteDiskConfig(c *Config) {
sc := s.conf.Config sc := s.conf.Config
*c = sc *c = sc
c.RatelimitWhitelist = slices.Clone(sc.RatelimitWhitelist) c.RatelimitWhitelist = slices.Clone(sc.RatelimitWhitelist)
c.BootstrapDNS = stringutil.CloneSlice(sc.BootstrapDNS) c.BootstrapDNS = slices.Clone(sc.BootstrapDNS)
c.FallbackDNS = stringutil.CloneSlice(sc.FallbackDNS) c.FallbackDNS = slices.Clone(sc.FallbackDNS)
c.AllowedClients = stringutil.CloneSlice(sc.AllowedClients) c.AllowedClients = slices.Clone(sc.AllowedClients)
c.DisallowedClients = stringutil.CloneSlice(sc.DisallowedClients) c.DisallowedClients = slices.Clone(sc.DisallowedClients)
c.BlockedHosts = stringutil.CloneSlice(sc.BlockedHosts) c.BlockedHosts = slices.Clone(sc.BlockedHosts)
c.TrustedProxies = slices.Clone(sc.TrustedProxies) c.TrustedProxies = slices.Clone(sc.TrustedProxies)
c.UpstreamDNS = stringutil.CloneSlice(sc.UpstreamDNS) c.UpstreamDNS = slices.Clone(sc.UpstreamDNS)
} }
// LocalPTRResolvers returns the current local PTR resolver configuration. // LocalPTRResolvers returns the current local PTR resolver configuration.
@ -322,7 +322,7 @@ func (s *Server) LocalPTRResolvers() (localPTRResolvers []string) {
s.serverLock.RLock() s.serverLock.RLock()
defer s.serverLock.RUnlock() defer s.serverLock.RUnlock()
return stringutil.CloneSlice(s.conf.LocalPTRResolvers) return slices.Clone(s.conf.LocalPTRResolvers)
} }
// AddrProcConfig returns the current address processing configuration. Only // AddrProcConfig returns the current address processing configuration. Only

View file

@ -13,9 +13,9 @@ import (
"github.com/AdguardTeam/AdGuardHome/internal/aghrenameio" "github.com/AdguardTeam/AdGuardHome/internal/aghrenameio"
"github.com/AdguardTeam/AdGuardHome/internal/filtering/rulelist" "github.com/AdguardTeam/AdGuardHome/internal/filtering/rulelist"
"github.com/AdguardTeam/golibs/container"
"github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log" "github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/stringutil"
) )
// filterDir is the subdirectory of a data directory to store downloaded // filterDir is the subdirectory of a data directory to store downloaded
@ -234,7 +234,7 @@ func (d *DNSFilter) loadFilters(array []FilterYAML) {
} }
func deduplicateFilters(filters []FilterYAML) (deduplicated []FilterYAML) { func deduplicateFilters(filters []FilterYAML) (deduplicated []FilterYAML) {
urls := stringutil.NewSet() urls := container.NewMapSet[string]()
lastIdx := 0 lastIdx := 0
for _, filter := range filters { for _, filter := range filters {

View file

@ -20,11 +20,11 @@ import (
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp" "github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
"github.com/AdguardTeam/AdGuardHome/internal/filtering/rulelist" "github.com/AdguardTeam/AdGuardHome/internal/filtering/rulelist"
"github.com/AdguardTeam/golibs/container"
"github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/hostsfile" "github.com/AdguardTeam/golibs/hostsfile"
"github.com/AdguardTeam/golibs/log" "github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/mathutil" "github.com/AdguardTeam/golibs/mathutil"
"github.com/AdguardTeam/golibs/stringutil"
"github.com/AdguardTeam/golibs/syncutil" "github.com/AdguardTeam/golibs/syncutil"
"github.com/AdguardTeam/urlfilter" "github.com/AdguardTeam/urlfilter"
"github.com/AdguardTeam/urlfilter/filterlist" "github.com/AdguardTeam/urlfilter/filterlist"
@ -629,7 +629,7 @@ func (d *DNSFilter) processRewrites(host string, qtype uint16) (res Result) {
res.Reason = Rewritten res.Reason = Rewritten
cnames := stringutil.NewSet() cnames := container.NewMapSet[string]()
origHost := host origHost := host
for matched && len(rewrites) > 0 && rewrites[0].Type == dns.TypeCNAME { for matched && len(rewrites) > 0 && rewrites[0].Type == dns.TypeCNAME {
rw := rewrites[0] rw := rewrites[0]

View file

@ -5,6 +5,7 @@ import (
"sync/atomic" "sync/atomic"
"github.com/AdguardTeam/AdGuardHome/internal/filtering/rulelist" "github.com/AdguardTeam/AdGuardHome/internal/filtering/rulelist"
"github.com/AdguardTeam/golibs/container"
"github.com/AdguardTeam/golibs/log" "github.com/AdguardTeam/golibs/log"
) )
@ -41,7 +42,7 @@ func (g *idGenerator) next() (id rulelist.URLFilterID) {
// fix ensures that flts all have unique IDs. // fix ensures that flts all have unique IDs.
func (g *idGenerator) fix(flts []FilterYAML) { func (g *idGenerator) fix(flts []FilterYAML) {
set := map[rulelist.URLFilterID]struct{}{} set := container.NewMapSet[rulelist.URLFilterID]()
for i, f := range flts { for i, f := range flts {
id := f.ID id := f.ID
if id == 0 { if id == 0 {
@ -49,14 +50,14 @@ func (g *idGenerator) fix(flts []FilterYAML) {
flts[i].ID = id flts[i].ID = id
} }
if _, ok := set[id]; !ok { if !set.Has(id) {
set[id] = struct{}{} set.Add(id)
continue continue
} }
newID := g.next() newID := g.next()
for _, ok := set[newID]; ok; _, ok = set[newID] { for set.Has(newID) {
newID = g.next() newID = g.next()
} }
@ -68,6 +69,6 @@ func (g *idGenerator) fix(flts []FilterYAML) {
) )
flts[i].ID = newID flts[i].ID = newID
set[newID] = struct{}{} set.Add(newID)
} }
} }

View file

@ -7,8 +7,8 @@ import (
"strings" "strings"
"sync" "sync"
"github.com/AdguardTeam/golibs/container"
"github.com/AdguardTeam/golibs/log" "github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/stringutil"
"github.com/AdguardTeam/urlfilter" "github.com/AdguardTeam/urlfilter"
"github.com/AdguardTeam/urlfilter/filterlist" "github.com/AdguardTeam/urlfilter/filterlist"
"github.com/AdguardTeam/urlfilter/rules" "github.com/AdguardTeam/urlfilter/rules"
@ -85,7 +85,7 @@ func (s *DefaultStorage) MatchRequest(dReq *urlfilter.DNSRequest) (rws []*rules.
} }
// TODO(a.garipov): Check cnames for cycles on initialization. // TODO(a.garipov): Check cnames for cycles on initialization.
cnames := stringutil.NewSet() cnames := container.NewMapSet[string]()
host := dReq.Hostname host := dReq.Hostname
for len(rrules) > 0 && rrules[0].DNSRewrite != nil && rrules[0].DNSRewrite.NewCNAME != "" { for len(rrules) > 0 && rrules[0].DNSRewrite != nil && rrules[0].DNSRewrite.NewCNAME != "" {
rule := rrules[0] rule := rrules[0]

View file

@ -19,6 +19,7 @@ import (
"github.com/AdguardTeam/AdGuardHome/internal/whois" "github.com/AdguardTeam/AdGuardHome/internal/whois"
"github.com/AdguardTeam/dnsproxy/proxy" "github.com/AdguardTeam/dnsproxy/proxy"
"github.com/AdguardTeam/dnsproxy/upstream" "github.com/AdguardTeam/dnsproxy/upstream"
"github.com/AdguardTeam/golibs/container"
"github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/hostsfile" "github.com/AdguardTeam/golibs/hostsfile"
"github.com/AdguardTeam/golibs/log" "github.com/AdguardTeam/golibs/log"
@ -54,7 +55,7 @@ type clientsContainer struct {
// ipToRC maps IP addresses to runtime client information. // ipToRC maps IP addresses to runtime client information.
ipToRC map[netip.Addr]*client.Runtime ipToRC map[netip.Addr]*client.Runtime
allTags *stringutil.Set allTags *container.MapSet[string]
// dhcp is the DHCP service implementation. // dhcp is the DHCP service implementation.
dhcp DHCP dhcp DHCP
@ -108,7 +109,7 @@ func (clients *clientsContainer) Init(
clients.clientIndex = client.NewIndex() clients.clientIndex = client.NewIndex()
clients.allTags = stringutil.NewSet(clientTags...) clients.allTags = container.NewMapSet(clientTags...)
// TODO(e.burkov): Use [dhcpsvc] implementation when it's ready. // TODO(e.burkov): Use [dhcpsvc] implementation when it's ready.
clients.dhcp = dhcpServer clients.dhcp = dhcpServer
@ -213,7 +214,7 @@ type clientObject struct {
// toPersistent returns an initialized persistent client if there are no errors. // toPersistent returns an initialized persistent client if there are no errors.
func (o *clientObject) toPersistent( func (o *clientObject) toPersistent(
filteringConf *filtering.Config, filteringConf *filtering.Config,
allTags *stringutil.Set, allTags *container.MapSet[string],
) (cli *client.Persistent, err error) { ) (cli *client.Persistent, err error) {
cli = &client.Persistent{ cli = &client.Persistent{
Name: o.Name, Name: o.Name,
@ -307,8 +308,8 @@ func (clients *clientsContainer) forConfig() (objs []*clientObject) {
BlockedServices: cli.BlockedServices.Clone(), BlockedServices: cli.BlockedServices.Clone(),
IDs: cli.IDs(), IDs: cli.IDs(),
Tags: stringutil.CloneSlice(cli.Tags), Tags: slices.Clone(cli.Tags),
Upstreams: stringutil.CloneSlice(cli.Upstreams), Upstreams: slices.Clone(cli.Upstreams),
UID: cli.UID, UID: cli.UID,

View file

@ -5,12 +5,12 @@ import (
"net/http" "net/http"
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp" "github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
"github.com/AdguardTeam/golibs/container"
"github.com/AdguardTeam/golibs/log" "github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/stringutil"
) )
// TODO(a.garipov): Get rid of a global or generate from .twosky.json. // TODO(a.garipov): Get rid of a global or generate from .twosky.json.
var allowedLanguages = stringutil.NewSet( var allowedLanguages = container.NewMapSet(
"ar", "ar",
"be", "be",
"bg", "bg",

View file

@ -9,6 +9,7 @@ import (
"strings" "strings"
"sync" "sync"
"github.com/AdguardTeam/golibs/container"
"github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log" "github.com/AdguardTeam/golibs/log"
"github.com/digineo/go-ipset/v2" "github.com/digineo/go-ipset/v2"
@ -174,18 +175,6 @@ func (p *props) parseAttrData(a netfilter.Attribute) {
} }
} }
// unit is a convenient alias for struct{}.
type unit = struct{}
// ipsInIpset is the type of a set of IP-address-to-ipset mappings.
type ipsInIpset map[ipInIpsetEntry]unit
// ipInIpsetEntry is the type for entries in an ipsInIpset set.
type ipInIpsetEntry struct {
ipsetName string
ipArr [net.IPv6len]byte
}
// manager is the Linux Netfilter ipset manager. // manager is the Linux Netfilter ipset manager.
type manager struct { type manager struct {
nameToIpset map[string]props nameToIpset map[string]props
@ -196,17 +185,24 @@ type manager struct {
// mu protects all properties below. // mu protects all properties below.
mu *sync.Mutex mu *sync.Mutex
// TODO(a.garipov): Currently, the ipset list is static, and we don't // TODO(a.garipov): Currently, the ipset list is static, and we don't read
// read the IPs already in sets, so we can assume that all incoming IPs // the IPs already in sets, so we can assume that all incoming IPs are
// are either added to all corresponding ipsets or not. When that stops // either added to all corresponding ipsets or not. When that stops being
// being the case, for example if we add dynamic reconfiguration of // the case, for example if we add dynamic reconfiguration of ipsets, this
// ipsets, this map will need to become a per-ipset-name one. // map will need to become a per-ipset-name one.
addedIPs ipsInIpset addedIPs *container.MapSet[ipInIpsetEntry]
ipv4Conn ipsetConn ipv4Conn ipsetConn
ipv6Conn ipsetConn ipv6Conn ipsetConn
} }
// ipInIpsetEntry is the type for entries in [manager.addIPs].
type ipInIpsetEntry struct {
ipsetName string
// TODO(schzen): Use netip.Addr.
ipArr [net.IPv6len]byte
}
// dialNetfilter establishes connections to Linux's netfilter module. // dialNetfilter establishes connections to Linux's netfilter module.
func (m *manager) dialNetfilter(conf *netlink.Config) (err error) { func (m *manager) dialNetfilter(conf *netlink.Config) (err error) {
// The kernel API does not actually require two sockets but package // The kernel API does not actually require two sockets but package
@ -372,7 +368,7 @@ func newManagerWithDialer(ipsetConf []string, dial dialer) (mgr Manager, err err
dial: dial, dial: dial,
addedIPs: make(ipsInIpset), addedIPs: container.NewMapSet[ipInIpsetEntry](),
} }
err = m.dialNetfilter(&netlink.Config{}) err = m.dialNetfilter(&netlink.Config{})
@ -438,7 +434,7 @@ func (m *manager) addIPs(host string, set props, ips []net.IP) (n int, err error
} }
copy(e.ipArr[:], ip.To16()) copy(e.ipArr[:], ip.To16())
if _, added := m.addedIPs[e]; added { if m.addedIPs.Has(e) {
continue continue
} }
@ -471,7 +467,7 @@ func (m *manager) addIPs(host string, set props, ips []net.IP) (n int, err error
for _, e := range newAddedEntries { for _, e := range newAddedEntries {
s := m.nameToIpset[e.ipsetName] s := m.nameToIpset[e.ipsetName]
if s.isPersistent { if s.isPersistent {
m.addedIPs[e] = unit{} m.addedIPs.Add(e)
} }
} }

View file

@ -7,6 +7,7 @@ import (
"net" "net"
"net/http" "net/http"
"net/url" "net/url"
"slices"
"strconv" "strconv"
"strings" "strings"
"time" "time"
@ -15,7 +16,6 @@ import (
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp" "github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
"github.com/AdguardTeam/AdGuardHome/internal/aghnet" "github.com/AdguardTeam/AdGuardHome/internal/aghnet"
"github.com/AdguardTeam/golibs/log" "github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/stringutil"
"github.com/AdguardTeam/golibs/timeutil" "github.com/AdguardTeam/golibs/timeutil"
"golang.org/x/net/idna" "golang.org/x/net/idna"
) )
@ -308,7 +308,7 @@ func parseSearchCriterion(q url.Values, name string, ct criterionType) (
asciiVal = "" asciiVal = ""
} }
case ctFilteringStatus: case ctFilteringStatus:
if !stringutil.InSlice(filteringStatusValues, val) { if !slices.Contains(filteringStatusValues, val) {
return false, sc, fmt.Errorf("invalid value %s", val) return false, sc, fmt.Errorf("invalid value %s", val)
} }
default: default:

View file

@ -26,7 +26,7 @@ require (
github.com/kyoh86/nolint v0.0.1 // indirect github.com/kyoh86/nolint v0.0.1 // indirect
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect
golang.org/x/exp/typeparams v0.0.0-20240222234643-814bf88cf225 // indirect golang.org/x/exp/typeparams v0.0.0-20240325151524-a685a6edb6d8 // indirect
golang.org/x/mod v0.16.0 // indirect golang.org/x/mod v0.16.0 // indirect
golang.org/x/sync v0.6.0 // indirect golang.org/x/sync v0.6.0 // indirect
golang.org/x/sys v0.18.0 // indirect golang.org/x/sys v0.18.0 // indirect

View file

@ -63,8 +63,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug= golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug=
golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/exp/typeparams v0.0.0-20240222234643-814bf88cf225 h1:BzKNaIRXh1bD+1557OcFIHlpYBiVbK4zEyn8zBHi1SE= golang.org/x/exp/typeparams v0.0.0-20240325151524-a685a6edb6d8 h1:ShhqwXlNzuDeQzaa6htzo1S333ACXZzJZgZLpKAza8E=
golang.org/x/exp/typeparams v0.0.0-20240222234643-814bf88cf225/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/exp/typeparams v0.0.0-20240325151524-a685a6edb6d8/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=

View file

@ -52,7 +52,7 @@ func prepareMultipartMsg(
w := multipart.NewWriter(buf) w := multipart.NewWriter(buf)
var fw io.Writer var fw io.Writer
err = mapsutil.OrderedRangeError(formData, w.WriteField) err = mapsutil.SortedRangeError(formData, w.WriteField)
if err != nil { if err != nil {
return nil, "", fmt.Errorf("writing field: %w", err) return nil, "", fmt.Errorf("writing field: %w", err)
} }