diff --git a/nftables_test.go b/nftables_test.go index b6d0f1c..25c8148 100644 --- a/nftables_test.go +++ b/nftables_test.go @@ -3818,7 +3818,7 @@ func TestDeleteElementNamedSet(t *testing.T) { Name: "test", KeyType: nftables.TypeInetService, } - if err := c.AddSet(portSet, []nftables.SetElement{{Key: []byte{0, 22}}, {Key: []byte{0, 23}}}); err != nil { + if err := c.AddSet(portSet, []nftables.SetElement{{Key: []byte{0, 22}}, {Key: []byte{0, 23}}, {Key: []byte{0, 24}}}); err != nil { t.Errorf("c.AddSet(portSet) failed: %v", err) } if err := c.Flush(); err != nil { @@ -3835,6 +3835,22 @@ func TestDeleteElementNamedSet(t *testing.T) { if err != nil { t.Errorf("c.GetSets() failed: %v", err) } + if len(elems) != 2 { + t.Fatalf("len(elems) = %d, want 2", len(elems)) + } + + c.SetDestroyElements(portSet, []nftables.SetElement{{Key: []byte{0, 24}}}) + c.SetDestroyElements(portSet, []nftables.SetElement{{Key: []byte{0, 24}}}) + c.SetDestroyElements(portSet, []nftables.SetElement{{Key: []byte{0, 99}}}) + + if err := c.Flush(); err != nil { + t.Errorf("Third c.Flush() failed: %v", err) + } + + elems, err = c.GetSetElements(portSet) + if err != nil { + t.Errorf("c.GetSets() failed: %v", err) + } if len(elems) != 1 { t.Fatalf("len(elems) = %d, want 1", len(elems)) } diff --git a/set.go b/set.go index e320117..dc97c4e 100644 --- a/set.go +++ b/set.go @@ -44,6 +44,9 @@ const ( 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 + // FIXME: in sys@v0.34.0 no unix.NFT_MSG_DESTROYSETELEM const yet. + // See nf_tables_msg_types enum in https://git.netfilter.org/nftables/tree/include/linux/netfilter/nf_tables.h + NFT_MSG_DESTROYSETELEM = 0x1e ) // SetDatatype represents a datatype declared by nft. @@ -391,6 +394,16 @@ func (cc *Conn) SetDeleteElements(s *Set, vals []SetElement) error { return cc.appendElemList(s, vals, unix.NFT_MSG_DELSETELEM) } +// SetDestroyElements like SetDeleteElements, but not an error if setelement doesn't exists +func (cc *Conn) SetDestroyElements(s *Set, vals []SetElement) error { + cc.mu.Lock() + defer cc.mu.Unlock() + if s.Anonymous { + return errors.New("anonymous sets cannot be updated") + } + return cc.appendElemList(s, vals, NFT_MSG_DESTROYSETELEM) +} + // maxElemBatchSize is the maximum size in bytes of encoded set elements which // are sent in one netlink message. The size field of a netlink attribute is a // uint16, and 1024 bytes is more than enough for the per-message headers. @@ -826,8 +839,9 @@ func parseSetDatatype(magic uint32) (SetDatatype, error) { } const ( - newElemHeaderType = netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_NEWSETELEM) - delElemHeaderType = netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_DELSETELEM) + newElemHeaderType = netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_NEWSETELEM) + delElemHeaderType = netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_DELSETELEM) + destroyElemHeaderType = netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | NFT_MSG_DESTROYSETELEM) ) func elementsFromMsg(fam byte, msg netlink.Message) ([]SetElement, error) {