Compare commits

...

4 Commits

Author SHA1 Message Date
Aleksei Ilin 96866fc962
Merge 9a398ccf70 into 85aee131ff 2025-01-14 23:39:21 +01:00
dependabot[bot] 85aee131ff
Bump golang.org/x/net from 0.23.0 to 0.33.0 in the go_modules group (#295)
Bumps the go_modules group with 1 update: [golang.org/x/net](https://github.com/golang/net).


Updates `golang.org/x/net` from 0.23.0 to 0.33.0
- [Commits](https://github.com/golang/net/compare/v0.23.0...v0.33.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: indirect
  dependency-group: go_modules
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-14 09:46:28 +01:00
Aleksei Ilin 9a398ccf70
set: Add set support for size specifier
Handle attribute NFTNL_SET_DESC_SIZE, as done in libnftnl:
https://git.netfilter.org/libnftnl/tree/src/set.c#n424

Example:
nft add set ip filter myset { type ipv4_addr\; size 65535\; flags dynamic\; }
2025-01-11 21:55:03 +01:00
Aleksei Ilin 8c0e43d650
set: Fix missing 'Dynamic' field restore in set unmarshal 2025-01-11 21:53:06 +01:00
4 changed files with 128 additions and 8 deletions

4
go.mod
View File

@ -5,12 +5,12 @@ go 1.21
require (
github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42
github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc
golang.org/x/sys v0.18.0
golang.org/x/sys v0.28.0
)
require (
github.com/google/go-cmp v0.6.0 // indirect
github.com/mdlayher/socket v0.5.0 // indirect
golang.org/x/net v0.23.0 // indirect
golang.org/x/net v0.33.0 // indirect
golang.org/x/sync v0.6.0 // indirect
)

8
go.sum
View File

@ -6,9 +6,9 @@ github.com/mdlayher/socket v0.5.0 h1:ilICZmJcQz70vrWVes1MFera4jGiWNocSkykwwoy3XI
github.com/mdlayher/socket v0.5.0/go.mod h1:WkcBFfvyG8QENs5+hfQPl1X6Jpd2yeLIYgrGFmJiJxI=
github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc h1:R83G5ikgLMxrBvLh22JhdfI8K6YXEPHx5P03Uu3DRs4=
github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI=
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=

41
set.go
View File

@ -267,6 +267,8 @@ type Set struct {
// https://git.netfilter.org/nftables/tree/include/datatype.h?id=d486c9e626405e829221b82d7355558005b26d8a#n109
KeyByteOrder binaryutil.ByteOrder
Comment string
// Indicates that the set has "size" specifier
Size uint32
}
// SetElement represents a data point within a set.
@ -553,6 +555,21 @@ func (cc *Conn) AddSet(s *Set, vals []SetElement) error {
}
tableInfo = append(tableInfo, netlink.Attribute{Type: unix.NLA_F_NESTED | unix.NFTA_SET_DESC, Data: numberOfElements})
}
var descBytes []byte
if s.Size > 0 {
// Marshal set size description
descSizeBytes, err := netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_SET_DESC_SIZE, Data: binaryutil.BigEndian.PutUint32(s.Size)},
})
if err != nil {
return fmt.Errorf("fail to marshal set size description: %w", err)
}
descBytes = append(descBytes, descSizeBytes...)
}
if s.Concatenation {
// Length of concatenated types is a must, otherwise segfaults when executing nft list ruleset
var concatDefinition []byte
@ -579,8 +596,13 @@ func (cc *Conn) AddSet(s *Set, vals []SetElement) error {
if err != nil {
return fmt.Errorf("fail to marshal concat definition %v", err)
}
// Marshal concat size description as set description
tableInfo = append(tableInfo, netlink.Attribute{Type: unix.NLA_F_NESTED | unix.NFTA_SET_DESC, Data: concatBytes})
descBytes = append(descBytes, concatBytes...)
}
if len(descBytes) > 0 {
// Marshal set description
tableInfo = append(tableInfo, netlink.Attribute{Type: unix.NLA_F_NESTED | unix.NFTA_SET_DESC, Data: descBytes})
}
// https://git.netfilter.org/libnftnl/tree/include/udata.h#n17
@ -734,6 +756,7 @@ func setsFromMsg(msg netlink.Message) (*Set, error) {
set.Interval = (flags & unix.NFT_SET_INTERVAL) != 0
set.IsMap = (flags & unix.NFT_SET_MAP) != 0
set.HasTimeout = (flags & unix.NFT_SET_TIMEOUT) != 0
set.Dynamic = (flags & unix.NFT_SET_EVAL) != 0
set.Concatenation = (flags & NFT_SET_CONCAT) != 0
case unix.NFTA_SET_KEY_TYPE:
nftMagic := ad.Uint32()
@ -762,6 +785,20 @@ func setsFromMsg(msg netlink.Message) (*Set, error) {
data := ad.Bytes()
value, ok := userdata.GetUint32(data, userdata.NFTNL_UDATA_SET_MERGE_ELEMENTS)
set.AutoMerge = ok && value == 1
case unix.NFTA_SET_DESC:
nestedAD, err := netlink.NewAttributeDecoder(ad.Bytes())
if err != nil {
return nil, fmt.Errorf("nested NewAttributeDecoder() failed: %w", err)
}
for nestedAD.Next() {
switch nestedAD.Type() {
case unix.NFTA_SET_DESC_SIZE:
set.Size = binary.BigEndian.Uint32(nestedAD.Bytes())
}
}
if nestedAD.Err() != nil {
return nil, fmt.Errorf("decoding set description: %w", nestedAD.Err())
}
}
}
return &set, nil

View File

@ -1,7 +1,11 @@
package nftables
import (
"reflect"
"testing"
"time"
"github.com/mdlayher/netlink"
)
// unknownNFTMagic is an nftMagic value that's unhandled by this
@ -185,3 +189,82 @@ func TestConcatSetTypeElements(t *testing.T) {
})
}
}
func TestMarshalSet(t *testing.T) {
t.Parallel()
tbl := &Table{
Name: "ipv4table",
Family: TableFamilyIPv4,
}
c, err := New(WithTestDial(
func(req []netlink.Message) ([]netlink.Message, error) {
return req, nil
}))
if err != nil {
t.Fatal(err)
}
c.AddTable(tbl)
// Ensure the table is added.
const connMsgStart = 1
if len(c.messages) != connMsgStart {
t.Fatalf("AddSet() wrong start message count: %d, expected: %d", len(c.messages), connMsgStart)
}
tests := []struct {
name string
set Set
}{
{
name: "Set without flags",
set: Set{
Name: "test-set",
ID: uint32(1),
Table: tbl,
KeyType: TypeIPAddr,
},
},
{
name: "Set with size, timeout, dynamic flag specified",
set: Set{
Name: "test-set",
ID: uint32(2),
HasTimeout: true,
Dynamic: true,
Size: 10,
Table: tbl,
KeyType: TypeIPAddr,
Timeout: time.Duration(30) * time.Second,
},
},
}
for i, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := c.AddSet(&tt.set, nil); err != nil {
t.Fatal(err)
}
connMsgSetIdx := connMsgStart + i
if len(c.messages) != connMsgSetIdx+1 {
t.Fatalf("AddSet() wrong message count: %d, expected: %d", len(c.messages), connMsgSetIdx+1)
}
msg := c.messages[connMsgSetIdx]
nset, err := setsFromMsg(msg)
if err != nil {
t.Fatalf("setsFromMsg() error: %+v", err)
}
// Table pointer is set after flush, which is not implemented in the test.
tt.set.Table = nil
if !reflect.DeepEqual(&tt.set, nset) {
t.Fatalf("original %+v and recovered %+v Set structs are different", tt.set, nset)
}
})
}
}