From 0929dfc8bffa02b3904d817dead1a62fcfa6103b Mon Sep 17 00:00:00 2001 From: Joe Williams Date: Sat, 29 Oct 2022 00:33:22 -0600 Subject: [PATCH] Support set element counters (#199) --- nftables_test.go | 43 +++++++++++++++++++++++++++++++++++++++++++ set.go | 13 +++++++++++++ 2 files changed, 56 insertions(+) diff --git a/nftables_test.go b/nftables_test.go index 1c82dff..23f24ba 100644 --- a/nftables_test.go +++ b/nftables_test.go @@ -2642,6 +2642,49 @@ func TestIP6SetAddElements(t *testing.T) { } } +func TestCreateUseCounterSet(t *testing.T) { + // Create a new network namespace to test these operations, + // and tear down the namespace at test completion. + c, newNS := openSystemNFTConn(t) + defer cleanupSystemNFTConn(t, newNS) + // Clear all rules at the beginning + end of the test. + c.FlushRuleset() + defer c.FlushRuleset() + + filter := c.AddTable(&nftables.Table{ + Family: nftables.TableFamilyIPv4, + Name: "filter", + }) + + portSet := &nftables.Set{ + Table: filter, + Name: "test", + KeyType: nftables.TypeInetService, + Counter: true, + } + if err := c.AddSet(portSet, nil); err != nil { + t.Errorf("c.AddSet(portSet) failed: %v", err) + } + if err := c.SetAddElements(portSet, []nftables.SetElement{{Key: binaryutil.BigEndian.PutUint16(22)}}); err != nil { + t.Errorf("c.SetVal(portSet) failed: %v", err) + } + + if err := c.Flush(); err != nil { + t.Errorf("c.Flush() failed: %v", err) + } + + sets, err := c.GetSets(filter) + if err != nil { + t.Errorf("c.GetSets() failed: %v", err) + } + if len(sets) != 1 { + t.Fatalf("len(sets) = %d, want 1", len(sets)) + } + if sets[0].Name != "test" { + t.Errorf("set[0].Name = %q, want kek", sets[0].Name) + } +} + func TestCreateDeleteNamedSet(t *testing.T) { // Create a new network namespace to test these operations, // and tear down the namespace at test completion. diff --git a/set.go b/set.go index 0240ed0..d9f9538 100644 --- a/set.go +++ b/set.go @@ -40,6 +40,8 @@ const ( NFTA_SET_DESC_CONCAT = 2 // https://git.netfilter.org/nftables/tree/include/linux/netfilter/nf_tables.h?id=d1289bff58e1878c3162f574c603da993e29b113#n428 NFTA_SET_ELEM_KEY_END = 10 + // https://git.netfilter.org/nftables/tree/include/linux/netfilter/nf_tables.h?id=d1289bff58e1878c3162f574c603da993e29b113#n429 + NFTA_SET_ELEM_EXPRESSIONS = 0x11 ) var allocSetID uint32 @@ -235,6 +237,7 @@ type Set struct { Interval bool IsMap bool HasTimeout bool + Counter bool // Can be updated per evaluation path, per `nft list ruleset` // indicates that set contains "flags dynamic" // https://git.netfilter.org/libnftnl/tree/include/linux/netfilter/nf_tables.h?id=84d12cfacf8ddd857a09435f3d982ab6250d250c#n298 @@ -548,6 +551,16 @@ func (cc *Conn) AddSet(s *Set, vals []SetElement) error { tableInfo = append(tableInfo, netlink.Attribute{Type: unix.NFTA_SET_USERDATA, Data: []byte("\x00\x04\x01\x00\x00\x00")}) } + if s.Counter { + data, err := netlink.MarshalAttributes([]netlink.Attribute{ + {Type: unix.NFTA_LIST_ELEM, Data: []byte("counter\x00")}, + {Type: unix.NFTA_SET_ELEM_PAD | unix.NFTA_SET_ELEM_DATA, Data: []byte{}}, + }) + if err != nil { + return err + } + tableInfo = append(tableInfo, netlink.Attribute{Type: unix.NLA_F_NESTED | NFTA_SET_ELEM_EXPRESSIONS, Data: data}) + } cc.messages = append(cc.messages, netlink.Message{ Header: netlink.Header{