From 0550966fc728a7ed7dbb5de1313949c9946d97d4 Mon Sep 17 00:00:00 2001 From: Florian Lehner Date: Sat, 6 Jan 2024 10:10:16 +0100 Subject: [PATCH] Add NByte ematch Signed-off-by: Florian Lehner --- ematch.go | 8 +++++++ ematch_nbyte.go | 51 ++++++++++++++++++++++++++++++++++++++++++++ ematch_nbyte_test.go | 46 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 105 insertions(+) create mode 100644 ematch_nbyte.go create mode 100644 ematch_nbyte_test.go diff --git a/ematch.go b/ematch.go index b5565a4..1d78a23 100644 --- a/ematch.go +++ b/ematch.go @@ -130,6 +130,7 @@ type EmatchMatch struct { IPSetMatch *IPSetMatch IptMatch *IptMatch ContainerMatch *ContainerMatch + NByteMatch *NByteMatch } // unmarshalEmatch parses the Ematch-encoded data and stores the result in the value pointed to by info. @@ -221,6 +222,11 @@ func unmarshalEmatchTreeList(data []byte, info *[]EmatchMatch) error { err := unmarshalContainerMatch(tmp[8:], expr) multiError = concatError(multiError, err) match.ContainerMatch = expr + case EmatchNByte: + expr := &NByteMatch{} + err := unmarshalNByteMatch(tmp[8:], expr) + multiError = concatError(multiError, err) + match.NByteMatch = expr default: return fmt.Errorf("unmarshalEmatchTreeList() kind %d is not yet implemented", match.Hdr.Kind) } @@ -249,6 +255,8 @@ func marshalEmatchTreeList(info *[]EmatchMatch) ([]byte, error) { expr, err = marshalIptMatch(m.IptMatch) case EmatchContainer: expr, err = marshalContainerMatch(m.ContainerMatch) + case EmatchNByte: + expr, err = marshalNByteMatch(m.NByteMatch) default: return []byte{}, fmt.Errorf("marshalEmatchTreeList() kind %d is not yet implemented", m.Hdr.Kind) } diff --git a/ematch_nbyte.go b/ematch_nbyte.go new file mode 100644 index 0000000..4f06df4 --- /dev/null +++ b/ematch_nbyte.go @@ -0,0 +1,51 @@ +package tc + +import ( + "fmt" +) + +type NByteMatch struct { + Offset uint16 + Layer uint8 + Needle []byte +} + +type tcfEmNByte struct { + off uint16 + len uint16 + layer uint8 +} + +func unmarshalNByteMatch(data []byte, info *NByteMatch) error { + if len(data) < 8 { + return fmt.Errorf("unmarshalNByteMatch: incomplete data") + } + + nbyte := tcfEmNByte{} + if err := unmarshalStruct(data[:5], nbyte); err != nil { + return err + } + info.Offset = nbyte.off + info.Layer = nbyte.layer + info.Needle = data[8:] + + return nil +} + +func marshalNByteMatch(info *NByteMatch) ([]byte, error) { + if info == nil { + return []byte{}, fmt.Errorf("marshalNByteMatch: %w", ErrNoArg) + } + nbyte := tcfEmNByte{ + off: info.Offset, + len: uint16(len(info.Needle)), + layer: info.Layer, + } + + tmp, err := marshalAndAlignStruct(nbyte) + if err != nil { + return []byte{}, err + } + tmp = append(tmp, info.Needle...) + return tmp, nil +} diff --git a/ematch_nbyte_test.go b/ematch_nbyte_test.go new file mode 100644 index 0000000..a247b41 --- /dev/null +++ b/ematch_nbyte_test.go @@ -0,0 +1,46 @@ +package tc + +import ( + "errors" + "testing" + + "github.com/google/go-cmp/cmp" +) + +func TestNByteMatch(t *testing.T) { + t.Skip() + tests := map[string]struct { + val NByteMatch + err1 error + err2 error + }{ + "simple": { + val: NByteMatch{Needle: []byte("helloWorld"), + Offset: 42, + Layer: 7}, + }, + } + + for name, testcase := range tests { + t.Run(name, func(t *testing.T) { + data, err1 := marshalNByteMatch(&testcase.val) + if !errors.Is(err1, testcase.err1) { + t.Fatalf("Unexpected error: %v", err1) + } + val := NByteMatch{} + err2 := unmarshalNByteMatch(data, &val) + if !errors.Is(err2, testcase.err2) { + t.Fatalf("Unexpected error: %v", err2) + } + if diff := cmp.Diff(val, testcase.val); diff != "" { + t.Fatalf("NByteMatch missmatch (want +got):\n%s", diff) + } + }) + } + t.Run("nil", func(t *testing.T) { + _, err := marshalNByteMatch(nil) + if !errors.Is(err, ErrNoArg) { + t.Fatalf("unexpected error: %v", err) + } + }) +}