From 5a47357ea5bf1a5d7c73fb8a7e6b2c041867dfa5 Mon Sep 17 00:00:00 2001 From: Moshe Litvin Date: Tue, 1 Jun 2021 17:49:27 +0300 Subject: [PATCH] Added Other expression type to support types that are not explicitly supported. This replaces the previous behaviour of silently ignoring unkown types when decoding --- expr/other.go | 50 ++++++++++++++++++++++++++++++++++++++++++ expr/other_test.go | 54 ++++++++++++++++++++++++++++++++++++++++++++++ rule.go | 7 ++---- 3 files changed, 106 insertions(+), 5 deletions(-) create mode 100644 expr/other.go create mode 100644 expr/other_test.go diff --git a/expr/other.go b/expr/other.go new file mode 100644 index 0000000..87aec6a --- /dev/null +++ b/expr/other.go @@ -0,0 +1,50 @@ +package expr + +import ( + "encoding/binary" + + "github.com/mdlayher/netlink" + "golang.org/x/sys/unix" +) + +// Other is a nft expression that this library don't know +// It can unmarshal/marshal it as list of attributes +type Other struct { + Type string // the type (name) of the expression + Attributes []OtherAttribute +} + +// OtherAttribute is one of the attributes in an Other +type OtherAttribute struct { + Type uint16 + Data []byte +} + +func (e *Other) marshal() ([]byte, error) { + attrs := make([]netlink.Attribute, len(e.Attributes)) + for i, a := range e.Attributes { + attrs[i].Type = a.Type + attrs[i].Data = a.Data + } + + data, err := netlink.MarshalAttributes(attrs) + if err != nil { + return nil, err + } + return netlink.MarshalAttributes([]netlink.Attribute{ + {Type: unix.NFTA_EXPR_NAME, Data: []byte(e.Type + "\x00")}, + {Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data}, + }) +} + +func (e *Other) unmarshal(data []byte) error { + ad, err := netlink.NewAttributeDecoder(data) + if err != nil { + return err + } + ad.ByteOrder = binary.BigEndian + for ad.Next() { + e.Attributes = append(e.Attributes, OtherAttribute{Type: ad.Type(), Data: ad.Bytes()}) + } + return ad.Err() +} diff --git a/expr/other_test.go b/expr/other_test.go new file mode 100644 index 0000000..0e94a56 --- /dev/null +++ b/expr/other_test.go @@ -0,0 +1,54 @@ +package expr + +import ( + "encoding/binary" + "reflect" + "testing" + + "github.com/mdlayher/netlink" + "golang.org/x/sys/unix" +) + +func TestOther(t *testing.T) { + orig := &Other{ + Type: "testing", + Attributes: []OtherAttribute{ + {1, []byte{66, 5}}, + {5, []byte("test")}, + }, + } + + data, err := Marshal(orig) + if err != nil { + t.Fatal("Error marshalling other: ", err) + } + + ad, err := netlink.NewAttributeDecoder(data) + if err != nil { + t.Fatalf("NewAttributeDecoder() error: %+v", err) + } + ad.ByteOrder = binary.BigEndian + if !ad.Next() { + t.Fatal("too short") + } + if ad.Type() != unix.NFTA_EXPR_NAME || ad.String() != orig.Type { + t.Fatalf("wrong name %d:%q", ad.Type(), ad.String()) + } + + if !ad.Next() { + t.Fatal("too short") + } + decoded := &Other{Type: "testing"} + if ad.Type() != unix.NFTA_EXPR_DATA { + t.Fatal("Wrong type for data:", ad.Type()) + } + if err := Unmarshal(ad.Bytes(), decoded); err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(orig, decoded) { + t.Errorf("Wrong structure decoded: %+v vs %+v", decoded, orig) + } + if ad.Next() { + t.Error("Got extra attribute: ", ad.Type()) + } +} diff --git a/rule.go b/rule.go index ec4ce1f..e270def 100644 --- a/rule.go +++ b/rule.go @@ -248,11 +248,8 @@ func exprsFromMsg(b []byte) ([]expr.Any, error) { e = &expr.Limit{} case "dynset": e = &expr.Dynset{} - } - if e == nil { - // TODO: introduce an opaque expression type so that users know - // something is here. - continue // unsupported expression type + default: + e = &expr.Other{Type: name} } ad.Do(func(b []byte) error {