From c123f7dc7d72df209de158c07a7acf61c2cf8674 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Sat, 20 Jul 2019 18:34:59 +0200 Subject: [PATCH] nftables_test: add test for issue #26 --- nftables_test.go | 129 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) diff --git a/nftables_test.go b/nftables_test.go index a327225..b71a1c6 100644 --- a/nftables_test.go +++ b/nftables_test.go @@ -2281,3 +2281,132 @@ func TestConfigureRangeIPv6(t *testing.T) { t.Fatal(err) } } + +func TestSet4(t *testing.T) { + // The want byte sequences come from stracing nft(8), e.g.: + // strace-4.21 -f -v -x -s 2048 -etrace=sendto nft add table ip nat + // + // Until https://github.com/strace/strace/issues/100 is resolved, + // you need to use strace 4.21 or apply the patch in the issue. + // + // Additional details can be obtained by specifying the --debug=all option + // when calling nft(8). + want := [][]byte{ + + // batch begin + []byte("\x00\x00\x00\x0a"), + + // table ip ipv4table { + // set test-set { + // type inet_service + // flags constant + // elements = { 12000, 12001, 12345, 12346 } + // } + // + // chain ipv4chain-2 { + // type nat hook prerouting priority dstnat; policy accept; + // tcp dport @test-set + // } + // } + + []byte("\x02\x00\x00\x00\x0e\x00\x01\x00\x69\x70\x76\x34\x74\x61\x62\x6c\x65\x00\x00\x00\x08\x00\x02\x00\x00\x00\x00\x00"), + + []byte("\x02\x00\x00\x00\x0e\x00\x01\x00\x69\x70\x76\x34\x74\x61\x62\x6c\x65\x00\x00\x00\x10\x00\x03\x00\x69\x70\x76\x34\x63\x68\x61\x69\x6e\x2d\x32\x00\x14\x00\x04\x80\x08\x00\x01\x00\x00\x00\x00\x00\x08\x00\x02\x00\xff\xff\xff\x9c\x08\x00\x05\x00\x00\x00\x00\x01\x08\x00\x07\x00\x6e\x61\x74\x00"), + + []byte("\x02\x00\x00\x00\x0e\x00\x01\x00\x69\x70\x76\x34\x74\x61\x62\x6c\x65\x00\x00\x00\x0d\x00\x02\x00\x74\x65\x73\x74\x2d\x73\x65\x74\x00\x00\x00\x00\x08\x00\x03\x00\x00\x00\x00\x02\x08\x00\x04\x00\x00\x00\x00\x0d\x08\x00\x05\x00\x00\x00\x00\x02\x08\x00\x0a\x00\x00\x00\x00\x01\x0c\x00\x09\x80\x08\x00\x01\x00\x00\x00\x00\x04\x0a\x00\x0d\x00\x00\x04\x02\x00\x00\x00\x00\x00"), + + []byte("\x02\x00\x00\x00\x0d\x00\x02\x00\x74\x65\x73\x74\x2d\x73\x65\x74\x00\x00\x00\x00\x08\x00\x04\x00\x00\x00\x00\x01\x0e\x00\x01\x00\x69\x70\x76\x34\x74\x61\x62\x6c\x65\x00\x00\x00\x44\x00\x03\x80\x10\x00\x01\x80\x0c\x00\x01\x80\x06\x00\x01\x00\x2e\xe0\x00\x00\x10\x00\x02\x80\x0c\x00\x01\x80\x06\x00\x01\x00\x2e\xe1\x00\x00\x10\x00\x03\x80\x0c\x00\x01\x80\x06\x00\x01\x00\x30\x39\x00\x00\x10\x00\x04\x80\x0c\x00\x01\x80\x06\x00\x01\x00\x30\x3a\x00\x00"), + + []byte("\x02\x00\x00\x00\x0e\x00\x01\x00\x69\x70\x76\x34\x74\x61\x62\x6c\x65\x00\x00\x00\x10\x00\x02\x00\x69\x70\x76\x34\x63\x68\x61\x69\x6e\x2d\x32\x00\xbc\x00\x04\x80\x24\x00\x01\x80\x09\x00\x01\x00\x6d\x65\x74\x61\x00\x00\x00\x00\x14\x00\x02\x80\x08\x00\x02\x00\x00\x00\x00\x10\x08\x00\x01\x00\x00\x00\x00\x01\x2c\x00\x01\x80\x08\x00\x01\x00\x63\x6d\x70\x00\x20\x00\x02\x80\x08\x00\x01\x00\x00\x00\x00\x01\x08\x00\x02\x00\x00\x00\x00\x00\x0c\x00\x03\x80\x05\x00\x01\x00\x06\x00\x00\x00\x34\x00\x01\x80\x0c\x00\x01\x00\x70\x61\x79\x6c\x6f\x61\x64\x00\x24\x00\x02\x80\x08\x00\x01\x00\x00\x00\x00\x01\x08\x00\x02\x00\x00\x00\x00\x02\x08\x00\x03\x00\x00\x00\x00\x02\x08\x00\x04\x00\x00\x00\x00\x02\x34\x00\x01\x80\x0b\x00\x01\x00\x6c\x6f\x6f\x6b\x75\x70\x00\x00\x24\x00\x02\x80\x08\x00\x02\x00\x00\x00\x00\x01\x0d\x00\x01\x00\x74\x65\x73\x74\x2d\x73\x65\x74\x00\x00\x00\x00\x08\x00\x04\x00\x00\x00\x00\x01"), + + // batch end + []byte("\x00\x00\x00\x0a"), + } + + c := &nftables.Conn{ + TestDial: func(req []netlink.Message) ([]netlink.Message, error) { + for idx, msg := range req { + b, err := msg.MarshalBinary() + if err != nil { + t.Fatal(err) + } + if len(b) < 16 { + continue + } + b = b[16:] + if len(want) == 0 { + t.Errorf("no want entry for message %d: %x", idx, b) + continue + } + if got, want := b, want[0]; !bytes.Equal(got, want) { + t.Errorf("message %d: %s", idx, linediff(nfdump(got), nfdump(want))) + } + want = want[1:] + } + return req, nil + }, + } + + tbl := &nftables.Table{ + Name: "ipv4table", + Family: nftables.TableFamilyIPv4, + } + ch := &nftables.Chain{ + Name: "ipv4chain-2", + Table: tbl, + Type: nftables.ChainTypeNAT, + Priority: nftables.ChainPriorityNATDest, + Hooknum: nftables.ChainHookPrerouting, + Policy: 1, // TODO + } + set := nftables.Set{ + Anonymous: false, + Constant: true, + Name: "test-set", + ID: uint32(1), //rand.Intn(0xffff)), + Table: tbl, + KeyType: nftables.TypeInetService, + } + c.AddTable(tbl) + c.AddChain(ch) + + re := []expr.Any{} + re = append(re, &expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1}) + re = append(re, &expr.Cmp{ + Op: expr.CmpOpEq, + Register: 1, + Data: []byte{unix.IPPROTO_TCP}, + }) + re = append(re, &expr.Payload{ + DestRegister: 1, + Base: expr.PayloadBaseTransportHeader, + Offset: 2, // Offset for a transport protocol header + Len: 2, // 2 bytes for port + }) + re = append(re, &expr.Lookup{ + SourceRegister: 1, + Invert: false, + SetID: set.ID, + SetName: set.Name, + }) + + ports := []uint16{12000, 12001, 12345, 12346} + setElements := make([]nftables.SetElement, len(ports)) + for i := 0; i < len(ports); i++ { + setElements[i].Key = binaryutil.BigEndian.PutUint16(ports[i]) + } + + if err := c.AddSet(&set, setElements); err != nil { + t.Fatal(err) + } + + c.AddRule(&nftables.Rule{ + Table: tbl, + Chain: ch, + Exprs: re, + }) + + if err := c.Flush(); err != nil { + t.Fatal(err) + } +}