From 2ed1f939b59591335447d8b445c9d3832c772f09 Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Mon, 27 Dec 2021 20:54:00 +0300 Subject: [PATCH] Pull request: aghnet: fix ipset init errors Updates #4027. Squashed commit of the following: commit 9ac0cc27ca94e630cc321c90b60b271499af4d9b Author: Ainar Garipov Date: Mon Dec 27 20:26:22 2021 +0300 aghnet: fix ipset init errors --- CHANGELOG.md | 2 ++ internal/aghnet/ipset.go | 7 ++++++- internal/aghnet/ipset_linux.go | 25 ++++++++++++++++++++----- internal/dnsforward/ipset.go | 15 +++++++-------- 4 files changed, 35 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4893f839..3c563ad2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ and this project adheres to ### Fixed +- `ipset` initialization bugs ([#4027]). - Legacy DNS rewrites from a wildcard pattern to a subdomain ([#4016]). - Service not being stopped before running the `uninstall` service action ([#3868]). @@ -46,6 +47,7 @@ and this project adheres to [#3987]: https://github.com/AdguardTeam/AdGuardHome/issues/3987 [#4008]: https://github.com/AdguardTeam/AdGuardHome/issues/4008 [#4016]: https://github.com/AdguardTeam/AdGuardHome/issues/4016 +[#4027]: https://github.com/AdguardTeam/AdGuardHome/issues/4027 diff --git a/internal/aghnet/ipset.go b/internal/aghnet/ipset.go index 422d4b4f..88a3f2b7 100644 --- a/internal/aghnet/ipset.go +++ b/internal/aghnet/ipset.go @@ -20,7 +20,12 @@ type IpsetManager interface { // // DOMAIN[,DOMAIN].../IPSET_NAME[,IPSET_NAME]... // -// The error is of type *aghos.UnsupportedError if the OS is not supported. +// 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) { + if len(ipsetConf) == 0 { + return nil, nil + } + return newIpsetMgr(ipsetConf) } diff --git a/internal/aghnet/ipset_linux.go b/internal/aghnet/ipset_linux.go index fa33d2a8..57248b41 100644 --- a/internal/aghnet/ipset_linux.go +++ b/internal/aghnet/ipset_linux.go @@ -14,6 +14,7 @@ import ( "github.com/digineo/go-ipset/v2" "github.com/mdlayher/netlink" "github.com/ti-mo/netfilter" + "golang.org/x/sys/unix" ) // How to test on a real Linux machine: @@ -42,11 +43,17 @@ import ( // newIpsetMgr returns a new Linux ipset manager. func newIpsetMgr(ipsetConf []string) (set IpsetManager, err error) { - dial := func(pf netfilter.ProtoFamily, conf *netlink.Config) (conn ipsetConn, err error) { - return ipset.Dial(pf, conf) + return newIpsetMgrWithDialer(ipsetConf, defaultDial) +} + +// defaultDial is the default netfilter dialing function. +func defaultDial(pf netfilter.ProtoFamily, conf *netlink.Config) (conn ipsetConn, err error) { + conn, err = ipset.Dial(pf, conf) + if err != nil { + return nil, err } - return newIpsetMgrWithDialer(ipsetConf, dial) + return conn, nil } // ipsetConn is the ipset conn interface. @@ -103,8 +110,8 @@ func (m *ipsetMgr) dialNetfilter(conf *netlink.Config) (err error) { // The kernel API does not actually require two sockets but package // github.com/digineo/go-ipset does. // - // TODO(a.garipov): Perhaps we can ditch package ipset altogether and - // just use packages netfilter and netlink. + // TODO(a.garipov): Perhaps we can ditch package ipset altogether and just + // use packages netfilter and netlink. m.ipv4Conn, err = m.dial(netfilter.ProtoIPv4, conf) if err != nil { return fmt.Errorf("dialing v4: %w", err) @@ -214,6 +221,14 @@ func newIpsetMgrWithDialer(ipsetConf []string, dial ipsetDialer) (mgr IpsetManag err = m.dialNetfilter(&netlink.Config{}) if err != nil { + if errors.Is(err, unix.EPROTONOSUPPORT) { + // The implementation doesn't support this protocol version. Just + // issue a warning. + log.Info("ipset: dialing netfilter: warning: %s", err) + + return nil, nil + } + return nil, fmt.Errorf("dialing netfilter: %w", err) } diff --git a/internal/dnsforward/ipset.go b/internal/dnsforward/ipset.go index 78c2cd6e..1aca3077 100644 --- a/internal/dnsforward/ipset.go +++ b/internal/dnsforward/ipset.go @@ -24,20 +24,19 @@ type ipsetCtx struct { func (c *ipsetCtx) init(ipsetConf []string) (err error) { c.ipsetMgr, err = aghnet.NewIpsetManager(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 permissions, or when the kernel doesn't - // support netfilter. + // ipset cannot currently be initialized if the server was installed + // from Snap or when the user or the binary doesn't have the required + // permissions, or when the kernel doesn't support netfilter. // // Log and go on. // - // TODO(a.garipov): The Snap problem can probably be solved if - // we add the netlink-connector interface plug. - log.Info("warning: cannot initialize ipset: %s", err) + // TODO(a.garipov): The Snap problem can probably be solved if we add + // the netlink-connector interface plug. + log.Info("ipset: warning: cannot initialize: %s", err) return nil } else if unsupErr := (&aghos.UnsupportedError{}); errors.As(err, &unsupErr) { - log.Info("warning: %s", err) + log.Info("ipset: warning: %s", err) return nil } else if err != nil {