Skip to content

Commit

Permalink
ipset: header data query
Browse files Browse the repository at this point in the history
  • Loading branch information
schzhn committed Nov 29, 2023
1 parent 849abaf commit abf8977
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 1 deletion.
42 changes: 41 additions & 1 deletion internal/ipset/ipset_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ func (qc *queryConn) listAll() (sets []props, err error) {
type ipsetConn interface {
Add(name string, entries ...*ipset.Entry) (err error)
Close() (err error)
Header(name string) (p *ipset.HeaderPolicy, err error)
listAll() (sets []props, err error)
}

Expand All @@ -112,6 +113,9 @@ type props struct {
// name of the ipset.
name string

// typeName of the ipset.
typeName string

// family of the IP addresses in the ipset.
family netfilter.ProtoFamily

Expand Down Expand Up @@ -148,6 +152,8 @@ func (p *props) parseAttribute(a netfilter.Attribute) {
case ipset.AttrSetName:
// Trim the null character.
p.name = string(bytes.Trim(a.Data, "\x00"))
case ipset.AttrTypeName:
p.typeName = string(bytes.Trim(a.Data, "\x00"))
case ipset.AttrFamily:
p.family = netfilter.ProtoFamily(a.Data[0])
default:
Expand Down Expand Up @@ -288,6 +294,35 @@ func (m *manager) parseIpsetConfig(ipsetConf []string) (err error) {
return nil
}

// ipsetProps returns the properties of an ipset with the given name.
//
// Additional header data query. See
// https://github.com/AdguardTeam/AdGuardHome/issues/6420.
func (m *manager) ipsetProps(p props) (err error) {
// The family doesn't seem to matter when we use a header query, so
// query only the IPv4 one.
//
// TODO(a.garipov): Find out if this is a bug or a feature.
var res *ipset.HeaderPolicy
res, err = m.ipv4Conn.Header(p.name)
if err != nil {
return err
}

if res == nil || res.Family == nil {
return errors.Error("empty response or no family data")
}

family := netfilter.ProtoFamily(res.Family.Value)
if family != netfilter.ProtoIPv4 && family != netfilter.ProtoIPv6 {
return fmt.Errorf("unexpected ipset family %q", family)
}

p.family = family

return nil
}

// ipsets returns currently known ipsets.
func (m *manager) ipsets(names []string) (sets []props, err error) {
for _, n := range names {
Expand All @@ -297,7 +332,12 @@ func (m *manager) ipsets(names []string) (sets []props, err error) {
}

if p.family != netfilter.ProtoIPv4 && p.family != netfilter.ProtoIPv6 {
return nil, fmt.Errorf("%q unexpected ipset family %q", p.name, p.family)
log.Debug("%q %q unexpected ipset family %q", p.name, p.typeName, p.family)

err = m.ipsetProps(p)
if err != nil {
return nil, fmt.Errorf("%q %q making header query: %w", p.name, p.typeName, err)
}
}

sets = append(sets, p)
Expand Down
5 changes: 5 additions & 0 deletions internal/ipset/ipset_linux_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ func (c *fakeConn) Close() (err error) {
return nil
}

// Header implements the [ipsetConn] interface for *fakeConn.
func (c *fakeConn) Header(_ string) (_ *ipset.HeaderPolicy, _ error) {
return nil, nil
}

// listAll implements the [ipsetConn] interface for *fakeConn.
func (c *fakeConn) listAll() (sets []props, err error) {
return c.sets, nil
Expand Down

0 comments on commit abf8977

Please sign in to comment.