From ef88f7462f9e770a54ea8735d40a291e2bf89d18 Mon Sep 17 00:00:00 2001 From: Stanislav Chzhen Date: Fri, 6 Oct 2023 13:16:39 +0300 Subject: [PATCH] Pull request 2024: 6233-imp-ipset Updates #6233. Squashed commit of the following: commit 308754d9cfc24005352bae6db420ad8a5ccde3eb Merge: 8289df04f 5d7e59e37 Author: Stanislav Chzhen Date: Fri Oct 6 13:04:13 2023 +0300 Merge branch 'master' into 6233-imp-ipset commit 8289df04f1827e28ea481e6880ceb72d4036dd4f Author: Stanislav Chzhen Date: Thu Oct 5 19:53:53 2023 +0300 ipset: imp naming commit b24ddd547128db58dcba1a0bf153398db8d9b71c Author: Stanislav Chzhen Date: Thu Oct 5 19:16:40 2023 +0300 all: imp ipset --- internal/dnsforward/ipset.go | 6 +- internal/{aghnet => ipset}/ipset.go | 16 ++--- internal/{aghnet => ipset}/ipset_linux.go | 62 +++++++++---------- .../ipset_linux_internal_test.go} | 36 +++++------ internal/{aghnet => ipset}/ipset_others.go | 4 +- 5 files changed, 63 insertions(+), 61 deletions(-) rename internal/{aghnet => ipset}/ipset.go (56%) rename internal/{aghnet => ipset}/ipset_linux.go (84%) rename internal/{aghnet/ipset_linux_test.go => ipset/ipset_linux_internal_test.go} (76%) rename internal/{aghnet => ipset}/ipset_others.go (62%) diff --git a/internal/dnsforward/ipset.go b/internal/dnsforward/ipset.go index 4330eb4b..cb6b1663 100644 --- a/internal/dnsforward/ipset.go +++ b/internal/dnsforward/ipset.go @@ -6,8 +6,8 @@ import ( "os" "strings" - "github.com/AdguardTeam/AdGuardHome/internal/aghnet" "github.com/AdguardTeam/AdGuardHome/internal/aghos" + "github.com/AdguardTeam/AdGuardHome/internal/ipset" "github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/log" "github.com/miekg/dns" @@ -15,14 +15,14 @@ import ( // ipsetCtx is the ipset context. ipsetMgr can be nil. type ipsetCtx struct { - ipsetMgr aghnet.IpsetManager + ipsetMgr ipset.Manager } // init initializes the ipset context. It is not safe for concurrent use. // // TODO(a.garipov): Rewrite into a simple constructor? func (c *ipsetCtx) init(ipsetConf []string) (err error) { - c.ipsetMgr, err = aghnet.NewIpsetManager(ipsetConf) + c.ipsetMgr, err = ipset.NewManager(ipsetConf) if errors.Is(err, os.ErrInvalid) || errors.Is(err, os.ErrPermission) { // ipset cannot currently be initialized if the server was installed // from Snap or when the user or the binary doesn't have the required diff --git a/internal/aghnet/ipset.go b/internal/ipset/ipset.go similarity index 56% rename from internal/aghnet/ipset.go rename to internal/ipset/ipset.go index 03e8a758..a81102a1 100644 --- a/internal/aghnet/ipset.go +++ b/internal/ipset/ipset.go @@ -1,20 +1,22 @@ -package aghnet +// Package ipset provides ipset functionality. +package ipset import ( "net" ) -// IpsetManager is the ipset manager interface. +// Manager is the ipset manager interface. // // TODO(a.garipov): Perhaps generalize this into some kind of a NetFilter type, // since ipset is exclusive to Linux? -type IpsetManager interface { +type Manager interface { Add(host string, ip4s, ip6s []net.IP) (n int, err error) Close() (err error) } -// NewIpsetManager returns a new ipset. IPv4 addresses are added to an ipset -// with an ipv4 family; IPv6 addresses, to an ipv6 ipset. ipset must exist. +// NewManager returns a new ipset manager. IPv4 addresses are added to an +// ipset with an ipv4 family; IPv6 addresses, to an ipv6 ipset. ipset must +// exist. // // The syntax of the ipsetConf is: // @@ -22,10 +24,10 @@ type IpsetManager interface { // // If ipsetConf is empty, msg and err are nil. The error is of type // *aghos.UnsupportedError if the OS is not supported. -func NewIpsetManager(ipsetConf []string) (mgr IpsetManager, err error) { +func NewManager(ipsetConf []string) (mgr Manager, err error) { if len(ipsetConf) == 0 { return nil, nil } - return newIpsetMgr(ipsetConf) + return newManager(ipsetConf) } diff --git a/internal/aghnet/ipset_linux.go b/internal/ipset/ipset_linux.go similarity index 84% rename from internal/aghnet/ipset_linux.go rename to internal/ipset/ipset_linux.go index bf4c8c86..84560897 100644 --- a/internal/aghnet/ipset_linux.go +++ b/internal/ipset/ipset_linux.go @@ -1,6 +1,6 @@ //go:build linux -package aghnet +package ipset import ( "fmt" @@ -31,9 +31,9 @@ import ( // 6. Run "sudo ipset list example_set". The Members field should contain the // resolved IP addresses. -// newIpsetMgr returns a new Linux ipset manager. -func newIpsetMgr(ipsetConf []string) (set IpsetManager, err error) { - return newIpsetMgrWithDialer(ipsetConf, defaultDial) +// newManager returns a new Linux ipset manager. +func newManager(ipsetConf []string) (set Manager, err error) { + return newManagerWithDialer(ipsetConf, defaultDial) } // defaultDial is the default netfilter dialing function. @@ -53,11 +53,11 @@ type ipsetConn interface { Header(name string) (p *ipset.HeaderPolicy, err error) } -// ipsetDialer creates an ipsetConn. -type ipsetDialer func(pf netfilter.ProtoFamily, conf *netlink.Config) (conn ipsetConn, err error) +// dialer creates an ipsetConn. +type dialer func(pf netfilter.ProtoFamily, conf *netlink.Config) (conn ipsetConn, err error) -// ipsetProps contains one Linux Netfilter ipset properties. -type ipsetProps struct { +// props contains one Linux Netfilter ipset properties. +type props struct { name string family netfilter.ProtoFamily } @@ -74,12 +74,12 @@ type ipInIpsetEntry struct { ipArr [net.IPv6len]byte } -// ipsetMgr is the Linux Netfilter ipset manager. -type ipsetMgr struct { - nameToIpset map[string]ipsetProps - domainToIpsets map[string][]ipsetProps +// manager is the Linux Netfilter ipset manager. +type manager struct { + nameToIpset map[string]props + domainToIpsets map[string][]props - dial ipsetDialer + dial dialer // mu protects all properties below. mu *sync.Mutex @@ -96,7 +96,7 @@ type ipsetMgr struct { } // dialNetfilter establishes connections to Linux's netfilter module. -func (m *ipsetMgr) 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 // github.com/digineo/go-ipset does. // @@ -145,7 +145,7 @@ func parseIpsetConfig(confStr string) (hosts, ipsetNames []string, err error) { } // ipsetProps returns the properties of an ipset with the given name. -func (m *ipsetMgr) ipsetProps(name string) (set ipsetProps, err error) { +func (m *manager) ipsetProps(name string) (set props, err error) { // The family doesn't seem to matter when we use a header query, so // query only the IPv4 one. // @@ -165,14 +165,14 @@ func (m *ipsetMgr) ipsetProps(name string) (set ipsetProps, err error) { return set, fmt.Errorf("unexpected ipset family %d", family) } - return ipsetProps{ + return props{ name: name, family: family, }, nil } // ipsets returns currently known ipsets. -func (m *ipsetMgr) ipsets(names []string) (sets []ipsetProps, err error) { +func (m *manager) ipsets(names []string) (sets []props, err error) { for _, name := range names { set, ok := m.nameToIpset[name] if ok { @@ -193,16 +193,16 @@ func (m *ipsetMgr) ipsets(names []string) (sets []ipsetProps, err error) { return sets, nil } -// newIpsetMgrWithDialer returns a new Linux ipset manager using the provided +// newManagerWithDialer returns a new Linux ipset manager using the provided // dialer. -func newIpsetMgrWithDialer(ipsetConf []string, dial ipsetDialer) (mgr IpsetManager, err error) { +func newManagerWithDialer(ipsetConf []string, dial dialer) (mgr Manager, err error) { defer func() { err = errors.Annotate(err, "ipset: %w") }() - m := &ipsetMgr{ + m := &manager{ mu: &sync.Mutex{}, - nameToIpset: make(map[string]ipsetProps), - domainToIpsets: make(map[string][]ipsetProps), + nameToIpset: make(map[string]props), + domainToIpsets: make(map[string][]props), dial: dial, @@ -229,7 +229,7 @@ func newIpsetMgrWithDialer(ipsetConf []string, dial ipsetDialer) (mgr IpsetManag return nil, fmt.Errorf("config line at idx %d: %w", i, err) } - var ipsets []ipsetProps + var ipsets []props ipsets, err = m.ipsets(ipsetNames) if err != nil { return nil, fmt.Errorf( @@ -249,7 +249,7 @@ func newIpsetMgrWithDialer(ipsetConf []string, dial ipsetDialer) (mgr IpsetManag // lookupHost find the ipsets for the host, taking subdomain wildcards into // account. -func (m *ipsetMgr) lookupHost(host string) (sets []ipsetProps) { +func (m *manager) lookupHost(host string) (sets []props) { // Search for matching ipset hosts starting with most specific domain. // We could use a trie here but the simple, inefficient solution isn't // that expensive: ~10 ns for TLD + SLD vs. ~140 ns for 10 subdomains on @@ -274,7 +274,7 @@ func (m *ipsetMgr) lookupHost(host string) (sets []ipsetProps) { // addIPs adds the IP addresses for the host to the ipset. set must be same // family as set's family. -func (m *ipsetMgr) addIPs(host string, set ipsetProps, ips []net.IP) (n int, err error) { +func (m *manager) addIPs(host string, set props, ips []net.IP) (n int, err error) { if len(ips) == 0 { return 0, nil } @@ -325,11 +325,11 @@ func (m *ipsetMgr) addIPs(host string, set ipsetProps, ips []net.IP) (n int, err } // addToSets adds the IP addresses to the corresponding ipset. -func (m *ipsetMgr) addToSets( +func (m *manager) addToSets( host string, ip4s []net.IP, ip6s []net.IP, - sets []ipsetProps, + sets []props, ) (n int, err error) { for _, set := range sets { var nn int @@ -356,8 +356,8 @@ func (m *ipsetMgr) addToSets( return n, nil } -// Add implements the IpsetManager interface for *ipsetMgr -func (m *ipsetMgr) Add(host string, ip4s, ip6s []net.IP) (n int, err error) { +// Add implements the [Manager] interface for *manager. +func (m *manager) Add(host string, ip4s, ip6s []net.IP) (n int, err error) { m.mu.Lock() defer m.mu.Unlock() @@ -371,8 +371,8 @@ func (m *ipsetMgr) Add(host string, ip4s, ip6s []net.IP) (n int, err error) { return m.addToSets(host, ip4s, ip6s, sets) } -// Close implements the IpsetManager interface for *ipsetMgr. -func (m *ipsetMgr) Close() (err error) { +// Close implements the [Manager] interface for *manager. +func (m *manager) Close() (err error) { m.mu.Lock() defer m.mu.Unlock() diff --git a/internal/aghnet/ipset_linux_test.go b/internal/ipset/ipset_linux_internal_test.go similarity index 76% rename from internal/aghnet/ipset_linux_test.go rename to internal/ipset/ipset_linux_internal_test.go index d220f87e..260c507e 100644 --- a/internal/aghnet/ipset_linux_test.go +++ b/internal/ipset/ipset_linux_internal_test.go @@ -1,6 +1,6 @@ //go:build linux -package aghnet +package ipset import ( "net" @@ -15,16 +15,16 @@ import ( "github.com/ti-mo/netfilter" ) -// fakeIpsetConn is a fake ipsetConn for tests. -type fakeIpsetConn struct { +// fakeConn is a fake ipsetConn for tests. +type fakeConn struct { ipv4Header *ipset.HeaderPolicy ipv4Entries *[]*ipset.Entry ipv6Header *ipset.HeaderPolicy ipv6Entries *[]*ipset.Entry } -// Add implements the ipsetConn interface for *fakeIpsetConn. -func (c *fakeIpsetConn) Add(name string, entries ...*ipset.Entry) (err error) { +// Add implements the [ipsetConn] interface for *fakeConn. +func (c *fakeConn) Add(name string, entries ...*ipset.Entry) (err error) { if strings.Contains(name, "ipv4") { *c.ipv4Entries = append(*c.ipv4Entries, entries...) @@ -38,13 +38,13 @@ func (c *fakeIpsetConn) Add(name string, entries ...*ipset.Entry) (err error) { return errors.Error("test: ipset not found") } -// Close implements the ipsetConn interface for *fakeIpsetConn. -func (c *fakeIpsetConn) Close() (err error) { +// Close implements the [ipsetConn] interface for *fakeConn. +func (c *fakeConn) Close() (err error) { return nil } -// Header implements the ipsetConn interface for *fakeIpsetConn. -func (c *fakeIpsetConn) Header(name string) (p *ipset.HeaderPolicy, err error) { +// Header implements the [ipsetConn] interface for *fakeConn. +func (c *fakeConn) Header(name string) (p *ipset.HeaderPolicy, err error) { if strings.Contains(name, "ipv4") { return c.ipv4Header, nil } else if strings.Contains(name, "ipv6") { @@ -54,7 +54,7 @@ func (c *fakeIpsetConn) Header(name string) (p *ipset.HeaderPolicy, err error) { return nil, errors.Error("test: ipset not found") } -func TestIpsetMgr_Add(t *testing.T) { +func TestManager_Add(t *testing.T) { ipsetConf := []string{ "example.com,example.net/ipv4set", "example.org,example.biz/ipv6set", @@ -67,7 +67,7 @@ func TestIpsetMgr_Add(t *testing.T) { pf netfilter.ProtoFamily, conf *netlink.Config, ) (conn ipsetConn, err error) { - return &fakeIpsetConn{ + return &fakeConn{ ipv4Header: &ipset.HeaderPolicy{ Family: ipset.NewUInt8Box(uint8(netfilter.ProtoIPv4)), }, @@ -79,7 +79,7 @@ func TestIpsetMgr_Add(t *testing.T) { }, nil } - m, err := newIpsetMgrWithDialer(ipsetConf, fakeDial) + m, err := newManagerWithDialer(ipsetConf, fakeDial) require.NoError(t, err) ip4 := net.IP{1, 2, 3, 4} @@ -114,21 +114,21 @@ func TestIpsetMgr_Add(t *testing.T) { assert.NoError(t, err) } -var ipsetPropsSink []ipsetProps +var ipsetPropsSink []props -func BenchmarkIpsetMgr_lookupHost(b *testing.B) { - propsLong := []ipsetProps{{ +func BenchmarkManager_LookupHost(b *testing.B) { + propsLong := []props{{ name: "example.com", family: netfilter.ProtoIPv4, }} - propsShort := []ipsetProps{{ + propsShort := []props{{ name: "example.net", family: netfilter.ProtoIPv4, }} - m := &ipsetMgr{ - domainToIpsets: map[string][]ipsetProps{ + m := &manager{ + domainToIpsets: map[string][]props{ "": propsLong, "example.net": propsShort, }, diff --git a/internal/aghnet/ipset_others.go b/internal/ipset/ipset_others.go similarity index 62% rename from internal/aghnet/ipset_others.go rename to internal/ipset/ipset_others.go index 8406e0e1..8b75912f 100644 --- a/internal/aghnet/ipset_others.go +++ b/internal/ipset/ipset_others.go @@ -1,11 +1,11 @@ //go:build !linux -package aghnet +package ipset import ( "github.com/AdguardTeam/AdGuardHome/internal/aghos" ) -func newIpsetMgr(_ []string) (mgr IpsetManager, err error) { +func newManager(_ []string) (mgr Manager, err error) { return nil, aghos.Unsupported("ipset") }