ipset: imp docs
This commit is contained in:
parent
544982b5d7
commit
4ef03c9e00
|
@ -14,7 +14,6 @@ import (
|
|||
"github.com/digineo/go-ipset/v2"
|
||||
"github.com/mdlayher/netlink"
|
||||
"github.com/ti-mo/netfilter"
|
||||
"golang.org/x/exp/slices"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
|
@ -48,14 +47,19 @@ func defaultDial(pf netfilter.ProtoFamily, conf *netlink.Config) (conn ipsetConn
|
|||
return &queryConn{c}, nil
|
||||
}
|
||||
|
||||
// queryConn is the [ipsetConn] implementation.
|
||||
type queryConn struct {
|
||||
*ipset.Conn
|
||||
}
|
||||
|
||||
func (qc *queryConn) ListAll() (sets []props, err error) {
|
||||
// type check
|
||||
var _ ipsetConn = (*queryConn)(nil)
|
||||
|
||||
// queryConn returns the list of all ipsets.
|
||||
func (qc *queryConn) listAll() (sets []props, err error) {
|
||||
msg, err := netfilter.MarshalNetlink(
|
||||
netfilter.Header{
|
||||
Family: netfilter.ProtoIPv4,
|
||||
Family: qc.Conn.Family,
|
||||
SubsystemID: netfilter.NFSubsysIPSet,
|
||||
MessageType: netfilter.MessageType(ipset.CmdList),
|
||||
Flags: netlink.Request | netlink.Dump,
|
||||
|
@ -66,19 +70,19 @@ func (qc *queryConn) ListAll() (sets []props, err error) {
|
|||
}},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("marshaling netlink msg: %w", err)
|
||||
}
|
||||
|
||||
ms, err := qc.Conn.Conn.Query(msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("querying netlink msg: %w", err)
|
||||
}
|
||||
|
||||
for _, s := range ms {
|
||||
p := props{}
|
||||
err = p.unmarshalMessage(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("unmarshaling netlink msg: %w", err)
|
||||
}
|
||||
|
||||
sets = append(sets, p)
|
||||
|
@ -91,7 +95,7 @@ func (qc *queryConn) ListAll() (sets []props, err error) {
|
|||
type ipsetConn interface {
|
||||
Add(name string, entries ...*ipset.Entry) (err error)
|
||||
Close() (err error)
|
||||
ListAll() (sets []props, err error)
|
||||
listAll() (sets []props, err error)
|
||||
}
|
||||
|
||||
// dialer creates an ipsetConn.
|
||||
|
@ -104,9 +108,12 @@ type props struct {
|
|||
temp bool
|
||||
}
|
||||
|
||||
// unmarshalMessage unmarshals netlink message and sets the properties of the
|
||||
// ipset.
|
||||
func (p *props) unmarshalMessage(msg netlink.Message) (err error) {
|
||||
_, attrs, err := netfilter.UnmarshalNetlink(msg)
|
||||
if err != nil {
|
||||
// Don't wrap the error since it's informative enough as is.
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -117,6 +124,8 @@ func (p *props) unmarshalMessage(msg netlink.Message) (err error) {
|
|||
return nil
|
||||
}
|
||||
|
||||
// parseAttribute parses netfilter attribute and sets the name and family of
|
||||
// the ipset.
|
||||
func (p *props) parseAttribute(a netfilter.Attribute) {
|
||||
switch ipset.AttributeType(a.Type) {
|
||||
case ipset.AttrData:
|
||||
|
@ -130,6 +139,7 @@ func (p *props) parseAttribute(a netfilter.Attribute) {
|
|||
}
|
||||
}
|
||||
|
||||
// parseAttrData parses attribute data and sets the timeout of the ipset.
|
||||
func (p *props) parseAttrData(a netfilter.Attribute) {
|
||||
for _, a := range a.Children {
|
||||
switch ipset.AttributeType(a.Type) {
|
||||
|
@ -195,8 +205,8 @@ func (m *manager) dialNetfilter(conf *netlink.Config) (err error) {
|
|||
return nil
|
||||
}
|
||||
|
||||
// parseIpsetConfig parses one ipset configuration string.
|
||||
func parseIpsetConfig(confStr string) (hosts, ipsetNames []string, err error) {
|
||||
// parseIpsetConfigLine parses one ipset configuration line.
|
||||
func parseIpsetConfigLine(confStr string) (hosts, ipsetNames []string, err error) {
|
||||
confStr = strings.TrimSpace(confStr)
|
||||
hostsAndNames := strings.Split(confStr, "/")
|
||||
if len(hostsAndNames) != 2 {
|
||||
|
@ -224,22 +234,53 @@ func parseIpsetConfig(confStr string) (hosts, ipsetNames []string, err error) {
|
|||
return hosts, ipsetNames, nil
|
||||
}
|
||||
|
||||
// ipsets returns currently known ipsets.
|
||||
func (m *manager) ipsets(names []string) (sets []props, err error) {
|
||||
// The family doesn't seem to matter when we use a header query, so
|
||||
// query only the IPv4 one.
|
||||
// parseIpsetConfig parses the ipset configuration and stores ipsets. It
|
||||
// returns an error if the configuration can't be used.
|
||||
func (m *manager) parseIpsetConfig(ipsetConf []string) (err error) {
|
||||
// The family doesn't seem to matter when we use a list query, so query
|
||||
// only the IPv4 one.
|
||||
//
|
||||
// TODO(a.garipov): Find out if this is a bug or a feature.
|
||||
all, err := m.ipv4Conn.ListAll()
|
||||
all, err := m.ipv4Conn.listAll()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
// Don't wrap the error since it's informative enough as is.
|
||||
return err
|
||||
}
|
||||
|
||||
for _, p := range all {
|
||||
if slices.Contains(names, p.name) {
|
||||
m.nameToIpset[p.name] = p
|
||||
sets = append(sets, p)
|
||||
m.nameToIpset[p.name] = p
|
||||
}
|
||||
|
||||
for i, confStr := range ipsetConf {
|
||||
var hosts, ipsetNames []string
|
||||
hosts, ipsetNames, err = parseIpsetConfigLine(confStr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("config line at idx %d: %w", i, err)
|
||||
}
|
||||
|
||||
var ipsets []props
|
||||
ipsets, err = m.ipsets(ipsetNames)
|
||||
if err != nil {
|
||||
return fmt.Errorf("getting ipsets from config line at idx %d: %w", i, err)
|
||||
}
|
||||
|
||||
for _, host := range hosts {
|
||||
m.domainToIpsets[host] = append(m.domainToIpsets[host], ipsets...)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ipsets returns currently known ipsets.
|
||||
func (m *manager) ipsets(names []string) (sets []props, err error) {
|
||||
for _, n := range names {
|
||||
p, ok := m.nameToIpset[n]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unknown ipset %q", n)
|
||||
}
|
||||
|
||||
sets = append(sets, p)
|
||||
}
|
||||
|
||||
return sets, nil
|
||||
|
@ -274,26 +315,9 @@ func newManagerWithDialer(ipsetConf []string, dial dialer) (mgr Manager, err err
|
|||
return nil, fmt.Errorf("dialing netfilter: %w", err)
|
||||
}
|
||||
|
||||
for i, confStr := range ipsetConf {
|
||||
var hosts, ipsetNames []string
|
||||
hosts, ipsetNames, err = parseIpsetConfig(confStr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("config line at idx %d: %w", i, err)
|
||||
}
|
||||
|
||||
var ipsets []props
|
||||
ipsets, err = m.ipsets(ipsetNames)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
"getting ipsets from config line at idx %d: %w",
|
||||
i,
|
||||
err,
|
||||
)
|
||||
}
|
||||
|
||||
for _, host := range hosts {
|
||||
m.domainToIpsets[host] = append(m.domainToIpsets[host], ipsets...)
|
||||
}
|
||||
err = m.parseIpsetConfig(ipsetConf)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("getting ipsets: %w", err)
|
||||
}
|
||||
|
||||
return m, nil
|
||||
|
|
|
@ -24,6 +24,9 @@ type fakeConn struct {
|
|||
sets []props
|
||||
}
|
||||
|
||||
// type check
|
||||
var _ ipsetConn = (*fakeConn)(nil)
|
||||
|
||||
// Add implements the [ipsetConn] interface for *fakeConn.
|
||||
func (c *fakeConn) Add(name string, entries ...*ipset.Entry) (err error) {
|
||||
if strings.Contains(name, "ipv4") {
|
||||
|
@ -44,8 +47,8 @@ func (c *fakeConn) Close() (err error) {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ListAll implements the [ipsetConn] interface for *fakeConn.
|
||||
func (c *fakeConn) ListAll() (sets []props, err error) {
|
||||
// listAll implements the [ipsetConn] interface for *fakeConn.
|
||||
func (c *fakeConn) listAll() (sets []props, err error) {
|
||||
return c.sets, nil
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue