Pull request: aghnet: fix ipset init errors

Updates #4027.

Squashed commit of the following:

commit 9ac0cc27ca94e630cc321c90b60b271499af4d9b
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Mon Dec 27 20:26:22 2021 +0300

    aghnet: fix ipset init errors
This commit is contained in:
Ainar Garipov 2021-12-27 20:54:00 +03:00
parent dea8a585f8
commit 2ed1f939b5
4 changed files with 35 additions and 14 deletions

View File

@ -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

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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 {