Skip to content

Instantly share code, notes, and snippets.

@stapelberg
Created December 10, 2022 13:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stapelberg/7ea441dc5bdef1a795cdd7bcb5b5b4cb to your computer and use it in GitHub Desktop.
Save stapelberg/7ea441dc5bdef1a795cdd7bcb5b5b4cb to your computer and use it in GitHub Desktop.
eglot log (working and broken)
[internal] Sat Dec 10 13:24:53 2022:
(:message "Running language server: (gopls -rpc.trace -debug=localhost:9040 -logfile=/tmp/gopls.log)")
[client-request] (id:1) Sat Dec 10 13:24:53 2022:
(:jsonrpc "2.0" :id 1 :method "initialize" :params
(:processId 336506 :rootPath "/home/michael/go/src/github.com/google/nftables/" :rootUri "file:///home/michael/go/src/github.com/google/nftables" :initializationOptions #s(hash-table size 1 test eql rehash-size 1.5 rehash-threshold 0.8125 data
())
:capabilities
(:workspace
(:applyEdit t :executeCommand
(:dynamicRegistration :json-false)
:workspaceEdit
(:documentChanges t)
:didChangeWatchedFiles
(:dynamicRegistration t)
:symbol
(:dynamicRegistration :json-false)
:configuration t :workspaceFolders t)
:textDocument
(:synchronization
(:dynamicRegistration :json-false :willSave t :willSaveWaitUntil t :didSave t)
:completion
(:dynamicRegistration :json-false :completionItem
(:snippetSupport :json-false :deprecatedSupport t :tagSupport
(:valueSet
[1]))
:contextSupport t)
:hover
(:dynamicRegistration :json-false :contentFormat
["markdown" "plaintext"])
:signatureHelp
(:dynamicRegistration :json-false :signatureInformation
(:parameterInformation
(:labelOffsetSupport t)
:activeParameterSupport t))
:references
(:dynamicRegistration :json-false)
:definition
(:dynamicRegistration :json-false :linkSupport t)
:declaration
(:dynamicRegistration :json-false :linkSupport t)
:implementation
(:dynamicRegistration :json-false :linkSupport t)
:typeDefinition
(:dynamicRegistration :json-false :linkSupport t)
:documentSymbol
(:dynamicRegistration :json-false :hierarchicalDocumentSymbolSupport t :symbolKind
(:valueSet
[1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26]))
:documentHighlight
(:dynamicRegistration :json-false)
:codeAction
(:dynamicRegistration :json-false :codeActionLiteralSupport
(:codeActionKind
(:valueSet
["quickfix" "refactor" "refactor.extract" "refactor.inline" "refactor.rewrite" "source" "source.organizeImports"]))
:isPreferredSupport t)
:formatting
(:dynamicRegistration :json-false)
:rangeFormatting
(:dynamicRegistration :json-false)
:rename
(:dynamicRegistration :json-false)
:publishDiagnostics
(:relatedInformation :json-false :codeDescriptionSupport :json-false :tagSupport
(:valueSet
[1 2])))
:experimental #s(hash-table size 1 test eql rehash-size 1.5 rehash-threshold 0.8125 data
()))
:workspaceFolders
[(:uri "file:///home/michael/go/src/github.com/google/nftables" :name "~/go/src/github.com/google/nftables/")]))
[server-reply] (id:1) Sat Dec 10 13:24:53 2022:
(:jsonrpc "2.0" :result
(:capabilities
(:textDocumentSync
(:openClose t :change 2 :save nil)
:completionProvider
(:triggerCharacters
["."])
:hoverProvider t :signatureHelpProvider
(:triggerCharacters
["(" ","])
:definitionProvider t :typeDefinitionProvider t :implementationProvider t :referencesProvider t :documentHighlightProvider t :documentSymbolProvider t :codeActionProvider
(:codeActionKinds
["quickfix" "refactor.extract" "refactor.rewrite" "source.fixAll" "source.organizeImports"])
:codeLensProvider nil :documentLinkProvider nil :workspaceSymbolProvider t :documentFormattingProvider t :renameProvider t :foldingRangeProvider t :executeCommandProvider
(:commands
["gopls.add_dependency" "gopls.add_import" "gopls.apply_fix" "gopls.check_upgrades" "gopls.edit_go_directive" "gopls.gc_details" "gopls.generate" "gopls.generate_gopls_mod" "gopls.go_get_package" "gopls.list_imports" "gopls.list_known_packages" "gopls.regenerate_cgo" "gopls.remove_dependency" "gopls.reset_go_mod_diagnostics" "gopls.run_tests" "gopls.run_vulncheck_exp" "gopls.start_debugging" "gopls.test" "gopls.tidy" "gopls.toggle_gc_details" "gopls.update_go_sum" "gopls.upgrade_dependency" "gopls.vendor"])
:callHierarchyProvider t :inlayHintProvider nil :workspace
(:workspaceFolders
(:supported t :changeNotifications "workspace/didChangeWorkspaceFolders")
:fileOperations nil))
:serverInfo
(:name "gopls" :version "{\"GoVersion\":\"go1.19.3\",\"Path\":\"golang.org/x/tools/gopls\",\"Main\":{\"Path\":\"golang.org/x/tools/gopls\",\"Version\":\"(devel)\",\"Sum\":\"\",\"Replace\":null},\"Deps\":[{\"Path\":\"github.com/BurntSushi/toml\",\"Version\":\"v1.2.0\",\"Sum\":\"h1:Rt8g24XnyGTyglgET/PRUNlrUeu9F5L+7FilkXfZgs0=\",\"Replace\":null},{\"Path\":\"github.com/google/go-cmp\",\"Version\":\"v0.5.8\",\"Sum\":\"h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=\",\"Replace\":null},{\"Path\":\"github.com/sergi/go-diff\",\"Version\":\"v1.1.0\",\"Sum\":\"h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=\",\"Replace\":null},{\"Path\":\"golang.org/x/exp\",\"Version\":\"v0.0.0-20220722155223-a9213eeb770e\",\"Sum\":\"h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA=\",\"Replace\":null},{\"Path\":\"golang.org/x/exp/typeparams\",\"Version\":\"v0.0.0-20220722155223-a9213eeb770e\",\"Sum\":\"h1:7Xs2YCOpMlNqSQSmrrnhlzBXIE/bpMecZplbLePTJvE=\",\"Replace\":null},{\"Path\":\"golang.org/x/mod\",\"Version\":\"v0.6.0\",\"Sum\":\"h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I=\",\"Replace\":null},{\"Path\":\"golang.org/x/sync\",\"Version\":\"v0.0.0-20220722155255-886fb9371eb4\",\"Sum\":\"h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw=\",\"Replace\":null},{\"Path\":\"golang.org/x/sys\",\"Version\":\"v0.1.0\",\"Sum\":\"h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=\",\"Replace\":null},{\"Path\":\"golang.org/x/text\",\"Version\":\"v0.4.0\",\"Sum\":\"h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=\",\"Replace\":null},{\"Path\":\"golang.org/x/tools\",\"Version\":\"v0.2.1-0.20221101170700-b5bc717366b2\",\"Sum\":\"h1:KBm+UwBaO/tdQ35tfGvxH1FUCiXRg4MoTzkznsdeab8=\",\"Replace\":null},{\"Path\":\"golang.org/x/vuln\",\"Version\":\"v0.0.0-20221010193109-563322be2ea9\",\"Sum\":\"h1:KaYZQUtEEaV8aVADIHAuYBTjo77aUcCvC7KTGKM3J1I=\",\"Replace\":null},{\"Path\":\"honnef.co/go/tools\",\"Version\":\"v0.3.3\",\"Sum\":\"h1:oDx7VAwstgpYpb3wv0oxiZlxY+foCpRAwY7Vk6XpAgA=\",\"Replace\":null},{\"Path\":\"mvdan.cc/gofumpt\",\"Version\":\"v0.3.1\",\"Sum\":\"h1:avhhrOmv0IuvQVK7fvwV91oFSGAk5/6Po8GXTzICeu8=\",\"Replace\":null},{\"Path\":\"mvdan.cc/xurls/v2\",\"Version\":\"v2.4.0\",\"Sum\":\"h1:tzxjVAj+wSBmDcF6zBB7/myTy3gX9xvi8Tyr28AuQgc=\",\"Replace\":null}],\"Settings\":[{\"Key\":\"-compiler\",\"Value\":\"gc\"},{\"Key\":\"-trimpath\",\"Value\":\"true\"},{\"Key\":\"CGO_ENABLED\",\"Value\":\"1\"},{\"Key\":\"GOARCH\",\"Value\":\"amd64\"},{\"Key\":\"GOOS\",\"Value\":\"linux\"},{\"Key\":\"GOAMD64\",\"Value\":\"v1\"},{\"Key\":\"vcs\",\"Value\":\"git\"},{\"Key\":\"vcs.revision\",\"Value\":\"8321f7bbcfd30300762661ed9188226b42e27ec1\"},{\"Key\":\"vcs.time\",\"Value\":\"2022-11-01T17:30:21Z\"},{\"Key\":\"vcs.modified\",\"Value\":\"false\"}],\"Version\":\"v0.10.1\"}"))
:id 1)
[client-notification] Sat Dec 10 13:24:53 2022:
(:jsonrpc "2.0" :method "initialized" :params #s(hash-table size 1 test eql rehash-size 1.5 rehash-threshold 0.8125 data
()))
[client-notification] Sat Dec 10 13:24:53 2022:
(:jsonrpc "2.0" :method "textDocument/didOpen" :params
(:textDocument
(:uri "file:///home/michael/go/src/github.com/google/nftables/nftables_test.go" :version 0 :languageId "go" :text "// Copyright 2018 Google LLC. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage nftables_test\n\nimport (\n \"bytes\"\n \"errors\"\n \"flag\"\n \"fmt\"\n \"net\"\n \"os\"\n \"reflect\"\n \"runtime\"\n \"strings\"\n \"testing\"\n \"time\"\n\n \"github.com/google/nftables\"\n \"github.com/google/nftables/binaryutil\"\n \"github.com/google/nftables/expr\"\n \"github.com/google/nftables/internal/nftest\"\n \"github.com/google/nftables/xt\"\n \"github.com/mdlayher/netlink\"\n \"github.com/vishvananda/netns\"\n \"golang.org/x/sys/unix\"\n)\n\nvar (\n enableSysTests = flag.Bool(\"run_system_tests\", false, \"Run tests that operate against the live kernel\")\n)\n\n// nfdump returns a hexdump of 4 bytes per line (like nft --debug=all), allowing\n// users to make sense of large byte literals more easily.\nfunc nfdump(b []byte) string {\n var buf bytes.Buffer\n i := 0\n for ; i < len(b); i += 4 {\n // TODO: show printable characters as ASCII\n fmt.Fprintf(&buf, \"%02x %02x %02x %02x\\n\",\n b[i],\n b[i+1],\n b[i+2],\n b[i+3])\n }\n for ; i < len(b); i++ {\n fmt.Fprintf(&buf, \"%02x \", b[i])\n }\n return buf.String()\n}\n\n// linediff returns a side-by-side diff of two nfdump() return values, flagging\n// lines which are not equal with an exclamation point prefix.\nfunc linediff(a, b string) string {\n var buf bytes.Buffer\n fmt.Fprintf(&buf, \"got -- want\\n\")\n linesA := strings.Split(a, \"\\n\")\n linesB := strings.Split(b, \"\\n\")\n for idx, lineA := range linesA {\n if idx >= len(linesB) {\n break\n }\n lineB := linesB[idx]\n prefix := \"! \"\n if lineA == lineB {\n prefix = \" \"\n }\n fmt.Fprintf(&buf, \"%s%s -- %s\\n\", prefix, lineA, lineB)\n }\n return buf.String()\n}\n\nfunc ifname(n string) []byte {\n b := make([]byte, 16)\n copy(b, []byte(n+\"\\x00\"))\n return b\n}\n\n// openSystemNFTConn returns a netlink connection that tests against\n// the running kernel in a separate network namespace.\n// cleanupSystemNFTConn() must be called from a defer to cleanup\n// created network namespace.\nfunc openSystemNFTConn(t *testing.T) (*nftables.Conn, netns.NsHandle) {\n t.Helper()\n if !*enableSysTests {\n t.SkipNow()\n }\n // We lock the goroutine into the current thread, as namespace operations\n // such as those invoked by `netns.New()` are thread-local. This is undone\n // in cleanupSystemNFTConn().\n runtime.LockOSThread()\n\n ns, err := netns.New()\n if err != nil {\n t.Fatalf(\"netns.New() failed: %v\", err)\n }\n c, err := nftables.New(nftables.WithNetNSFd(int(ns)))\n if err != nil {\n t.Fatalf(\"nftables.New() failed: %v\", err)\n }\n return c, ns\n}\n\nfunc cleanupSystemNFTConn(t *testing.T, newNS netns.NsHandle) {\n defer runtime.UnlockOSThread()\n\n if err := newNS.Close(); err != nil {\n t.Fatalf(\"newNS.Close() failed: %v\", err)\n }\n}\n\nfunc TestRuleOperations(t *testing.T) {\n\n // Create a new network namespace to test these operations,\n // and tear down the namespace at test completion.\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n // Clear all rules at the beginning + end of the test.\n c.FlushRuleset()\n defer c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n prerouting := c.AddChain(&nftables.Chain{\n Name: \"base-chain\",\n Table: filter,\n Type: nftables.ChainTypeFilter,\n Hooknum: nftables.ChainHookPrerouting,\n Priority: nftables.ChainPriorityFilter,\n })\n\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: prerouting,\n Exprs: []expr.Any{\n &expr.Verdict{\n // [ immediate reg 0 drop ]\n Kind: expr.VerdictDrop,\n },\n },\n })\n\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: prerouting,\n Exprs: []expr.Any{\n &expr.Verdict{\n // [ immediate reg 0 drop ]\n Kind: expr.VerdictDrop,\n },\n },\n })\n\n c.InsertRule(&nftables.Rule{\n Table: filter,\n Chain: prerouting,\n Exprs: []expr.Any{\n &expr.Verdict{\n // [ immediate reg 0 accept ]\n Kind: expr.VerdictAccept,\n },\n },\n })\n\n c.InsertRule(&nftables.Rule{\n Table: filter,\n Chain: prerouting,\n Exprs: []expr.Any{\n &expr.Verdict{\n // [ immediate reg 0 queue ]\n Kind: expr.VerdictQueue,\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n\n rules, _ := c.GetRules(filter, prerouting)\n\n want := []expr.VerdictKind{\n expr.VerdictQueue,\n expr.VerdictAccept,\n expr.VerdictDrop,\n expr.VerdictDrop,\n }\n\n for i, r := range rules {\n rr, _ := r.Exprs[0].(*expr.Verdict)\n\n if rr.Kind != want[i] {\n t.Fatalf(\"bad verdict kind at %d\", i)\n }\n }\n\n c.ReplaceRule(&nftables.Rule{\n Table: filter,\n Chain: prerouting,\n Handle: rules[2].Handle,\n Exprs: []expr.Any{\n &expr.Verdict{\n // [ immediate reg 0 accept ]\n Kind: expr.VerdictAccept,\n },\n },\n })\n\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: prerouting,\n Position: rules[2].Handle,\n Exprs: []expr.Any{\n &expr.Verdict{\n // [ immediate reg 0 drop ]\n Kind: expr.VerdictDrop,\n },\n },\n })\n\n c.InsertRule(&nftables.Rule{\n Table: filter,\n Chain: prerouting,\n Position: rules[2].Handle,\n Exprs: []expr.Any{\n &expr.Verdict{\n // [ immediate reg 0 queue ]\n Kind: expr.VerdictQueue,\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n\n rules, _ = c.GetRules(filter, prerouting)\n\n want = []expr.VerdictKind{\n expr.VerdictQueue,\n expr.VerdictAccept,\n expr.VerdictQueue,\n expr.VerdictAccept,\n expr.VerdictDrop,\n expr.VerdictDrop,\n }\n\n for i, r := range rules {\n rr, _ := r.Exprs[0].(*expr.Verdict)\n\n if rr.Kind != want[i] {\n t.Fatalf(\"bad verdict kind at %d\", i)\n }\n }\n}\n\nfunc TestConfigureNAT(t *testing.T) {\n // The want byte sequences come from stracing nft(8), e.g.:\n // strace -f -v -x -s 2048 -eraw=sendto nft add table ip nat\n //\n // The nft(8) command sequence was taken from:\n // https://wiki.nftables.org/wiki-nftables/index.php/Performing_Network_Address_Translation_(NAT)\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft flush ruleset\n []byte(\"\\x00\\x00\\x00\\x00\"),\n // nft add table ip nat\n []byte(\"\\x02\\x00\\x00\\x00\\x08\\x00\\x01\\x00\\x6e\\x61\\x74\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain nat prerouting '{' type nat hook prerouting priority 0 \\; '}'\n []byte(\"\\x02\\x00\\x00\\x00\\x08\\x00\\x01\\x00\\x6e\\x61\\x74\\x00\\x0f\\x00\\x03\\x00\\x70\\x72\\x65\\x72\\x6f\\x75\\x74\\x69\\x6e\\x67\\x00\\x00\\x14\\x00\\x04\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x08\\x00\\x07\\x00\\x6e\\x61\\x74\\x00\"),\n // nft add chain nat postrouting '{' type nat hook postrouting priority 100 \\; '}'\n []byte(\"\\x02\\x00\\x00\\x00\\x08\\x00\\x01\\x00\\x6e\\x61\\x74\\x00\\x10\\x00\\x03\\x00\\x70\\x6f\\x73\\x74\\x72\\x6f\\x75\\x74\\x69\\x6e\\x67\\x00\\x14\\x00\\x04\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x04\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x64\\x08\\x00\\x07\\x00\\x6e\\x61\\x74\\x00\"),\n // nft add rule nat postrouting oifname uplink0 masquerade\n []byte(\"\\x02\\x00\\x00\\x00\\x08\\x00\\x01\\x00\\x6e\\x61\\x74\\x00\\x10\\x00\\x02\\x00\\x70\\x6f\\x73\\x74\\x72\\x6f\\x75\\x74\\x69\\x6e\\x67\\x00\\x74\\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\\x07\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x38\\x00\\x01\\x80\\x08\\x00\\x01\\x00\\x63\\x6d\\x70\\x00\\x2c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x18\\x00\\x03\\x80\\x14\\x00\\x01\\x00\\x75\\x70\\x6c\\x69\\x6e\\x6b\\x30\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x14\\x00\\x01\\x80\\x09\\x00\\x01\\x00\\x6d\\x61\\x73\\x71\\x00\\x00\\x00\\x00\\x04\\x00\\x02\\x80\"),\n // nft add rule nat prerouting iif uplink0 tcp dport 4070 dnat 192.168.23.2:4080\n []byte(\"\\x02\\x00\\x00\\x00\\x08\\x00\\x01\\x00\\x6e\\x61\\x74\\x00\\x0f\\x00\\x02\\x00\\x70\\x72\\x65\\x72\\x6f\\x75\\x74\\x69\\x6e\\x67\\x00\\x00\\x98\\x01\\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\\x06\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x38\\x00\\x01\\x80\\x08\\x00\\x01\\x00\\x63\\x6d\\x70\\x00\\x2c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x18\\x00\\x03\\x80\\x14\\x00\\x01\\x00\\x75\\x70\\x6c\\x69\\x6e\\x6b\\x30\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\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\\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\\x06\\x00\\x01\\x00\\x0f\\xe6\\x00\\x00\\x2c\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x69\\x6d\\x6d\\x65\\x64\\x69\\x61\\x74\\x65\\x00\\x00\\x00\\x18\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x0c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\xc0\\xa8\\x17\\x02\\x2c\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x69\\x6d\\x6d\\x65\\x64\\x69\\x61\\x74\\x65\\x00\\x00\\x00\\x18\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x02\\x0c\\x00\\x02\\x80\\x06\\x00\\x01\\x00\\x0f\\xf0\\x00\\x00\\x30\\x00\\x01\\x80\\x08\\x00\\x01\\x00\\x6e\\x61\\x74\\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\\x01\\x08\\x00\\x05\\x00\\x00\\x00\\x00\\x02\"),\n // nft add rule nat prerouting iifname uplink0 udp dport 4070-4090 dnat 192.168.23.2:4070-4090\n []byte(\"\\x02\\x00\\x00\\x00\\x08\\x00\\x01\\x00\\x6e\\x61\\x74\\x00\\x0f\\x00\\x02\\x00\\x70\\x72\\x65\\x72\\x6f\\x75\\x74\\x69\\x6e\\x67\\x00\\x00\\xf8\\x01\\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\\x06\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x38\\x00\\x01\\x80\\x08\\x00\\x01\\x00\\x63\\x6d\\x70\\x00\\x2c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x18\\x00\\x03\\x80\\x14\\x00\\x01\\x00\\x75\\x70\\x6c\\x69\\x6e\\x6b\\x30\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\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\\x11\\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\\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\\x05\\x0c\\x00\\x03\\x80\\x06\\x00\\x01\\x00\\x0f\\xe6\\x00\\x00\\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\\x03\\x0c\\x00\\x03\\x80\\x06\\x00\\x01\\x00\\x0f\\xfa\\x00\\x00\\x2c\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x69\\x6d\\x6d\\x65\\x64\\x69\\x61\\x74\\x65\\x00\\x00\\x00\\x18\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x0c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\xc0\\xa8\\x17\\x02\\x2c\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x69\\x6d\\x6d\\x65\\x64\\x69\\x61\\x74\\x65\\x00\\x00\\x00\\x18\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x02\\x0c\\x00\\x02\\x80\\x06\\x00\\x01\\x00\\x0f\\xe6\\x00\\x00\\x2c\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x69\\x6d\\x6d\\x65\\x64\\x69\\x61\\x74\\x65\\x00\\x00\\x00\\x18\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x03\\x0c\\x00\\x02\\x80\\x06\\x00\\x01\\x00\\x0f\\xfa\\x00\\x00\\x38\\x00\\x01\\x80\\x08\\x00\\x01\\x00\\x6e\\x61\\x74\\x00\\x2c\\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\\x01\\x08\\x00\\x05\\x00\\x00\\x00\\x00\\x02\\x08\\x00\\x06\\x00\\x00\\x00\\x00\\x03\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.FlushRuleset()\n\n nat := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"nat\",\n })\n\n prerouting := c.AddChain(&nftables.Chain{\n Name: \"prerouting\",\n Hooknum: nftables.ChainHookPrerouting,\n Priority: nftables.ChainPriorityFilter,\n Table: nat,\n Type: nftables.ChainTypeNAT,\n })\n\n postrouting := c.AddChain(&nftables.Chain{\n Name: \"postrouting\",\n Hooknum: nftables.ChainHookPostrouting,\n Priority: nftables.ChainPriorityNATSource,\n Table: nat,\n Type: nftables.ChainTypeNAT,\n })\n\n c.AddRule(&nftables.Rule{\n Table: nat,\n Chain: postrouting,\n Exprs: []expr.Any{\n // meta load oifname => reg 1\n &expr.Meta{Key: expr.MetaKeyOIFNAME, Register: 1},\n // cmp eq reg 1 0x696c7075 0x00306b6e 0x00000000 0x00000000\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: ifname(\"uplink0\"),\n },\n // masq\n &expr.Masq{},\n },\n })\n\n c.AddRule(&nftables.Rule{\n Table: nat,\n Chain: prerouting,\n Exprs: []expr.Any{\n // [ meta load iifname => reg 1 ]\n &expr.Meta{Key: expr.MetaKeyIIFNAME, Register: 1},\n // [ cmp eq reg 1 0x696c7075 0x00306b6e 0x00000000 0x00000000 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: ifname(\"uplink0\"),\n },\n\n // [ meta load l4proto => reg 1 ]\n &expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1},\n // [ cmp eq reg 1 0x00000006 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{unix.IPPROTO_TCP},\n },\n\n // [ payload load 2b @ transport header + 2 => reg 1 ]\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseTransportHeader,\n Offset: 2, // TODO\n Len: 2, // TODO\n },\n // [ cmp eq reg 1 0x0000e60f ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: binaryutil.BigEndian.PutUint16(4070),\n },\n\n // [ immediate reg 1 0x0217a8c0 ]\n &expr.Immediate{\n Register: 1,\n Data: net.ParseIP(\"192.168.23.2\").To4(),\n },\n // [ immediate reg 2 0x0000f00f ]\n &expr.Immediate{\n Register: 2,\n Data: binaryutil.BigEndian.PutUint16(4080),\n },\n // [ nat dnat ip addr_min reg 1 addr_max reg 0 proto_min reg 2 proto_max reg 0 ]\n &expr.NAT{\n Type: expr.NATTypeDestNAT,\n Family: unix.NFPROTO_IPV4,\n RegAddrMin: 1,\n RegProtoMin: 2,\n },\n },\n })\n\n c.AddRule(&nftables.Rule{\n Table: nat,\n Chain: prerouting,\n Exprs: []expr.Any{\n // [ meta load iifname => reg 1 ]\n &expr.Meta{Key: expr.MetaKeyIIFNAME, Register: 1},\n // [ cmp eq reg 1 0x696c7075 0x00306b6e 0x00000000 0x00000000 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: ifname(\"uplink0\"),\n },\n\n // [ meta load l4proto => reg 1 ]\n &expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1},\n // [ cmp eq reg 1 0x00000006 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{unix.IPPROTO_UDP},\n },\n\n // [ payload load 2b @ transport header + 2 => reg 1 ]\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseTransportHeader,\n Offset: 2, // TODO\n Len: 2, // TODO\n },\n // [ cmp gte reg 1 0x0000e60f ]\n &expr.Cmp{\n Op: expr.CmpOpGte,\n Register: 1,\n Data: binaryutil.BigEndian.PutUint16(4070),\n },\n // [ cmp lte reg 1 0x0000fa0f ]\n &expr.Cmp{\n Op: expr.CmpOpLte,\n Register: 1,\n Data: binaryutil.BigEndian.PutUint16(4090),\n },\n\n // [ immediate reg 1 0x0217a8c0 ]\n &expr.Immediate{\n Register: 1,\n Data: net.ParseIP(\"192.168.23.2\").To4(),\n },\n // [ immediate reg 2 0x0000f00f ]\n &expr.Immediate{\n Register: 2,\n Data: binaryutil.BigEndian.PutUint16(4070),\n },\n // [ immediate reg 3 0x0000fa0f ]\n &expr.Immediate{\n Register: 3,\n Data: binaryutil.BigEndian.PutUint16(4090),\n },\n // [ nat dnat ip addr_min reg 1 addr_max reg 0 proto_min reg 2 proto_max reg 3 ]\n &expr.NAT{\n Type: expr.NATTypeDestNAT,\n Family: unix.NFPROTO_IPV4,\n RegAddrMin: 1,\n RegProtoMin: 2,\n RegProtoMax: 3,\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestConfigureNATSourceAddress(t *testing.T) {\n // The want byte sequences come from stracing nft(8), e.g.:\n // strace -f -v -x -s 2048 -eraw=sendto nft add table ip nat\n //\n // The nft(8) command sequence was taken from:\n // https://wiki.nftables.org/wiki-nftables/index.php/Performing_Network_Address_Translation_(NAT)\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft flush ruleset\n []byte(\"\\x00\\x00\\x00\\x00\"),\n // nft add table ip nat\n []byte(\"\\x02\\x00\\x00\\x00\\x08\\x00\\x01\\x00\\x6e\\x61\\x74\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain nat postrouting '{' type nat hook postrouting priority 100 \\; '}'\n []byte(\"\\x02\\x00\\x00\\x00\\x08\\x00\\x01\\x00\\x6e\\x61\\x74\\x00\\x10\\x00\\x03\\x00\\x70\\x6f\\x73\\x74\\x72\\x6f\\x75\\x74\\x69\\x6e\\x67\\x00\\x14\\x00\\x04\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x04\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x64\\x08\\x00\\x07\\x00\\x6e\\x61\\x74\\x00\"),\n // nft add rule nat postrouting ip saddr 192.168.69.2 masquerade\n []byte(\"\\x02\\x00\\x00\\x00\\x08\\x00\\x01\\x00\\x6e\\x61\\x74\\x00\\x10\\x00\\x02\\x00\\x70\\x6f\\x73\\x74\\x72\\x6f\\x75\\x74\\x69\\x6e\\x67\\x00\\x78\\x00\\x04\\x80\\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\\x01\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x0c\\x08\\x00\\x04\\x00\\x00\\x00\\x00\\x04\\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\\x08\\x00\\x01\\x00\\xc0\\xa8\\x45\\x02\\x14\\x00\\x01\\x80\\x09\\x00\\x01\\x00\\x6d\\x61\\x73\\x71\\x00\\x00\\x00\\x00\\x04\\x00\\x02\\x80\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.FlushRuleset()\n\n nat := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"nat\",\n })\n\n postrouting := c.AddChain(&nftables.Chain{\n Name: \"postrouting\",\n Hooknum: nftables.ChainHookPostrouting,\n Priority: nftables.ChainPriorityNATSource,\n Table: nat,\n Type: nftables.ChainTypeNAT,\n })\n\n c.AddRule(&nftables.Rule{\n Table: nat,\n Chain: postrouting,\n Exprs: []expr.Any{\n // payload load 4b @ network header + 12 => reg 1\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseNetworkHeader,\n Offset: 12,\n Len: 4,\n },\n // cmp eq reg 1 0x0245a8c0\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: net.ParseIP(\"192.168.69.2\").To4(),\n },\n\n // masq\n &expr.Masq{},\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestExprLogOptions(t *testing.T) {\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n\n c.FlushRuleset()\n defer c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n input := c.AddChain(&nftables.Chain{\n Name: \"input\",\n Table: filter,\n Type: nftables.ChainTypeFilter,\n Hooknum: nftables.ChainHookInput,\n Priority: nftables.ChainPriorityFilter,\n })\n forward := c.AddChain(&nftables.Chain{\n Name: \"forward\",\n Table: filter,\n Type: nftables.ChainTypeFilter,\n Hooknum: nftables.ChainHookInput,\n Priority: nftables.ChainPriorityFilter,\n })\n\n keyGQ := uint32((1 << unix.NFTA_LOG_GROUP) | (1 << unix.NFTA_LOG_QTHRESHOLD) | (1 << unix.NFTA_LOG_SNAPLEN))\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: input,\n Exprs: []expr.Any{\n &expr.Log{\n Key: keyGQ,\n QThreshold: uint16(20),\n Group: uint16(1),\n Snaplen: uint32(132),\n },\n },\n })\n\n keyPL := uint32((1 << unix.NFTA_LOG_PREFIX) | (1 << unix.NFTA_LOG_LEVEL) | (1 << unix.NFTA_LOG_FLAGS))\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: forward,\n Exprs: []expr.Any{\n &expr.Log{\n Key: keyPL,\n Data: []byte(\"LOG FORWARD\"),\n Level: expr.LogLevelDebug,\n Flags: expr.LogFlagsTCPOpt | expr.LogFlagsIPOpt,\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Errorf(\"c.Flush() failed: %v\", err)\n }\n\n rules, err := c.GetRules(\n &nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n },\n &nftables.Chain{\n Name: \"input\",\n },\n )\n if err != nil {\n t.Fatal(err)\n }\n\n if got, want := len(rules), 1; got != want {\n t.Fatalf(\"unexpected number of rules: got %d, want %d\", got, want)\n }\n\n rule := rules[0]\n if got, want := len(rule.Exprs), 1; got != want {\n t.Fatalf(\"unexpected number of exprs: got %d, want %d\", got, want)\n }\n\n le, ok := rule.Exprs[0].(*expr.Log)\n if !ok {\n t.Fatalf(\"unexpected expression type: got %T, want *expr.Log\", rule.Exprs[0])\n }\n\n if got, want := le.Key, keyGQ; got != want {\n t.Fatalf(\"unexpected log key: got %d, want %d\", got, want)\n }\n\n if got, want := le.Group, uint16(1); got != want {\n t.Fatalf(\"unexpected group: got %d, want %d\", got, want)\n }\n\n if got, want := le.QThreshold, uint16(20); got != want {\n t.Fatalf(\"unexpected queue-threshold: got %d, want %d\", got, want)\n }\n\n if got, want := le.Snaplen, uint32(132); got != want {\n t.Fatalf(\"unexpected snaplen: got %d, want %d\", got, want)\n }\n\n rules, err = c.GetRules(\n &nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n },\n &nftables.Chain{\n Name: \"forward\",\n },\n )\n if err != nil {\n t.Fatal(err)\n }\n\n if got, want := len(rules), 1; got != want {\n t.Fatalf(\"unexpected number of rules: got %d, want %d\", got, want)\n }\n\n rule = rules[0]\n if got, want := len(rule.Exprs), 1; got != want {\n t.Fatalf(\"unexpected number of exprs: got %d, want %d\", got, want)\n }\n\n le, ok = rule.Exprs[0].(*expr.Log)\n if !ok {\n t.Fatalf(\"unexpected expression type: got %T, want *expr.Log\", rule.Exprs[0])\n }\n\n if got, want := le.Key, keyPL; got != want {\n t.Fatalf(\"unexpected log key: got %d, want %d\", got, want)\n }\n\n if got, want := string(le.Data), \"LOG FORWARD\"; got != want {\n t.Fatalf(\"unexpected prefix data: got %s, want %s\", got, want)\n }\n\n if got, want := le.Level, expr.LogLevelDebug; got != want {\n t.Fatalf(\"unexpected log level: got %d, want %d\", got, want)\n }\n\n if got, want := le.Flags, expr.LogFlagsTCPOpt|expr.LogFlagsIPOpt; got != want {\n t.Fatalf(\"unexpected log flags: got %d, want %d\", got, want)\n }\n}\n\nfunc TestExprLogPrefix(t *testing.T) {\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n\n c.FlushRuleset()\n defer c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n input := c.AddChain(&nftables.Chain{\n Name: \"input\",\n Table: filter,\n Type: nftables.ChainTypeFilter,\n Hooknum: nftables.ChainHookInput,\n Priority: nftables.ChainPriorityFilter,\n })\n\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: input,\n Exprs: []expr.Any{\n &expr.Log{\n Key: 1 << unix.NFTA_LOG_PREFIX,\n Data: []byte(\"LOG INPUT\"),\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Errorf(\"c.Flush() failed: %v\", err)\n }\n\n rules, err := c.GetRules(\n &nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n },\n &nftables.Chain{\n Name: \"input\",\n },\n )\n if err != nil {\n t.Fatal(err)\n }\n\n if got, want := len(rules), 1; got != want {\n t.Fatalf(\"unexpected number of rules: got %d, want %d\", got, want)\n }\n if got, want := len(rules[0].Exprs), 1; got != want {\n t.Fatalf(\"unexpected number of exprs: got %d, want %d\", got, want)\n }\n\n logExpr, ok := rules[0].Exprs[0].(*expr.Log)\n if !ok {\n t.Fatalf(\"Exprs[0] is type %T, want *expr.Log\", rules[0].Exprs[0])\n }\n\n // nftables defaults to warn log level when no level is specified and group is not defined\n // see https://wiki.nftables.org/wiki-nftables/index.php/Logging_traffic\n if got, want := logExpr.Key, uint32((1<<unix.NFTA_LOG_PREFIX)|(1<<unix.NFTA_LOG_LEVEL)); got != want {\n t.Fatalf(\"unexpected *expr.Log key: got %d, want %d\", got, want)\n }\n if got, want := string(logExpr.Data), \"LOG INPUT\"; got != want {\n t.Fatalf(\"unexpected *expr.Log data: got %s, want %s\", got, want)\n }\n if got, want := logExpr.Level, expr.LogLevelWarning; got != want {\n t.Fatalf(\"unexpected *expr.Log level: got %d, want %d\", got, want)\n }\n}\n\nfunc TestAddCounter(t *testing.T) {\n // The want byte sequences come from stracing nft(8), e.g.:\n // strace -f -v -x -s 2048 -eraw=sendto nft add table ip nat\n //\n // The nft(8) command sequence was taken from:\n // https://wiki.nftables.org/wiki-nftables/index.php/Performing_Network_Address_Translation_(NAT)\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft add counter ip filter fwded\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0a\\x00\\x02\\x00\\x66\\x77\\x64\\x65\\x64\\x00\\x00\\x00\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x01\\x1c\\x00\\x04\\x80\\x0c\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x0c\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"),\n // nft add rule ip filter forward counter name fwded\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0c\\x00\\x02\\x00\\x66\\x6f\\x72\\x77\\x61\\x72\\x64\\x00\\x2c\\x00\\x04\\x80\\x28\\x00\\x01\\x80\\x0b\\x00\\x01\\x00\\x6f\\x62\\x6a\\x72\\x65\\x66\\x00\\x00\\x18\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x09\\x00\\x02\\x00\\x66\\x77\\x64\\x65\\x64\\x00\\x00\\x00\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.AddObj(&nftables.CounterObj{\n Table: &nftables.Table{Name: \"filter\", Family: nftables.TableFamilyIPv4},\n Name: \"fwded\",\n Bytes: 0,\n Packets: 0,\n })\n\n c.AddRule(&nftables.Rule{\n Table: &nftables.Table{Name: \"filter\", Family: nftables.TableFamilyIPv4},\n Chain: &nftables.Chain{Name: \"forward\", Type: nftables.ChainTypeFilter},\n Exprs: []expr.Any{\n &expr.Objref{\n Type: 1,\n Name: \"fwded\",\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestDeleteCounter(t *testing.T) {\n // The want byte sequences come from stracing nft(8), e.g.:\n // strace -f -v -x -s 2048 -eraw=sendto nft add table ip nat\n //\n // The nft(8) command sequence was taken from:\n // https://wiki.nftables.org/wiki-nftables/index.php/Performing_Network_Address_Translation_(NAT)\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft add counter ip filter fwded\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0a\\x00\\x02\\x00\\x66\\x77\\x64\\x65\\x64\\x00\\x00\\x00\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x01\\x1c\\x00\\x04\\x80\\x0c\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x0c\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"),\n // nft delete counter ip filter fwded\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0a\\x00\\x02\\x00\\x66\\x77\\x64\\x65\\x64\\x00\\x00\\x00\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x01\\x04\\x00\\x04\\x80\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.AddObj(&nftables.CounterObj{\n Table: &nftables.Table{Name: \"filter\", Family: nftables.TableFamilyIPv4},\n Name: \"fwded\",\n Bytes: 0,\n Packets: 0,\n })\n\n c.DeleteObject(&nftables.CounterObj{\n Table: &nftables.Table{Name: \"filter\", Family: nftables.TableFamilyIPv4},\n Name: \"fwded\",\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestDelRule(t *testing.T) {\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft delete rule ipv4table ipv4chain-1 handle 9\n []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\\x31\\x00\\x0c\\x00\\x03\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x09\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.DelRule(&nftables.Rule{\n Table: &nftables.Table{Name: \"ipv4table\", Family: nftables.TableFamilyIPv4},\n Chain: &nftables.Chain{Name: \"ipv4chain-1\", Type: nftables.ChainTypeFilter},\n Handle: uint64(9),\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestLog(t *testing.T) {\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft add rule ipv4table ipv4chain-1 log prefix nftables\n []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\\x31\\x00\\x24\\x00\\x04\\x80\\x20\\x00\\x01\\x80\\x08\\x00\\x01\\x00\\x6c\\x6f\\x67\\x00\\x14\\x00\\x02\\x80\\x0d\\x00\\x02\\x00\\x6e\\x66\\x74\\x61\\x62\\x6c\\x65\\x73\\x00\\x00\\x00\\x00\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.AddRule(&nftables.Rule{\n Table: &nftables.Table{Name: \"ipv4table\", Family: nftables.TableFamilyIPv4},\n Chain: &nftables.Chain{Name: \"ipv4chain-1\", Type: nftables.ChainTypeFilter},\n Exprs: []expr.Any{\n &expr.Log{\n Key: 1 << unix.NFTA_LOG_PREFIX,\n Data: []byte(\"nftables\"),\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestTProxy(t *testing.T) {\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft add rule filter divert ip protocol tcp tproxy to :50080\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0b\\x00\\x02\\x00\\x64\\x69\\x76\\x65\\x72\\x74\\x00\\x00\\xb4\\x00\\x04\\x80\\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\\x01\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x09\\x08\\x00\\x04\\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\\x2c\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x69\\x6d\\x6d\\x65\\x64\\x69\\x61\\x74\\x65\\x00\\x00\\x00\\x18\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x0c\\x00\\x02\\x80\\x06\\x00\\x01\\x00\\xc3\\xa0\\x00\\x00\\x24\\x00\\x01\\x80\\x0b\\x00\\x01\\x00\\x74\\x70\\x72\\x6f\\x78\\x79\\x00\\x00\\x14\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x02\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x01\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.AddRule(&nftables.Rule{\n Table: &nftables.Table{Name: \"filter\", Family: nftables.TableFamilyIPv4},\n Chain: &nftables.Chain{\n Name: \"divert\",\n Type: nftables.ChainTypeFilter,\n Hooknum: nftables.ChainHookPrerouting,\n Priority: nftables.ChainPriorityRef(-150),\n },\n Exprs: []expr.Any{\n // [ payload load 1b @ network header + 9 => reg 1 ]\n &expr.Payload{DestRegister: 1, Base: expr.PayloadBaseNetworkHeader, Offset: 9, Len: 1},\n // [ cmp eq reg 1 0x00000006 ]\n &expr.Cmp{Op: expr.CmpOpEq, Register: 1, Data: []byte{unix.IPPROTO_TCP}},\n // [ immediate reg 1 0x0000a0c3 ]\n &expr.Immediate{Register: 1, Data: binaryutil.BigEndian.PutUint16(50080)},\n // [ tproxy ip port reg 1 ]\n &expr.TProxy{\n Family: byte(nftables.TableFamilyIPv4),\n TableFamily: byte(nftables.TableFamilyIPv4),\n RegPort: 1,\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestCt(t *testing.T) {\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // sudo nft add rule ipv4table ipv4chain-5 ct mark 123 counter\n []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\\x35\\x00\\x24\\x00\\x04\\x80\\x20\\x00\\x01\\x80\\x07\\x00\\x01\\x00\\x63\\x74\\x00\\x00\\x14\\x00\\x02\\x80\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x03\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.AddRule(&nftables.Rule{\n Table: &nftables.Table{Name: \"ipv4table\", Family: nftables.TableFamilyIPv4},\n Chain: &nftables.Chain{\n Name: \"ipv4chain-5\",\n },\n Exprs: []expr.Any{\n // [ ct load mark => reg 1 ]\n &expr.Ct{\n Key: unix.NFT_CT_MARK,\n Register: 1,\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestCtSet(t *testing.T) {\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // sudo nft add rule filter forward ct mark set 1\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0c\\x00\\x02\\x00\\x66\\x6f\\x72\\x77\\x61\\x72\\x64\\x00\\x50\\x00\\x04\\x80\\x2c\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x69\\x6d\\x6d\\x65\\x64\\x69\\x61\\x74\\x65\\x00\\x00\\x00\\x18\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x0c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x01\\x00\\x00\\x00\\x20\\x00\\x01\\x80\\x07\\x00\\x01\\x00\\x63\\x74\\x00\\x00\\x14\\x00\\x02\\x80\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x03\\x08\\x00\\x04\\x00\\x00\\x00\\x00\\x01\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.AddRule(&nftables.Rule{\n Table: &nftables.Table{Name: \"filter\", Family: nftables.TableFamilyIPv4},\n Chain: &nftables.Chain{\n Name: \"forward\",\n },\n Exprs: []expr.Any{\n // [ immediate reg 1 0x00000001 ]\n &expr.Immediate{\n Register: 1,\n Data: binaryutil.NativeEndian.PutUint32(1),\n },\n // [ ct set mark with reg 1 ]\n &expr.Ct{\n Key: expr.CtKeyMARK,\n Register: 1,\n SourceRegister: true,\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestCtStat(t *testing.T) {\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // ct state established,related accept\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0b\\x00\\x02\\x00\\x6f\\x75\\x74\\x70\\x75\\x74\\x00\\x00\\xc4\\x00\\x04\\x80\\x20\\x00\\x01\\x80\\x07\\x00\\x01\\x00\\x63\\x74\\x00\\x00\\x14\\x00\\x02\\x80\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x44\\x00\\x01\\x80\\x0c\\x00\\x01\\x00\\x62\\x69\\x74\\x77\\x69\\x73\\x65\\x00\\x34\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x04\\x0c\\x00\\x04\\x80\\x08\\x00\\x01\\x00\\x06\\x00\\x00\\x00\\x0c\\x00\\x05\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\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\\x01\\x0c\\x00\\x03\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x30\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x69\\x6d\\x6d\\x65\\x64\\x69\\x61\\x74\\x65\\x00\\x00\\x00\\x1c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x10\\x00\\x02\\x80\\x0c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.AddRule(&nftables.Rule{\n Table: &nftables.Table{Name: \"filter\", Family: nftables.TableFamilyIPv4},\n Chain: &nftables.Chain{\n Name: \"output\",\n },\n Exprs: []expr.Any{\n &expr.Ct{Register: 1, SourceRegister: false, Key: expr.CtKeySTATE},\n &expr.Bitwise{\n SourceRegister: 1,\n DestRegister: 1,\n Len: 4,\n Mask: binaryutil.NativeEndian.PutUint32(expr.CtStateBitESTABLISHED | expr.CtStateBitRELATED),\n Xor: binaryutil.NativeEndian.PutUint32(0),\n },\n &expr.Cmp{Op: expr.CmpOpNeq, Register: 1, Data: []byte{0, 0, 0, 0}},\n &expr.Verdict{Kind: expr.VerdictAccept},\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestAddRuleWithPosition(t *testing.T) {\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft add rule ip ipv4table ipv4chain-1 position 2 ip version 6\n []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\\x31\\x00\\xa8\\x00\\x04\\x80\\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\\x01\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x00\\x08\\x00\\x04\\x00\\x00\\x00\\x00\\x01\\x44\\x00\\x01\\x80\\x0c\\x00\\x01\\x00\\x62\\x69\\x74\\x77\\x69\\x73\\x65\\x00\\x34\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x01\\x0c\\x00\\x04\\x80\\x05\\x00\\x01\\x00\\xf0\\x00\\x00\\x00\\x0c\\x00\\x05\\x80\\x05\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\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\\x60\\x00\\x00\\x00\\x0c\\x00\\x06\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.AddRule(&nftables.Rule{\n Position: 2,\n Table: &nftables.Table{Name: \"ipv4table\", Family: nftables.TableFamilyIPv4},\n Chain: &nftables.Chain{\n Name: \"ipv4chain-1\",\n Type: nftables.ChainTypeFilter,\n Hooknum: nftables.ChainHookPrerouting,\n Priority: nftables.ChainPriorityRef(0),\n },\n\n Exprs: []expr.Any{\n // [ payload load 1b @ network header + 0 => reg 1 ]\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseNetworkHeader,\n Offset: 0, // Offset for a transport protocol header\n Len: 1, // 1 bytes for port\n },\n // [ bitwise reg 1 = (reg=1 & 0x000000f0 ) ^ 0x00000000 ]\n &expr.Bitwise{\n SourceRegister: 1,\n DestRegister: 1,\n Len: 1,\n Mask: []byte{0xf0},\n Xor: []byte{0x0},\n },\n // [ cmp eq reg 1 0x00000060 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{(0x6 << 4)},\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestLastingConnection(t *testing.T) {\n testdialerr := errors.New(\"test dial sentinel error\")\n dialCount := 0\n c, err := nftables.New(\n nftables.AsLasting(),\n nftables.WithTestDial(func(req []netlink.Message) ([]netlink.Message, error) {\n dialCount++\n return nil, testdialerr\n }))\n if err != nil {\n t.Errorf(\"creating lasting netlink connection failed %v\", err)\n return\n }\n defer func() {\n if err := c.CloseLasting(); err != nil {\n t.Errorf(\"closing lasting netlink connection failed %v\", err)\n }\n }()\n\n _, err = c.ListTables()\n if !errors.Is(err, testdialerr) {\n t.Errorf(\"non-testdialerr error returned from TestDial %v\", err)\n return\n }\n if dialCount != 1 {\n t.Errorf(\"internal test error with TestDial invocations %v\", dialCount)\n return\n }\n\n // While a lasting netlink connection is open, replacing TestDial must be\n // ineffective as there is no need to dial again and activating a new\n // TestDial function. The newly set TestDial function must be getting\n // ignored.\n c.TestDial = func(req []netlink.Message) ([]netlink.Message, error) {\n dialCount--\n return nil, errors.New(\"transient netlink connection error\")\n }\n _, err = c.ListTables()\n if !errors.Is(err, testdialerr) {\n t.Errorf(\"non-testdialerr error returned from TestDial %v\", err)\n return\n }\n if dialCount != 2 {\n t.Errorf(\"internal test error with TestDial invocations %v\", dialCount)\n return\n }\n\n for i := 0; i < 2; i++ {\n err = c.CloseLasting()\n if err != nil {\n t.Errorf(\"closing lasting netlink connection failed in attempt no. %d: %v\", i, err)\n return\n }\n }\n _, err = c.ListTables()\n if errors.Is(err, testdialerr) {\n t.Error(\"testdialerr error returned from TestDial when expecting different error\")\n return\n }\n if dialCount != 1 {\n t.Errorf(\"internal test error with TestDial invocations %v\", dialCount)\n return\n }\n\n // fall into defer'ed second CloseLasting which must not cause any errors.\n}\n\nfunc TestListChains(t *testing.T) {\n polDrop := nftables.ChainPolicyDrop\n polAcpt := nftables.ChainPolicyAccept\n reply := [][]byte{\n // chain input { type filter hook input priority filter; policy accept; }\n []byte(\"\\x70\\x00\\x00\\x00\\x03\\x0a\\x02\\x00\\x00\\x00\\x00\\x00\\xb8\\x76\\x02\\x00\\x01\\x00\\x00\\xc3\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0c\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x01\\x0a\\x00\\x03\\x00\\x69\\x6e\\x70\\x75\\x74\\x00\\x00\\x00\\x14\\x00\\x04\\x00\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x08\\x00\\x05\\x00\\x00\\x00\\x00\\x01\\x0b\\x00\\x07\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x0a\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x06\\x00\\x00\\x00\\x00\\x00\"),\n // chain forward { type filter hook forward priority filter; policy drop; }\n []byte(\"\\x70\\x00\\x00\\x00\\x03\\x0a\\x02\\x00\\x00\\x00\\x00\\x01\\xb8\\x76\\x02\\x00\\x01\\x00\\x00\\xc3\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0c\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x0c\\x00\\x03\\x00\\x66\\x6f\\x72\\x77\\x61\\x72\\x64\\x00\\x14\\x00\\x04\\x00\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x02\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x08\\x00\\x05\\x00\\x00\\x00\\x00\\x00\\x0b\\x00\\x07\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x0a\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x06\\x00\\x00\\x00\\x00\\x00\"),\n // chain output { type filter hook output priority filter; policy accept; }\n []byte(\"\\x70\\x00\\x00\\x00\\x03\\x0a\\x02\\x00\\x00\\x00\\x00\\x02\\xb8\\x76\\x02\\x00\\x01\\x00\\x00\\xc3\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0c\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x03\\x0b\\x00\\x03\\x00\\x6f\\x75\\x74\\x70\\x75\\x74\\x00\\x00\\x14\\x00\\x04\\x00\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x03\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x08\\x00\\x05\\x00\\x00\\x00\\x00\\x01\\x0b\\x00\\x07\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x0a\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x06\\x00\\x00\\x00\\x00\\x00\"),\n // chain undef { counter packets 56235 bytes 175436495 return }\n []byte(\"\\x40\\x00\\x00\\x00\\x03\\x0a\\x02\\x00\\x00\\x00\\x00\\x03\\xb8\\x76\\x02\\x00\\x01\\x00\\x00\\xc3\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0c\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x04\\x0a\\x00\\x03\\x00\\x75\\x6e\\x64\\x65\\x66\\x00\\x00\\x00\\x08\\x00\\x06\\x00\\x00\\x00\\x00\\x01\"),\n []byte(\"\\x14\\x00\\x00\\x00\\x03\\x00\\x02\\x00\\x00\\x00\\x00\\x04\\xb8\\x76\\x02\\x00\\x00\\x00\\x00\\x00\"),\n }\n\n want := []*nftables.Chain{\n {\n Name: \"input\",\n Hooknum: nftables.ChainHookInput,\n Priority: nftables.ChainPriorityFilter,\n Type: nftables.ChainTypeFilter,\n Policy: &polAcpt,\n },\n {\n Name: \"forward\",\n Hooknum: nftables.ChainHookForward,\n Priority: nftables.ChainPriorityFilter,\n Type: nftables.ChainTypeFilter,\n Policy: &polDrop,\n },\n {\n Name: \"output\",\n Hooknum: nftables.ChainHookOutput,\n Priority: nftables.ChainPriorityFilter,\n Type: nftables.ChainTypeFilter,\n Policy: &polAcpt,\n },\n {\n Name: \"undef\",\n Hooknum: nil,\n Priority: nil,\n Policy: nil,\n },\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n msgReply := make([]netlink.Message, len(reply))\n for i, r := range reply {\n nm := &netlink.Message{}\n nm.UnmarshalBinary(r)\n nm.Header.Sequence = req[0].Header.Sequence\n nm.Header.PID = req[0].Header.PID\n msgReply[i] = *nm\n }\n return msgReply, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n chains, err := c.ListChains()\n if err != nil {\n t.Errorf(\"error returned from TestDial %v\", err)\n return\n }\n\n if len(chains) != len(want) {\n t.Errorf(\"number of chains %d != number of want %d\", len(chains), len(want))\n return\n }\n\n validate := func(got interface{}, want interface{}, name string, index int) {\n if got != want {\n t.Errorf(\"chain %d: chain %s mismatch, got %v want %v\", index, name, got, want)\n }\n }\n\n for i, chain := range chains {\n validate(chain.Name, want[i].Name, \"name\", i)\n if want[i].Hooknum != nil && chain.Hooknum != nil {\n validate(*chain.Hooknum, *want[i].Hooknum, \"hooknum value\", i)\n } else {\n validate(chain.Hooknum, want[i].Hooknum, \"hooknum pointer\", i)\n }\n if want[i].Priority != nil && chain.Priority != nil {\n validate(*chain.Priority, *want[i].Priority, \"priority value\", i)\n } else {\n validate(chain.Priority, want[i].Priority, \"priority pointer\", i)\n }\n validate(chain.Type, want[i].Type, \"type\", i)\n\n if want[i].Policy != nil && chain.Policy != nil {\n validate(*chain.Policy, *want[i].Policy, \"policy value\", i)\n } else {\n validate(chain.Policy, want[i].Policy, \"policy pointer\", i)\n }\n }\n\n}\n\nfunc TestAddChain(t *testing.T) {\n tests := []struct {\n name string\n chain *nftables.Chain\n want [][]byte\n }{\n {\n name: \"Base chain\",\n chain: &nftables.Chain{\n Name: \"base-chain\",\n Hooknum: nftables.ChainHookPrerouting,\n Priority: nftables.ChainPriorityRef(0),\n Type: nftables.ChainTypeFilter,\n },\n want: [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain ip filter base-chain { type filter hook prerouting priority 0 \\; }\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x03\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\x14\\x00\\x04\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x0b\\x00\\x07\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n },\n },\n {\n name: \"Regular chain\",\n chain: &nftables.Chain{\n Name: \"regular-chain\",\n },\n want: [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain ip filter regular-chain\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x12\\x00\\x03\\x00\\x72\\x65\\x67\\x75\\x6c\\x61\\x72\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\x00\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n },\n },\n }\n\n for _, tt := range tests {\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(tt.want[idx]) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n got := b\n if !bytes.Equal(got, tt.want[idx]) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(tt.want[idx])))\n }\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n tt.chain.Table = filter\n c.AddChain(tt.chain)\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n }\n}\n\nfunc TestDelChain(t *testing.T) {\n tests := []struct {\n name string\n chain *nftables.Chain\n want [][]byte\n }{\n {\n name: \"Base chain\",\n chain: &nftables.Chain{\n Name: \"base-chain\",\n Hooknum: nftables.ChainHookPrerouting,\n Priority: nftables.ChainPriorityRef(0),\n Type: nftables.ChainTypeFilter,\n },\n want: [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft delete chain ip filter base-chain\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x03\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n },\n },\n {\n name: \"Regular chain\",\n chain: &nftables.Chain{\n Name: \"regular-chain\",\n },\n want: [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft delete chain ip filter regular-chain\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x12\\x00\\x03\\x00\\x72\\x65\\x67\\x75\\x6c\\x61\\x72\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\x00\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n },\n },\n }\n\n for _, tt := range tests {\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(tt.want[idx]) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n got := b\n if !bytes.Equal(got, tt.want[idx]) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(tt.want[idx])))\n }\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n tt.chain.Table = &nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n }\n c.DelChain(tt.chain)\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n }\n}\nfunc TestGetObjReset(t *testing.T) {\n // The want byte sequences come from stracing nft(8), e.g.:\n // strace -f -v -x -s 2048 -eraw=sendto nft list chain ip filter forward\n\n want := [][]byte{\n []byte{0x2, 0x0, 0x0, 0x0, 0xb, 0x0, 0x1, 0x0, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x0, 0x0, 0xa, 0x0, 0x2, 0x0, 0x66, 0x77, 0x64, 0x65, 0x64, 0x0, 0x0, 0x0, 0x8, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x1},\n }\n\n // The reply messages come from adding log.Printf(\"msgs: %#v\", msgs) to\n // (*github.com/mdlayher/netlink/Conn).receive\n reply := [][]netlink.Message{\n nil,\n []netlink.Message{netlink.Message{Header: netlink.Header{Length: 0x64, Type: 0xa12, Flags: 0x802, Sequence: 0x9acb0443, PID: 0xde9}, Data: []uint8{0x2, 0x0, 0x0, 0x10, 0xb, 0x0, 0x1, 0x0, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x0, 0x0, 0xa, 0x0, 0x2, 0x0, 0x66, 0x77, 0x64, 0x65, 0x64, 0x0, 0x0, 0x0, 0x8, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x1, 0x8, 0x0, 0x5, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1c, 0x0, 0x4, 0x0, 0xc, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x61, 0xc, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9, 0xc, 0x0, 0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}}},\n []netlink.Message{netlink.Message{Header: netlink.Header{Length: 0x14, Type: 0x3, Flags: 0x2, Sequence: 0x9acb0443, PID: 0xde9}, Data: []uint8{0x0, 0x0, 0x0, 0x0}}},\n []netlink.Message{netlink.Message{Header: netlink.Header{Length: 36, Type: netlink.Error, Flags: 0x100, Sequence: 0x9acb0443, PID: 0xde9}, Data: []uint8{0, 0, 0, 0, 88, 0, 0, 0, 12, 10, 5, 4, 143, 109, 199, 146, 236, 9, 0, 0}}},\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n rep := reply[0]\n reply = reply[1:]\n return rep, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n filter := &nftables.Table{Name: \"filter\", Family: nftables.TableFamilyIPv4}\n obj, err := c.ResetObject(&nftables.CounterObj{\n Table: filter,\n Name: \"fwded\",\n })\n\n if err != nil {\n t.Fatal(err)\n }\n\n co, ok := obj.(*nftables.CounterObj)\n if !ok {\n t.Fatalf(\"unexpected type: got %T, want *nftables.CounterObj\", obj)\n }\n if got, want := co.Table.Name, filter.Name; got != want {\n t.Errorf(\"unexpected table name: got %q, want %q\", got, want)\n }\n if got, want := co.Table.Family, filter.Family; got != want {\n t.Errorf(\"unexpected table family: got %d, want %d\", got, want)\n }\n if got, want := co.Packets, uint64(9); got != want {\n t.Errorf(\"unexpected number of packets: got %d, want %d\", got, want)\n }\n if got, want := co.Bytes, uint64(1121); got != want {\n t.Errorf(\"unexpected number of bytes: got %d, want %d\", got, want)\n }\n}\n\nfunc TestObjAPI(t *testing.T) {\n if os.Getenv(\"TRAVIS\") == \"true\" {\n t.SkipNow()\n }\n\n // Create a new network namespace to test these operations,\n // and tear down the namespace at test completion.\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n\n // Clear all rules at the beginning + end of the test.\n c.FlushRuleset()\n defer c.FlushRuleset()\n\n table := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n tableOther := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"foo\",\n })\n\n chain := c.AddChain(&nftables.Chain{\n Name: \"chain\",\n Table: table,\n Type: nftables.ChainTypeFilter,\n Hooknum: nftables.ChainHookPostrouting,\n Priority: nftables.ChainPriorityFilter,\n })\n\n counter1 := c.AddObj(&nftables.CounterObj{\n Table: table,\n Name: \"fwded1\",\n Bytes: 1,\n Packets: 1,\n })\n\n counter2 := c.AddObj(&nftables.CounterObj{\n Table: table,\n Name: \"fwded2\",\n Bytes: 1,\n Packets: 1,\n })\n\n c.AddObj(&nftables.CounterObj{\n Table: tableOther,\n Name: \"fwdedOther\",\n Bytes: 0,\n Packets: 0,\n })\n\n c.AddRule(&nftables.Rule{\n Table: table,\n Chain: chain,\n Exprs: []expr.Any{\n &expr.Objref{\n Type: 1,\n Name: \"fwded1\",\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatalf(err.Error())\n }\n\n objs, err := c.GetObjects(table)\n\n if err != nil {\n t.Errorf(\"c.GetObjects(table) failed: %v failed\", err)\n }\n\n if got := len(objs); got != 2 {\n t.Fatalf(\"unexpected number of objects: got %d, want %d\", got, 2)\n }\n\n objsOther, err := c.GetObjects(tableOther)\n\n if err != nil {\n t.Errorf(\"c.GetObjects(tableOther) failed: %v failed\", err)\n }\n\n if got := len(objsOther); got != 1 {\n t.Fatalf(\"unexpected number of objects: got %d, want %d\", got, 1)\n }\n\n obj1, err := c.GetObject(counter1)\n\n if err != nil {\n t.Errorf(\"c.GetObject(counter1) failed: %v failed\", err)\n }\n\n rcounter1, ok := obj1.(*nftables.CounterObj)\n\n if !ok {\n t.Fatalf(\"unexpected type: got %T, want *nftables.CounterObj\", rcounter1)\n }\n\n if rcounter1.Name != \"fwded1\" {\n t.Fatalf(\"unexpected counter name: got %s, want %s\", rcounter1.Name, \"fwded1\")\n }\n\n obj2, err := c.GetObject(counter2)\n\n if err != nil {\n t.Errorf(\"c.GetObject(counter2) failed: %v failed\", err)\n }\n\n rcounter2, ok := obj2.(*nftables.CounterObj)\n\n if !ok {\n t.Fatalf(\"unexpected type: got %T, want *nftables.CounterObj\", rcounter2)\n }\n\n if rcounter2.Name != \"fwded2\" {\n t.Fatalf(\"unexpected counter name: got %s, want %s\", rcounter2.Name, \"fwded2\")\n }\n\n _, err = c.ResetObject(counter1)\n\n if err != nil {\n t.Errorf(\"c.ResetObjects(table) failed: %v failed\", err)\n }\n\n obj1, err = c.GetObject(counter1)\n\n if err != nil {\n t.Errorf(\"c.GetObject(counter1) failed: %v failed\", err)\n }\n\n if counter1 := obj1.(*nftables.CounterObj); counter1.Packets > 0 {\n t.Errorf(\"unexpected packets number: got %d, want %d\", counter1.Packets, 0)\n }\n\n obj2, err = c.GetObject(counter2)\n\n if err != nil {\n t.Errorf(\"c.GetObject(counter2) failed: %v failed\", err)\n }\n\n if counter2 := obj2.(*nftables.CounterObj); counter2.Packets != 1 {\n t.Errorf(\"unexpected packets number: got %d, want %d\", counter2.Packets, 1)\n }\n\n legacy, err := c.GetObj(counter1)\n\n if err != nil {\n t.Errorf(\"c.GetObj(counter1) failed: %v failed\", err)\n }\n\n if len(legacy) != 2 {\n t.Errorf(\"unexpected number of objects: got %d, want %d\", len(legacy), 2)\n }\n\n legacyReset, err := c.GetObjReset(counter1)\n\n if err != nil {\n t.Errorf(\"c.GetObjReset(counter1) failed: %v failed\", err)\n }\n\n if len(legacyReset) != 2 {\n t.Errorf(\"unexpected number of objects: got %d, want %d\", len(legacyReset), 2)\n }\n\n}\n\nfunc TestConfigureClamping(t *testing.T) {\n // The want byte sequences come from stracing nft(8), e.g.:\n // strace -f -v -x -s 2048 -eraw=sendto nft add table ip nat\n //\n // The nft(8) command sequence was taken from:\n // https://wiki.nftables.org/wiki-nftables/index.php/Mangle_TCP_options\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft flush ruleset\n []byte(\"\\x00\\x00\\x00\\x00\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain filter forward '{' type filter hook forward priority 0 \\; '}'\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0c\\x00\\x03\\x00\\x66\\x6f\\x72\\x77\\x61\\x72\\x64\\x00\\x14\\x00\\x04\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x02\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x0b\\x00\\x07\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\"),\n // nft add rule ip filter forward oifname uplink0 tcp flags syn tcp option maxseg size set rt mtu\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0c\\x00\\x02\\x00\\x66\\x6f\\x72\\x77\\x61\\x72\\x64\\x00\\xf0\\x01\\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\\x07\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x38\\x00\\x01\\x80\\x08\\x00\\x01\\x00\\x63\\x6d\\x70\\x00\\x2c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x18\\x00\\x03\\x80\\x14\\x00\\x01\\x00\\x75\\x70\\x6c\\x69\\x6e\\x6b\\x30\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\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\\x0d\\x08\\x00\\x04\\x00\\x00\\x00\\x00\\x01\\x44\\x00\\x01\\x80\\x0c\\x00\\x01\\x00\\x62\\x69\\x74\\x77\\x69\\x73\\x65\\x00\\x34\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x01\\x0c\\x00\\x04\\x80\\x05\\x00\\x01\\x00\\x02\\x00\\x00\\x00\\x0c\\x00\\x05\\x80\\x05\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\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\\x01\\x0c\\x00\\x03\\x80\\x05\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x20\\x00\\x01\\x80\\x07\\x00\\x01\\x00\\x72\\x74\\x00\\x00\\x14\\x00\\x02\\x80\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x03\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x40\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x62\\x79\\x74\\x65\\x6f\\x72\\x64\\x65\\x72\\x00\\x00\\x00\\x2c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x04\\x00\\x00\\x00\\x00\\x02\\x08\\x00\\x05\\x00\\x00\\x00\\x00\\x02\\x3c\\x00\\x01\\x80\\x0b\\x00\\x01\\x00\\x65\\x78\\x74\\x68\\x64\\x72\\x00\\x00\\x2c\\x00\\x02\\x80\\x08\\x00\\x07\\x00\\x00\\x00\\x00\\x01\\x05\\x00\\x02\\x00\\x02\\x00\\x00\\x00\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x02\\x08\\x00\\x04\\x00\\x00\\x00\\x00\\x02\\x08\\x00\\x06\\x00\\x00\\x00\\x00\\x01\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n forward := c.AddChain(&nftables.Chain{\n Name: \"forward\",\n Table: filter,\n Type: nftables.ChainTypeFilter,\n Hooknum: nftables.ChainHookForward,\n Priority: nftables.ChainPriorityFilter,\n })\n\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: forward,\n Exprs: []expr.Any{\n // [ meta load oifname => reg 1 ]\n &expr.Meta{Key: expr.MetaKeyOIFNAME, Register: 1},\n // [ cmp eq reg 1 0x30707070 0x00000000 0x00000000 0x00000000 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: ifname(\"uplink0\"),\n },\n\n // [ meta load l4proto => reg 1 ]\n &expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1},\n // [ cmp eq reg 1 0x00000006 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{unix.IPPROTO_TCP},\n },\n\n // [ payload load 1b @ transport header + 13 => reg 1 ]\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseTransportHeader,\n Offset: 13, // TODO\n Len: 1, // TODO\n },\n // [ bitwise reg 1 = (reg=1 & 0x00000002 ) ^ 0x00000000 ]\n &expr.Bitwise{\n DestRegister: 1,\n SourceRegister: 1,\n Len: 1,\n Mask: []byte{0x02},\n Xor: []byte{0x00},\n },\n // [ cmp neq reg 1 0x00000000 ]\n &expr.Cmp{\n Op: expr.CmpOpNeq,\n Register: 1,\n Data: []byte{0x00},\n },\n\n // [ rt load tcpmss => reg 1 ]\n &expr.Rt{\n Register: 1,\n Key: expr.RtTCPMSS,\n },\n // [ byteorder reg 1 = hton(reg 1, 2, 2) ]\n &expr.Byteorder{\n DestRegister: 1,\n SourceRegister: 1,\n Op: expr.ByteorderHton,\n Len: 2,\n Size: 2,\n },\n // [ exthdr write tcpopt reg 1 => 2b @ 2 + 2 ]\n &expr.Exthdr{\n SourceRegister: 1,\n Type: 2, // TODO\n Offset: 2,\n Len: 2,\n Op: expr.ExthdrOpTcpopt,\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestMatchPacketHeader(t *testing.T) {\n // The want byte sequences come from stracing nft(8), e.g.:\n // strace -f -v -x -s 2048 -eraw=sendto nft add table ip nat\n //\n // The nft(8) command sequence was adopted from:\n // https://wiki.nftables.org/wiki-nftables/index.php/Matching_packet_headers\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft flush ruleset\n []byte(\"\\x00\\x00\\x00\\x00\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain filter input '{' type filter hook forward priority filter \\; '}'\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0a\\x00\\x03\\x00\\x69\\x6e\\x70\\x75\\x74\\x00\\x00\\x00\\x14\\x00\\x04\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x0b\\x00\\x07\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\"),\n // nft add rule ip filter input tcp flags syn tcp option maxseg size 1-500 drop\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0a\\x00\\x02\\x00\\x69\\x6e\\x70\\x75\\x74\\x00\\x00\\x00\\xc4\\x01\\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\\x0d\\x08\\x00\\x04\\x00\\x00\\x00\\x00\\x01\\x44\\x00\\x01\\x80\\x0c\\x00\\x01\\x00\\x62\\x69\\x74\\x77\\x69\\x73\\x65\\x00\\x34\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x01\\x0c\\x00\\x04\\x80\\x05\\x00\\x01\\x00\\x02\\x00\\x00\\x00\\x0c\\x00\\x05\\x80\\x05\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\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\\x01\\x0c\\x00\\x03\\x80\\x05\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x44\\x00\\x01\\x80\\x0b\\x00\\x01\\x00\\x65\\x78\\x74\\x68\\x64\\x72\\x00\\x00\\x34\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x05\\x00\\x02\\x00\\x02\\x00\\x00\\x00\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x02\\x08\\x00\\x04\\x00\\x00\\x00\\x00\\x02\\x08\\x00\\x06\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x05\\x00\\x00\\x00\\x00\\x00\\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\\x05\\x0c\\x00\\x03\\x80\\x06\\x00\\x01\\x00\\x00\\x01\\x00\\x00\\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\\x03\\x0c\\x00\\x03\\x80\\x06\\x00\\x01\\x00\\x01\\xf4\\x00\\x00\\x30\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x69\\x6d\\x6d\\x65\\x64\\x69\\x61\\x74\\x65\\x00\\x00\\x00\\x1c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x10\\x00\\x02\\x80\\x0c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n input := c.AddChain(&nftables.Chain{\n Name: \"input\",\n Table: filter,\n Type: nftables.ChainTypeFilter,\n Hooknum: nftables.ChainHookInput,\n Priority: nftables.ChainPriorityFilter,\n })\n\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: input,\n Exprs: []expr.Any{\n // [ meta load l4proto => reg 1 ]\n &expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1},\n // [ cmp eq reg 1 0x00000006 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{unix.IPPROTO_TCP},\n },\n\n // [ payload load 1b @ transport header + 13 => reg 1 ]\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseTransportHeader,\n Offset: 13, // TODO\n Len: 1, // TODO\n },\n // [ bitwise reg 1 = (reg=1 & 0x00000002 ) ^ 0x00000000 ]\n &expr.Bitwise{\n DestRegister: 1,\n SourceRegister: 1,\n Len: 1,\n Mask: []byte{0x02},\n Xor: []byte{0x00},\n },\n // [ cmp neq reg 1 0x00000000 ]\n &expr.Cmp{\n Op: expr.CmpOpNeq,\n Register: 1,\n Data: []byte{0x00},\n },\n\n // [ exthdr load tcpopt 2b @ 2 + 2 => reg 1 ]\n &expr.Exthdr{\n DestRegister: 1,\n Type: 2, // TODO\n Offset: 2,\n Len: 2,\n Op: expr.ExthdrOpTcpopt,\n },\n\n // [ cmp gte reg 1 0x00000100 ]\n &expr.Cmp{\n Op: expr.CmpOpGte,\n Register: 1,\n Data: binaryutil.BigEndian.PutUint16(uint16(1)),\n },\n // [ cmp lte reg 1 0x0000f401 ]\n &expr.Cmp{\n Op: expr.CmpOpLte,\n Register: 1,\n Data: binaryutil.BigEndian.PutUint16(uint16(500)),\n },\n // [ immediate reg 0 drop ]\n &expr.Verdict{\n Kind: expr.VerdictDrop,\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestDropVerdict(t *testing.T) {\n // The want byte sequences come from stracing nft(8), e.g.:\n // strace -f -v -x -s 2048 -eraw=sendto nft add table ip nat\n //\n // The nft(8) command sequence was taken from:\n // https://wiki.nftables.org/wiki-nftables/index.php/Mangle_TCP_options\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft flush ruleset\n []byte(\"\\x00\\x00\\x00\\x00\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain filter forward '{' type filter hook forward priority 0 \\; '}'\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0c\\x00\\x03\\x00\\x66\\x6f\\x72\\x77\\x61\\x72\\x64\\x00\\x14\\x00\\x04\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x02\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x0b\\x00\\x07\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\"),\n // nft add rule filter forward tcp dport 1234 drop\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0c\\x00\\x02\\x00\\x66\\x6f\\x72\\x77\\x61\\x72\\x64\\x00\\xe4\\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\\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\\x06\\x00\\x01\\x00\\x04\\xd2\\x00\\x00\\x30\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x69\\x6d\\x6d\\x65\\x64\\x69\\x61\\x74\\x65\\x00\\x00\\x00\\x1c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x10\\x00\\x02\\x80\\x0c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n forward := c.AddChain(&nftables.Chain{\n Name: \"forward\",\n Table: filter,\n Type: nftables.ChainTypeFilter,\n Hooknum: nftables.ChainHookForward,\n Priority: nftables.ChainPriorityFilter,\n })\n\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: forward,\n Exprs: []expr.Any{\n // [ meta load l4proto => reg 1 ]\n &expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1},\n // [ cmp eq reg 1 0x00000006 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{unix.IPPROTO_TCP},\n },\n\n // [ payload load 2b @ transport header + 2 => reg 1 ]\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseTransportHeader,\n Offset: 2,\n Len: 2,\n },\n // [ cmp eq reg 1 0x0000d204 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{0x04, 0xd2},\n },\n // [ immediate reg 0 drop ]\n &expr.Verdict{\n Kind: expr.VerdictDrop,\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestCreateUseAnonymousSet(t *testing.T) {\n // The want byte sequences come from stracing nft(8), e.g.:\n // strace -f -v -x -s 2048 -eraw=sendto nft add table ip nat\n //\n // The nft(8) command sequence was taken from:\n // https://wiki.nftables.org/wiki-nftables/index.php/Mangle_TCP_options\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft flush ruleset\n []byte(\"\\x00\\x00\\x00\\x00\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // Create anonymous set with key len of 2 bytes and data len of 0 bytes\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0c\\x00\\x02\\x00\\x5f\\x5f\\x73\\x65\\x74\\x25\\x64\\x00\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x03\\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\\x02\\x0a\\x00\\x0d\\x00\\x00\\x04\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // Assign the two values to the aforementioned anonymous set\n []byte(\"\\x02\\x00\\x00\\x00\\x0c\\x00\\x02\\x00\\x5f\\x5f\\x73\\x65\\x74\\x25\\x64\\x00\\x08\\x00\\x04\\x00\\x00\\x00\\x00\\x01\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x24\\x00\\x03\\x80\\x10\\x00\\x01\\x80\\x0c\\x00\\x01\\x80\\x06\\x00\\x01\\x00\\x00\\x45\\x00\\x00\\x10\\x00\\x02\\x80\\x0c\\x00\\x01\\x80\\x06\\x00\\x01\\x00\\x04\\x8b\\x00\\x00\"),\n // nft add rule filter forward tcp dport {69, 1163} drop\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0c\\x00\\x02\\x00\\x66\\x6f\\x72\\x77\\x61\\x72\\x64\\x00\\xe8\\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\\x30\\x00\\x01\\x80\\x0b\\x00\\x01\\x00\\x6c\\x6f\\x6f\\x6b\\x75\\x70\\x00\\x00\\x20\\x00\\x02\\x80\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x01\\x0c\\x00\\x01\\x00\\x5f\\x5f\\x73\\x65\\x74\\x25\\x64\\x00\\x08\\x00\\x04\\x00\\x00\\x00\\x00\\x01\\x30\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x69\\x6d\\x6d\\x65\\x64\\x69\\x61\\x74\\x65\\x00\\x00\\x00\\x1c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x10\\x00\\x02\\x80\\x0c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n set := &nftables.Set{\n Anonymous: true,\n Constant: true,\n Table: filter,\n KeyType: nftables.TypeInetService,\n }\n\n if err := c.AddSet(set, []nftables.SetElement{\n {Key: binaryutil.BigEndian.PutUint16(69)},\n {Key: binaryutil.BigEndian.PutUint16(1163)},\n }); err != nil {\n t.Errorf(\"c.AddSet() failed: %v\", err)\n }\n\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: &nftables.Chain{Name: \"forward\", Type: nftables.ChainTypeFilter},\n Exprs: []expr.Any{\n // [ meta load l4proto => reg 1 ]\n &expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1},\n // [ cmp eq reg 1 0x00000006 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{unix.IPPROTO_TCP},\n },\n\n // [ payload load 2b @ transport header + 2 => reg 1 ]\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseTransportHeader,\n Offset: 2,\n Len: 2,\n },\n // [ lookup reg 1 set __set%d ]\n &expr.Lookup{\n SourceRegister: 1,\n SetName: set.Name,\n SetID: set.ID,\n },\n // [ immediate reg 0 drop ]\n &expr.Verdict{\n Kind: expr.VerdictDrop,\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestCappedErrMsgOnSets(t *testing.T) {\n c, newNS := openSystemNFTConn(t)\n c, err := nftables.New(nftables.WithNetNSFd(int(newNS)), nftables.AsLasting())\n if err != nil {\n t.Fatalf(\"nftables.New() failed: %v\", err)\n }\n defer cleanupSystemNFTConn(t, newNS)\n c.FlushRuleset()\n defer c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n if err := c.Flush(); err != nil {\n t.Errorf(\"failed adding table: %v\", err)\n }\n tables, err := c.ListTablesOfFamily(nftables.TableFamilyIPv4)\n if err != nil {\n t.Errorf(\"failed to list IPv4 tables: %v\", err)\n }\n\n for _, t := range tables {\n if t.Name == \"filter\" {\n filter = t\n break\n }\n }\n\n ifSet := &nftables.Set{\n Table: filter,\n Name: \"if_set\",\n KeyType: nftables.TypeIFName,\n }\n if err := c.AddSet(ifSet, nil); err != nil {\n t.Errorf(\"c.AddSet(ifSet) failed: %v\", err)\n }\n if err := c.Flush(); err != nil {\n t.Errorf(\"failed adding set ifSet: %v\", err)\n }\n ifSet, err = c.GetSetByName(filter, \"if_set\")\n if err != nil {\n t.Fatalf(\"failed getting set by name: %v\", err)\n }\n\n elems, err := c.GetSetElements(ifSet)\n if err != nil {\n t.Errorf(\"failed getting set elements (ifSet): %v\", err)\n }\n\n if got, want := len(elems), 0; got != want {\n t.Errorf(\"first GetSetElements(ifSet) call len not equal: got %d, want %d\", got, want)\n }\n\n elements := []nftables.SetElement{\n {Key: []byte(\"012345678912345\\x00\")},\n }\n if err := c.SetAddElements(ifSet, elements); err != nil {\n t.Errorf(\"adding SetElements(ifSet) failed: %v\", err)\n }\n if err := c.Flush(); err != nil {\n t.Errorf(\"failed adding set elements ifSet: %v\", err)\n }\n\n elems, err = c.GetSetElements(ifSet)\n if err != nil {\n t.Fatalf(\"failed getting set elements (ifSet): %v\", err)\n }\n\n if got, want := len(elems), 1; got != want {\n t.Fatalf(\"second GetSetElements(ifSet) call len not equal: got %d, want %d\", got, want)\n }\n\n if got, want := elems, elements; !reflect.DeepEqual(elems, elements) {\n t.Errorf(\"SetElements(ifSet) not equal: got %v, want %v\", got, want)\n }\n}\n\nfunc TestCreateUseNamedSet(t *testing.T) {\n // Create a new network namespace to test these operations,\n // and tear down the namespace at test completion.\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n // Clear all rules at the beginning + end of the test.\n c.FlushRuleset()\n defer c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n portSet := &nftables.Set{\n Table: filter,\n Name: \"test\",\n KeyType: nftables.TypeInetService,\n }\n if err := c.AddSet(portSet, nil); err != nil {\n t.Errorf(\"c.AddSet(portSet) failed: %v\", err)\n }\n if err := c.SetAddElements(portSet, []nftables.SetElement{{Key: binaryutil.BigEndian.PutUint16(22)}}); err != nil {\n t.Errorf(\"c.SetVal(portSet) failed: %v\", err)\n }\n\n ipSet := &nftables.Set{\n Table: filter,\n Name: \"IPs_4_dayz\",\n KeyType: nftables.TypeIPAddr,\n }\n if err := c.AddSet(ipSet, []nftables.SetElement{{Key: []byte(net.ParseIP(\"192.168.1.64\").To4())}}); err != nil {\n t.Errorf(\"c.AddSet(ipSet) failed: %v\", err)\n }\n if err := c.SetAddElements(ipSet, []nftables.SetElement{{Key: []byte(net.ParseIP(\"192.168.1.42\").To4())}}); err != nil {\n t.Errorf(\"c.SetVal(ipSet) failed: %v\", err)\n }\n if err := c.Flush(); err != nil {\n t.Errorf(\"c.Flush() failed: %v\", err)\n }\n\n sets, err := c.GetSets(filter)\n if err != nil {\n t.Errorf(\"c.GetSets() failed: %v\", err)\n }\n if len(sets) != 2 {\n t.Fatalf(\"len(sets) = %d, want 2\", len(sets))\n }\n if sets[0].Name != \"test\" {\n t.Errorf(\"set[0].Name = %q, want test\", sets[0].Name)\n }\n if sets[1].Name != \"IPs_4_dayz\" {\n t.Errorf(\"set[1].Name = %q, want IPs_4_dayz\", sets[1].Name)\n }\n}\n\nfunc TestIP6SetAddElements(t *testing.T) {\n\n // Create a new network namespace to test these operations,\n // and tear down the namespace at test completion.\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n // Clear all rules at the beginning + end of the test.\n c.FlushRuleset()\n defer c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv6,\n Name: \"filter\",\n })\n portSet := &nftables.Set{\n Table: filter,\n Name: \"ports\",\n KeyType: nftables.TypeInetService,\n }\n if err := c.AddSet(portSet, nil); err != nil {\n t.Errorf(\"c.AddSet(portSet) failed: %v\", err)\n }\n if err := c.SetAddElements(portSet, []nftables.SetElement{\n {Key: binaryutil.BigEndian.PutUint16(22)},\n {Key: binaryutil.BigEndian.PutUint16(80)},\n }); err != nil {\n t.Errorf(\"c.SetVal(portSet) failed: %v\", err)\n }\n\n if err := c.Flush(); err != nil {\n t.Errorf(\"c.Flush() failed: %v\", err)\n }\n\n sets, err := c.GetSets(filter)\n if err != nil {\n t.Errorf(\"c.GetSets() failed: %v\", err)\n }\n if len(sets) != 1 {\n t.Fatalf(\"len(sets) = %d, want 1\", len(sets))\n }\n\n elements, err := c.GetSetElements(sets[0])\n if err != nil {\n t.Errorf(\"c.GetSetElements(portSet) failed: %v\", err)\n }\n if len(elements) != 2 {\n t.Fatalf(\"len(portSetElements) = %d, want 2\", len(sets))\n }\n}\n\nfunc TestCreateUseCounterSet(t *testing.T) {\n // Create a new network namespace to test these operations,\n // and tear down the namespace at test completion.\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n // Clear all rules at the beginning + end of the test.\n c.FlushRuleset()\n defer c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n portSet := &nftables.Set{\n Table: filter,\n Name: \"test\",\n KeyType: nftables.TypeInetService,\n Counter: true,\n }\n if err := c.AddSet(portSet, nil); err != nil {\n t.Errorf(\"c.AddSet(portSet) failed: %v\", err)\n }\n if err := c.SetAddElements(portSet, []nftables.SetElement{{Key: binaryutil.BigEndian.PutUint16(22)}}); err != nil {\n t.Errorf(\"c.SetVal(portSet) failed: %v\", err)\n }\n\n if err := c.Flush(); err != nil {\n t.Errorf(\"c.Flush() failed: %v\", err)\n }\n\n sets, err := c.GetSets(filter)\n if err != nil {\n t.Errorf(\"c.GetSets() failed: %v\", err)\n }\n if len(sets) != 1 {\n t.Fatalf(\"len(sets) = %d, want 1\", len(sets))\n }\n if sets[0].Name != \"test\" {\n t.Errorf(\"set[0].Name = %q, want test\", sets[0].Name)\n }\n}\n\nfunc TestCreateDeleteNamedSet(t *testing.T) {\n // Create a new network namespace to test these operations,\n // and tear down the namespace at test completion.\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n // Clear all rules at the beginning + end of the test.\n c.FlushRuleset()\n defer c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n portSet := &nftables.Set{\n Table: filter,\n Name: \"test\",\n KeyType: nftables.TypeInetService,\n }\n if err := c.AddSet(portSet, nil); err != nil {\n t.Errorf(\"c.AddSet(portSet) failed: %v\", err)\n }\n if err := c.Flush(); err != nil {\n t.Errorf(\"c.Flush() failed: %v\", err)\n }\n\n c.DelSet(portSet)\n\n if err := c.Flush(); err != nil {\n t.Errorf(\"Second c.Flush() failed: %v\", err)\n }\n\n sets, err := c.GetSets(filter)\n if err != nil {\n t.Errorf(\"c.GetSets() failed: %v\", err)\n }\n if len(sets) != 0 {\n t.Fatalf(\"len(sets) = %d, want 0\", len(sets))\n }\n}\n\nfunc TestDeleteElementNamedSet(t *testing.T) {\n // Create a new network namespace to test these operations,\n // and tear down the namespace at test completion.\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n // Clear all rules at the beginning + end of the test.\n c.FlushRuleset()\n defer c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n portSet := &nftables.Set{\n Table: filter,\n Name: \"test\",\n KeyType: nftables.TypeInetService,\n }\n if err := c.AddSet(portSet, []nftables.SetElement{{Key: []byte{0, 22}}, {Key: []byte{0, 23}}}); err != nil {\n t.Errorf(\"c.AddSet(portSet) failed: %v\", err)\n }\n if err := c.Flush(); err != nil {\n t.Errorf(\"c.Flush() failed: %v\", err)\n }\n\n c.SetDeleteElements(portSet, []nftables.SetElement{{Key: []byte{0, 23}}})\n\n if err := c.Flush(); err != nil {\n t.Errorf(\"Second c.Flush() failed: %v\", err)\n }\n\n elems, err := c.GetSetElements(portSet)\n if err != nil {\n t.Errorf(\"c.GetSets() failed: %v\", err)\n }\n if len(elems) != 1 {\n t.Fatalf(\"len(elems) = %d, want 1\", len(elems))\n }\n if !bytes.Equal(elems[0].Key, []byte{0, 22}) {\n t.Errorf(\"elems[0].Key = %v, want 22\", elems[0].Key)\n }\n}\n\nfunc TestFlushNamedSet(t *testing.T) {\n if os.Getenv(\"TRAVIS\") == \"true\" {\n t.SkipNow()\n }\n // Create a new network namespace to test these operations,\n // and tear down the namespace at test completion.\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n // Clear all rules at the beginning + end of the test.\n c.FlushRuleset()\n defer c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n portSet := &nftables.Set{\n Table: filter,\n Name: \"test\",\n KeyType: nftables.TypeInetService,\n }\n if err := c.AddSet(portSet, []nftables.SetElement{{Key: []byte{0, 22}}, {Key: []byte{0, 23}}}); err != nil {\n t.Errorf(\"c.AddSet(portSet) failed: %v\", err)\n }\n if err := c.Flush(); err != nil {\n t.Errorf(\"c.Flush() failed: %v\", err)\n }\n\n c.FlushSet(portSet)\n\n if err := c.Flush(); err != nil {\n t.Errorf(\"Second c.Flush() failed: %v\", err)\n }\n\n elems, err := c.GetSetElements(portSet)\n if err != nil {\n t.Errorf(\"c.GetSets() failed: %v\", err)\n }\n if len(elems) != 0 {\n t.Fatalf(\"len(elems) = %d, want 0\", len(elems))\n }\n}\n\nfunc TestSetElementsInterval(t *testing.T) {\n // Create a new network namespace to test these operations,\n // and tear down the namespace at test completion.\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n // Clear all rules at the beginning + end of the test.\n c.FlushRuleset()\n defer c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv6,\n Name: \"filter\",\n })\n portSet := &nftables.Set{\n Table: filter,\n Name: \"ports\",\n KeyType: nftables.MustConcatSetType(nftables.TypeIP6Addr, nftables.TypeInetService, nftables.TypeIP6Addr),\n Interval: true,\n Concatenation: true,\n }\n if err := c.AddSet(portSet, nil); err != nil {\n t.Errorf(\"c.AddSet(portSet) failed: %v\", err)\n }\n\n // { 777c:ab4b:85f0:1614:49e5:d29b:aa7b:cc90 . 50000 . 8709:1cb9:163e:9b55:357f:ef64:708a:edcb }\n keyBytes := []byte{119, 124, 171, 75, 133, 240, 22, 20, 73, 229, 210, 155, 170, 123, 204, 144, 195, 80, 0, 0, 135, 9, 28, 185, 22, 62, 155, 85, 53, 127, 239, 100, 112, 138, 237, 203}\n // { 777c:ab4b:85f0:1614:49e5:d29b:aa7b:cc90 . 60000 . 8709:1cb9:163e:9b55:357f:ef64:708a:edcb }\n keyEndBytes := []byte{119, 124, 171, 75, 133, 240, 22, 20, 73, 229, 210, 155, 170, 123, 204, 144, 234, 96, 0, 0, 135, 9, 28, 185, 22, 62, 155, 85, 53, 127, 239, 100, 112, 138, 237, 203}\n // elements = { 777c:ab4b:85f0:1614:49e5:d29b:aa7b:cc90 . 50000-60000 . 8709:1cb9:163e:9b55:357f:ef64:708a:edcb }\n if err := c.SetAddElements(portSet, []nftables.SetElement{\n {Key: keyBytes, KeyEnd: keyEndBytes},\n }); err != nil {\n t.Errorf(\"c.SetVal(portSet) failed: %v\", err)\n }\n\n if err := c.Flush(); err != nil {\n t.Errorf(\"c.Flush() failed: %v\", err)\n }\n\n sets, err := c.GetSets(filter)\n if err != nil {\n t.Errorf(\"c.GetSets() failed: %v\", err)\n }\n if len(sets) != 1 {\n t.Fatalf(\"len(sets) = %d, want 1\", len(sets))\n }\n\n elements, err := c.GetSetElements(sets[0])\n if err != nil {\n t.Errorf(\"c.GetSetElements(portSet) failed: %v\", err)\n }\n if len(elements) != 1 {\n t.Fatalf(\"len(portSetElements) = %d, want 1\", len(sets))\n }\n\n element := elements[0]\n if len(element.Key) == 0 {\n t.Fatal(\"len(portSetElements.Key) = 0\")\n }\n if len(element.KeyEnd) == 0 {\n t.Fatal(\"len(portSetElements.KeyEnd) = 0\")\n }\n if !bytes.Equal(element.Key, keyBytes) {\n t.Fatal(\"element.Key != keyBytes\")\n }\n if !bytes.Equal(element.KeyEnd, keyEndBytes) {\n t.Fatal(\"element.KeyEnd != keyEndBytes\")\n }\n}\n\nfunc TestCreateListFlowtable(t *testing.T) {\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n c.FlushRuleset()\n defer c.FlushRuleset()\n\n filter := &nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n }\n\n flowtable := &nftables.Flowtable{\n Table: filter,\n Name: \"flowtable_test\",\n }\n\n c.AddTable(filter)\n c.AddFlowtable(flowtable)\n\n if err := c.Flush(); err != nil {\n t.Fatalf(\"c.Flush() failed: %v\", err)\n }\n\n flowtables, err := c.ListFlowtables(filter)\n if err != nil {\n t.Fatalf(\"c.ListFlowtables() failed: %v\", err)\n }\n\n if got, want := len(flowtables), 1; got != want {\n t.Fatalf(\"flowtable entry length mismatch: got %d, want %d\", got, want)\n }\n}\n\nfunc TestCreateListFlowtableWithDevices(t *testing.T) {\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n c.FlushRuleset()\n defer c.FlushRuleset()\n\n filter := &nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n }\n\n lo, err := net.InterfaceByName(\"lo\")\n if err != nil {\n t.Fatalf(\"net.InterfaceByName() failed: %v\", err)\n }\n\n flowtable := &nftables.Flowtable{\n Table: filter,\n Name: \"flowtable_test\",\n Devices: []string{lo.Name},\n Hooknum: nftables.FlowtableHookIngress,\n Priority: nftables.FlowtablePriorityRef(5),\n }\n\n c.AddTable(filter)\n c.AddFlowtable(flowtable)\n\n if err := c.Flush(); err != nil {\n t.Fatalf(\"c.Flush() failed: %v\", err)\n }\n\n flowtables, err := c.ListFlowtables(filter)\n if err != nil {\n t.Fatalf(\"c.ListFlowtables() failed: %v\", err)\n }\n\n if got, want := len(flowtables), 1; got != want {\n t.Fatalf(\"flowtable entry length mismatch: got %d, want %d\", got, want)\n }\n\n sysFlowtable := flowtables[0]\n if got, want := sysFlowtable.Table, flowtable.Table; got != want {\n t.Errorf(\"flowtables table mismatch: got %v, want %v\", got, want)\n }\n\n if got, want := sysFlowtable.Name, flowtable.Name; got != want {\n t.Errorf(\"flowtables name mismatch: got %s, want %s\", got, want)\n }\n\n if len(sysFlowtable.Devices) != 1 {\n t.Fatalf(\"expected 1 device in flowtable, got %d\", len(sysFlowtable.Devices))\n }\n\n if got, want := sysFlowtable.Devices, flowtable.Devices; !reflect.DeepEqual(got, want) {\n t.Errorf(\"flowtables device mismatch: got %v, want %v\", got, want)\n }\n\n if got, want := *sysFlowtable.Hooknum, *flowtable.Hooknum; got != want {\n t.Errorf(\"flowtables hook mismatch: got %v, want %v\", got, want)\n }\n\n if got, want := *sysFlowtable.Priority, *flowtable.Priority; got != want {\n t.Errorf(\"flowtables prio mismatch: got %v, want %v\", got, want)\n }\n}\n\nfunc TestCreateDeleteFlowtable(t *testing.T) {\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n c.FlushRuleset()\n defer c.FlushRuleset()\n\n filter := &nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n }\n\n flowtable := &nftables.Flowtable{\n Table: filter,\n Name: \"flowtable_test\",\n }\n\n c.AddTable(filter)\n c.AddFlowtable(flowtable)\n flowtable.Name = \"flowtable_test_to_delete\"\n c.AddFlowtable(flowtable)\n\n if err := c.Flush(); err != nil {\n t.Fatalf(\"c.Flush() failed: %v\", err)\n }\n\n flowtables, err := c.ListFlowtables(filter)\n if err != nil {\n t.Fatalf(\"c.ListFlowtables() failed: %v\", err)\n }\n\n if got, want := len(flowtables), 2; got != want {\n t.Fatalf(\"flowtable entry length mismatch: got %d, want %d\", got, want)\n }\n\n c.DelFlowtable(flowtable)\n if err := c.Flush(); err != nil {\n t.Fatalf(\"c.Flush() failed: %v\", err)\n }\n\n flowtables, err = c.ListFlowtables(filter)\n if err != nil {\n t.Fatalf(\"c.ListFlowtables() after deletion failed: %v\", err)\n }\n\n if got, want := len(flowtables), 1; got != want {\n t.Errorf(\"flowtable entry length mismatch: got %d, want %d\", got, want)\n }\n\n if got, removed := flowtables[0].Name, flowtable.Name; got == removed {\n t.Errorf(\"wrong flowtable entry deleted\")\n }\n}\n\nfunc TestOffload(t *testing.T) {\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n c.FlushRuleset()\n defer c.FlushRuleset()\n\n filter := &nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n }\n\n accept := nftables.ChainPolicyAccept\n forward := &nftables.Chain{\n Name: \"forward\",\n Table: filter,\n Type: nftables.ChainTypeFilter,\n Priority: nftables.ChainPriorityFilter,\n Hooknum: nftables.ChainHookForward,\n Policy: &accept,\n }\n\n flowtable := &nftables.Flowtable{\n Table: filter,\n Name: \"flowtable_test\",\n }\n\n c.AddTable(filter)\n c.AddChain(forward)\n c.AddFlowtable(flowtable)\n\n if err := c.Flush(); err != nil {\n t.Fatalf(\"c.Flush() failed: %v\", err)\n }\n\n rule := &nftables.Rule{\n Table: filter,\n Chain: forward,\n Exprs: []expr.Any{\n &expr.Payload{\n OperationType: expr.PayloadLoad,\n Base: expr.PayloadBaseNetworkHeader,\n Len: 1,\n Offset: 9,\n DestRegister: 1,\n },\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{0x06, 0x00, 0x00, 0x00},\n },\n &expr.FlowOffload{\n Name: flowtable.Name,\n },\n },\n }\n c.AddRule(rule)\n\n if err := c.Flush(); err != nil {\n t.Fatalf(\"c.Flush() offload failed: %v\", err)\n }\n\n rules, err := c.GetRule(filter, forward)\n if err != nil {\n t.Fatalf(\"c.GetRule() failed: %v\", err)\n }\n\n if got, want := len(rules), 1; got != want {\n t.Fatalf(\"rule count mismatch: got %d, want %d\", got, want)\n }\n\n sysRule := rules[0]\n if got, want := sysRule.Exprs, rule.Exprs; !reflect.DeepEqual(got, want) {\n t.Errorf(\"rule content mismatch: got %v, want %v\", got, want)\n }\n}\n\nfunc TestFlushChain(t *testing.T) {\n // Create a new network namespace to test these operations,\n // and tear down the namespace at test completion.\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n // Clear all rules at the beginning + end of the test.\n c.FlushRuleset()\n defer c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n forward := c.AddChain(&nftables.Chain{\n Table: filter,\n Name: \"forward\",\n })\n\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: forward,\n Exprs: []expr.Any{\n // [ meta load l4proto => reg 1 ]\n &expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1},\n // [ cmp eq reg 1 0x00000006 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{unix.IPPROTO_TCP},\n },\n\n // [ payload load 2b @ transport header + 2 => reg 1 ]\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseTransportHeader,\n Offset: 2,\n Len: 2,\n },\n // [ cmp eq reg 1 0x0000d204 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{0x04, 0xd2},\n },\n // [ immediate reg 0 drop ]\n &expr.Verdict{\n Kind: expr.VerdictDrop,\n },\n },\n })\n\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: forward,\n Exprs: []expr.Any{\n // [ meta load l4proto => reg 1 ]\n &expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1},\n // [ cmp eq reg 1 0x00000006 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{unix.IPPROTO_TCP},\n },\n\n // [ payload load 2b @ transport header + 2 => reg 1 ]\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseTransportHeader,\n Offset: 2,\n Len: 2,\n },\n // [ cmp eq reg 1 0x000010e1 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{0xe1, 0x10},\n },\n // [ immediate reg 0 drop ]\n &expr.Verdict{\n Kind: expr.VerdictDrop,\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Errorf(\"c.Flush() failed: %v\", err)\n }\n rules, err := c.GetRules(filter, forward)\n if err != nil {\n t.Errorf(\"c.GetRules() failed: %v\", err)\n }\n if len(rules) != 2 {\n t.Fatalf(\"len(rules) = %d, want 2\", len(rules))\n }\n\n c.FlushChain(forward)\n\n if err := c.Flush(); err != nil {\n t.Errorf(\"Second c.Flush() failed: %v\", err)\n }\n\n rules, err = c.GetRules(filter, forward)\n if err != nil {\n t.Errorf(\"c.GetRules() failed: %v\", err)\n }\n if len(rules) != 0 {\n t.Fatalf(\"len(rules) = %d, want 0\", len(rules))\n }\n}\n\nfunc TestFlushTable(t *testing.T) {\n if os.Getenv(\"TRAVIS\") == \"true\" {\n t.SkipNow()\n }\n // Create a new network namespace to test these operations,\n // and tear down the namespace at test completion.\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n // Clear all rules at the beginning + end of the test.\n c.FlushRuleset()\n defer c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n nat := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"nat\",\n })\n\n forward := c.AddChain(&nftables.Chain{\n Table: filter,\n Name: \"forward\",\n })\n\n input := c.AddChain(&nftables.Chain{\n Table: filter,\n Name: \"input\",\n })\n\n prerouting := c.AddChain(&nftables.Chain{\n Table: nat,\n Name: \"prerouting\",\n })\n\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: forward,\n Exprs: []expr.Any{\n // [ meta load l4proto => reg 1 ]\n &expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1},\n // [ cmp eq reg 1 0x00000006 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{unix.IPPROTO_TCP},\n },\n\n // [ payload load 2b @ transport header + 2 => reg 1 ]\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseTransportHeader,\n Offset: 2,\n Len: 2,\n },\n // [ cmp eq reg 1 0x0000d204 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{0x04, 0xd2},\n },\n // [ immediate reg 0 drop ]\n &expr.Verdict{\n Kind: expr.VerdictDrop,\n },\n },\n })\n\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: forward,\n Exprs: []expr.Any{\n // [ meta load l4proto => reg 1 ]\n &expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1},\n // [ cmp eq reg 1 0x00000006 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{unix.IPPROTO_TCP},\n },\n\n // [ payload load 2b @ transport header + 2 => reg 1 ]\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseTransportHeader,\n Offset: 2,\n Len: 2,\n },\n // [ cmp eq reg 1 0x000010e1 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{0xe1, 0x10},\n },\n // [ immediate reg 0 drop ]\n &expr.Verdict{\n Kind: expr.VerdictDrop,\n },\n },\n })\n\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: input,\n Exprs: []expr.Any{\n // [ meta load l4proto => reg 1 ]\n &expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1},\n // [ cmp eq reg 1 0x00000006 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{unix.IPPROTO_TCP},\n },\n\n // [ payload load 2b @ transport header + 2 => reg 1 ]\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseTransportHeader,\n Offset: 2,\n Len: 2,\n },\n // [ cmp eq reg 1 0x0000162e ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{0x2e, 0x16},\n },\n // [ immediate reg 0 drop ]\n &expr.Verdict{\n Kind: expr.VerdictDrop,\n },\n },\n })\n\n c.AddRule(&nftables.Rule{\n Table: nat,\n Chain: prerouting,\n Exprs: []expr.Any{\n // [ meta load l4proto => reg 1 ]\n &expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1},\n // [ cmp eq reg 1 0x00000006 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{unix.IPPROTO_TCP},\n },\n\n // [ payload load 2b @ transport header + 2 => reg 1 ]\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseTransportHeader,\n Offset: 2, // TODO\n Len: 2, // TODO\n },\n // [ cmp eq reg 1 0x00001600 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{0x00, 0x16},\n },\n\n // [ immediate reg 1 0x0000ae08 ]\n &expr.Immediate{\n Register: 1,\n Data: binaryutil.BigEndian.PutUint16(2222),\n },\n\n // [ redir proto_min reg 1 ]\n &expr.Redir{\n RegisterProtoMin: 1,\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Errorf(\"c.Flush() failed: %v\", err)\n }\n rules, err := c.GetRules(filter, forward)\n if err != nil {\n t.Errorf(\"c.GetRules() failed: %v\", err)\n }\n if len(rules) != 2 {\n t.Fatalf(\"len(rules) = %d, want 2\", len(rules))\n }\n rules, err = c.GetRules(filter, input)\n if err != nil {\n t.Errorf(\"c.GetRules() failed: %v\", err)\n }\n if len(rules) != 1 {\n t.Fatalf(\"len(rules) = %d, want 1\", len(rules))\n }\n rules, err = c.GetRules(nat, prerouting)\n if err != nil {\n t.Errorf(\"c.GetRules() failed: %v\", err)\n }\n if len(rules) != 1 {\n t.Fatalf(\"len(rules) = %d, want 1\", len(rules))\n }\n\n c.FlushTable(filter)\n\n if err := c.Flush(); err != nil {\n t.Errorf(\"Second c.Flush() failed: %v\", err)\n }\n\n rules, err = c.GetRules(filter, forward)\n if err != nil {\n t.Errorf(\"c.GetRules() failed: %v\", err)\n }\n if len(rules) != 0 {\n t.Fatalf(\"len(rules) = %d, want 0\", len(rules))\n }\n rules, err = c.GetRules(filter, input)\n if err != nil {\n t.Errorf(\"c.GetRules() failed: %v\", err)\n }\n if len(rules) != 0 {\n t.Fatalf(\"len(rules) = %d, want 0\", len(rules))\n }\n rules, err = c.GetRules(nat, prerouting)\n if err != nil {\n t.Errorf(\"c.GetRules() failed: %v\", err)\n }\n if len(rules) != 1 {\n t.Fatalf(\"len(rules) = %d, want 1\", len(rules))\n }\n}\n\nfunc TestGetLookupExprDestSet(t *testing.T) {\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n c.FlushRuleset()\n defer c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n forward := c.AddChain(&nftables.Chain{\n Name: \"forward\",\n Table: filter,\n Type: nftables.ChainTypeFilter,\n Hooknum: nftables.ChainHookForward,\n Priority: nftables.ChainPriorityFilter,\n })\n\n set := &nftables.Set{\n Table: filter,\n Name: \"test\",\n IsMap: true,\n KeyType: nftables.TypeInetService,\n DataType: nftables.TypeVerdict,\n }\n if err := c.AddSet(set, nil); err != nil {\n t.Errorf(\"c.AddSet(set) failed: %v\", err)\n }\n if err := c.Flush(); err != nil {\n t.Errorf(\"c.Flush() failed: %v\", err)\n }\n\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: forward,\n Exprs: []expr.Any{\n &expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1},\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{unix.IPPROTO_TCP},\n },\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseTransportHeader,\n Offset: 2,\n Len: 2,\n },\n &expr.Lookup{\n SourceRegister: 1,\n SetName: set.Name,\n SetID: set.ID,\n DestRegister: 0,\n IsDestRegSet: true,\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Errorf(\"c.Flush() failed: %v\", err)\n }\n\n rules, err := c.GetRules(\n &nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n },\n &nftables.Chain{\n Name: \"forward\",\n },\n )\n if err != nil {\n t.Fatal(err)\n }\n\n if got, want := len(rules), 1; got != want {\n t.Fatalf(\"unexpected number of rules: got %d, want %d\", got, want)\n }\n if got, want := len(rules[0].Exprs), 4; got != want {\n t.Fatalf(\"unexpected number of exprs: got %d, want %d\", got, want)\n }\n\n lookup, lookupOk := rules[0].Exprs[3].(*expr.Lookup)\n if !lookupOk {\n t.Fatalf(\"Exprs[3] is type %T, want *expr.Lookup\", rules[0].Exprs[3])\n }\n if want := (&expr.Lookup{\n SourceRegister: 1,\n SetName: set.Name,\n DestRegister: 0,\n IsDestRegSet: true,\n }); !reflect.DeepEqual(lookup, want) {\n t.Errorf(\"lookup expr = %+v, wanted %+v\", lookup, want)\n }\n}\n\nfunc TestGetRuleLookupVerdictImmediate(t *testing.T) {\n // Create a new network namespace to test these operations,\n // and tear down the namespace at test completion.\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n // Clear all rules at the beginning + end of the test.\n c.FlushRuleset()\n defer c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n forward := c.AddChain(&nftables.Chain{\n Name: \"forward\",\n Table: filter,\n Type: nftables.ChainTypeFilter,\n Hooknum: nftables.ChainHookForward,\n Priority: nftables.ChainPriorityFilter,\n })\n\n set := &nftables.Set{\n Table: filter,\n Name: \"test\",\n KeyType: nftables.TypeInetService,\n }\n if err := c.AddSet(set, nil); err != nil {\n t.Errorf(\"c.AddSet(portSet) failed: %v\", err)\n }\n if err := c.Flush(); err != nil {\n t.Errorf(\"c.Flush() failed: %v\", err)\n }\n\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: forward,\n Exprs: []expr.Any{\n // [ meta load l4proto => reg 1 ]\n &expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1},\n // [ cmp eq reg 1 0x00000006 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{unix.IPPROTO_TCP},\n },\n // [ payload load 2b @ transport header + 2 => reg 1 ]\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseTransportHeader,\n Offset: 2,\n Len: 2,\n },\n // [ lookup reg 1 set __set%d ]\n &expr.Lookup{\n SourceRegister: 1,\n SetName: set.Name,\n SetID: set.ID,\n },\n // [ immediate reg 0 drop ]\n &expr.Verdict{\n Kind: expr.VerdictAccept,\n },\n // [ immediate reg 2 test ]\n &expr.Immediate{\n Register: 2,\n Data: []byte(\"test\"),\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Errorf(\"c.Flush() failed: %v\", err)\n }\n\n rules, err := c.GetRules(\n &nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n },\n &nftables.Chain{\n Name: \"forward\",\n },\n )\n if err != nil {\n t.Fatal(err)\n }\n\n if got, want := len(rules), 1; got != want {\n t.Fatalf(\"unexpected number of rules: got %d, want %d\", got, want)\n }\n if got, want := len(rules[0].Exprs), 6; got != want {\n t.Fatalf(\"unexpected number of exprs: got %d, want %d\", got, want)\n }\n\n lookup, lookupOk := rules[0].Exprs[3].(*expr.Lookup)\n if !lookupOk {\n t.Fatalf(\"Exprs[3] is type %T, want *expr.Lookup\", rules[0].Exprs[3])\n }\n if want := (&expr.Lookup{\n SourceRegister: 1,\n SetName: set.Name,\n }); !reflect.DeepEqual(lookup, want) {\n t.Errorf(\"lookup expr = %+v, wanted %+v\", lookup, want)\n }\n\n verdict, verdictOk := rules[0].Exprs[4].(*expr.Verdict)\n if !verdictOk {\n t.Fatalf(\"Exprs[4] is type %T, want *expr.Verdict\", rules[0].Exprs[4])\n }\n if want := (&expr.Verdict{\n Kind: expr.VerdictAccept,\n }); !reflect.DeepEqual(verdict, want) {\n t.Errorf(\"verdict expr = %+v, wanted %+v\", verdict, want)\n }\n\n imm, immOk := rules[0].Exprs[5].(*expr.Immediate)\n if !immOk {\n t.Fatalf(\"Exprs[4] is type %T, want *expr.Immediate\", rules[0].Exprs[5])\n }\n if want := (&expr.Immediate{\n Register: 2,\n Data: []byte(\"test\"),\n }); !reflect.DeepEqual(imm, want) {\n t.Errorf(\"verdict expr = %+v, wanted %+v\", imm, want)\n }\n}\n\nfunc TestDynset(t *testing.T) {\n // Create a new network namespace to test these operations,\n // and tear down the namespace at test completion.\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n // Clear all rules at the beginning + end of the test.\n c.FlushRuleset()\n defer c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n forward := c.AddChain(&nftables.Chain{\n Name: \"forward\",\n Table: filter,\n Type: nftables.ChainTypeFilter,\n Hooknum: nftables.ChainHookForward,\n Priority: nftables.ChainPriorityFilter,\n })\n\n set := &nftables.Set{\n Table: filter,\n Name: \"dynamic-set\",\n KeyType: nftables.TypeIPAddr,\n HasTimeout: true,\n Timeout: time.Duration(600 * time.Second),\n }\n if err := c.AddSet(set, nil); err != nil {\n t.Errorf(\"c.AddSet(portSet) failed: %v\", err)\n }\n if err := c.Flush(); err != nil {\n t.Errorf(\"c.Flush() failed: %v\", err)\n }\n\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: forward,\n Exprs: []expr.Any{\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseNetworkHeader,\n Offset: uint32(12),\n Len: uint32(4),\n },\n &expr.Dynset{\n SrcRegKey: 1,\n SetName: set.Name,\n SetID: set.ID,\n Operation: uint32(unix.NFT_DYNSET_OP_UPDATE),\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Errorf(\"c.Flush() failed: %v\", err)\n }\n\n rules, err := c.GetRules(\n &nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n },\n &nftables.Chain{\n Name: \"forward\",\n },\n )\n if err != nil {\n t.Fatal(err)\n }\n\n if got, want := len(rules), 1; got != want {\n t.Fatalf(\"unexpected number of rules: got %d, want %d\", got, want)\n }\n if got, want := len(rules[0].Exprs), 2; got != want {\n t.Fatalf(\"unexpected number of exprs: got %d, want %d\", got, want)\n }\n\n dynset, dynsetOk := rules[0].Exprs[1].(*expr.Dynset)\n if !dynsetOk {\n t.Fatalf(\"Exprs[0] is type %T, want *expr.Dynset\", rules[0].Exprs[1])\n }\n if want := (&expr.Dynset{\n SrcRegKey: 1,\n SetName: set.Name,\n Operation: uint32(unix.NFT_DYNSET_OP_UPDATE),\n }); !reflect.DeepEqual(dynset, want) {\n t.Errorf(\"dynset expr = %+v, wanted %+v\", dynset, want)\n }\n}\n\nfunc TestDynsetWithOneExpression(t *testing.T) {\n // Create a new network namespace to test these operations,\n // and tear down the namespace at test completion.\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n // Clear all rules at the beginning + end of the test.\n c.FlushRuleset()\n defer c.FlushRuleset()\n table := &nftables.Table{\n Name: \"filter\",\n Family: nftables.TableFamilyIPv4,\n }\n chain := &nftables.Chain{\n Name: \"forward\",\n Hooknum: nftables.ChainHookForward,\n Table: table,\n Priority: nftables.ChainPriorityRef(0),\n Type: nftables.ChainTypeFilter,\n }\n set := &nftables.Set{\n Table: table,\n Name: \"myMeter\",\n KeyType: nftables.TypeIPAddr,\n Dynamic: true,\n }\n c.AddTable(table)\n c.AddChain(chain)\n if err := c.AddSet(set, nil); err != nil {\n t.Errorf(\"c.AddSet(myMeter) failed: %v\", err)\n }\n if err := c.Flush(); err != nil {\n t.Errorf(\"c.Flush() failed: %v\", err)\n }\n\n rule := &nftables.Rule{\n Table: table,\n Chain: chain,\n Exprs: []expr.Any{\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseNetworkHeader,\n Offset: uint32(12),\n Len: uint32(4),\n },\n &expr.Dynset{\n SrcRegKey: 1,\n SetName: set.Name,\n Operation: uint32(unix.NFT_DYNSET_OP_ADD),\n Exprs: []expr.Any{\n &expr.Limit{\n Type: expr.LimitTypePkts,\n Rate: 200,\n Unit: expr.LimitTimeSecond,\n Burst: 5,\n },\n },\n },\n &expr.Verdict{\n Kind: expr.VerdictDrop,\n },\n },\n }\n c.AddRule(rule)\n if err := c.Flush(); err != nil {\n t.Errorf(\"c.Flush() failed: %v\", err)\n }\n\n rules, err := c.GetRules(table, chain)\n if err != nil {\n t.Fatal(err)\n }\n\n if got, want := len(rules), 1; got != want {\n t.Fatalf(\"unexpected number of rules: got %d, want %d\", got, want)\n }\n if got, want := len(rules[0].Exprs), 3; got != want {\n t.Fatalf(\"unexpected number of exprs: got %d, want %d\", got, want)\n }\n\n dynset, dynsetOk := rules[0].Exprs[1].(*expr.Dynset)\n if !dynsetOk {\n t.Fatalf(\"Exprs[0] is type %T, want *expr.Dynset\", rules[0].Exprs[1])\n }\n\n if got, want := len(dynset.Exprs), 1; got != want {\n t.Fatalf(\"unexpected number of dynset.Exprs: got %d, want %d\", got, want)\n }\n\n if got, want := dynset.SetName, set.Name; got != want {\n t.Fatalf(\"dynset.SetName is %s, want %s\", got, want)\n }\n\n if want := (&expr.Limit{\n Type: expr.LimitTypePkts,\n Rate: 200,\n Unit: expr.LimitTimeSecond,\n Burst: 5,\n }); !reflect.DeepEqual(dynset.Exprs[0], want) {\n t.Errorf(\"dynset.Exprs[0] expr = %+v, wanted %+v\", dynset.Exprs[0], want)\n }\n}\n\nfunc TestDynsetWithMultipleExpressions(t *testing.T) {\n // Create a new network namespace to test these operations,\n // and tear down the namespace at test completion.\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n // Clear all rules at the beginning + end of the test.\n c.FlushRuleset()\n defer c.FlushRuleset()\n table := &nftables.Table{\n Name: \"filter\",\n Family: nftables.TableFamilyIPv4,\n }\n chain := &nftables.Chain{\n Name: \"forward\",\n Hooknum: nftables.ChainHookForward,\n Table: table,\n Priority: nftables.ChainPriorityRef(0),\n Type: nftables.ChainTypeFilter,\n }\n set := &nftables.Set{\n Table: table,\n Name: \"myMeter\",\n KeyType: nftables.TypeIPAddr,\n Dynamic: true,\n }\n c.AddTable(table)\n c.AddChain(chain)\n if err := c.AddSet(set, nil); err != nil {\n t.Errorf(\"c.AddSet(myMeter) failed: %v\", err)\n }\n if err := c.Flush(); err != nil {\n t.Errorf(\"c.Flush() failed: %v\", err)\n }\n\n rule := &nftables.Rule{\n Table: table,\n Chain: chain,\n Exprs: []expr.Any{\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseNetworkHeader,\n Offset: uint32(12),\n Len: uint32(4),\n },\n &expr.Dynset{\n SrcRegKey: 1,\n SetName: set.Name,\n Operation: uint32(unix.NFT_DYNSET_OP_ADD),\n Exprs: []expr.Any{\n &expr.Connlimit{\n Count: 20,\n Flags: 1,\n },\n &expr.Limit{\n Type: expr.LimitTypePkts,\n Rate: 10,\n Unit: expr.LimitTimeSecond,\n Burst: 2,\n },\n },\n },\n &expr.Verdict{\n Kind: expr.VerdictDrop,\n },\n },\n }\n c.AddRule(rule)\n if err := c.Flush(); err != nil {\n t.Errorf(\"c.Flush() failed: %v\", err)\n }\n\n rules, err := c.GetRules(table, chain)\n if err != nil {\n t.Fatal(err)\n }\n\n if got, want := len(rules), 1; got != want {\n t.Fatalf(\"unexpected number of rules: got %d, want %d\", got, want)\n }\n if got, want := len(rules[0].Exprs), 3; got != want {\n t.Fatalf(\"unexpected number of exprs: got %d, want %d\", got, want)\n }\n\n dynset, dynsetOk := rules[0].Exprs[1].(*expr.Dynset)\n if !dynsetOk {\n t.Fatalf(\"Exprs[0] is type %T, want *expr.Dynset\", rules[0].Exprs[1])\n }\n\n if got, want := len(dynset.Exprs), 2; got != want {\n t.Fatalf(\"unexpected number of dynset.Exprs: got %d, want %d\", got, want)\n }\n\n if got, want := dynset.SetName, set.Name; got != want {\n t.Fatalf(\"dynset.SetName is %s, want %s\", got, want)\n }\n\n if want := (&expr.Connlimit{\n Count: 20,\n Flags: 1,\n }); !reflect.DeepEqual(dynset.Exprs[0], want) {\n t.Errorf(\"dynset.Exprs[0] expr = %+v, wanted %+v\", dynset.Exprs[0], want)\n }\n\n if want := (&expr.Limit{\n Type: expr.LimitTypePkts,\n Rate: 10,\n Unit: expr.LimitTimeSecond,\n Burst: 2,\n }); !reflect.DeepEqual(dynset.Exprs[1], want) {\n t.Errorf(\"dynset.Exprs[1] expr = %+v, wanted %+v\", dynset.Exprs[1], want)\n }\n}\n\nfunc TestConfigureNATRedirect(t *testing.T) {\n // The want byte sequences come from stracing nft(8), e.g.:\n // strace -f -v -x -s 2048 -eraw=sendto nft add table ip nat\n //\n // The nft(8) command sequence was taken from:\n // https://wiki.nftables.org/wiki-nftables/index.php/Performing_Network_Address_Translation_(NAT)\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft flush ruleset\n []byte(\"\\x00\\x00\\x00\\x00\"),\n // nft add table ip nat\n []byte(\"\\x02\\x00\\x00\\x00\\x08\\x00\\x01\\x00\\x6e\\x61\\x74\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain nat prerouting '{' type nat hook prerouting priority 0 \\; '}'\n []byte(\"\\x02\\x00\\x00\\x00\\x08\\x00\\x01\\x00\\x6e\\x61\\x74\\x00\\x0f\\x00\\x03\\x00\\x70\\x72\\x65\\x72\\x6f\\x75\\x74\\x69\\x6e\\x67\\x00\\x00\\x14\\x00\\x04\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x08\\x00\\x07\\x00\\x6e\\x61\\x74\\x00\"),\n // nft add rule nat prerouting tcp dport 22 redirect to 2222\n []byte(\"\\x02\\x00\\x00\\x00\\x08\\x00\\x01\\x00\\x6e\\x61\\x74\\x00\\x0f\\x00\\x02\\x00\\x70\\x72\\x65\\x72\\x6f\\x75\\x74\\x69\\x6e\\x67\\x00\\x00\\xfc\\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\\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\\x06\\x00\\x01\\x00\\x00\\x16\\x00\\x00\\x2c\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x69\\x6d\\x6d\\x65\\x64\\x69\\x61\\x74\\x65\\x00\\x00\\x00\\x18\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x0c\\x00\\x02\\x80\\x06\\x00\\x01\\x00\\x08\\xae\\x00\\x00\\x1c\\x00\\x01\\x80\\x0a\\x00\\x01\\x00\\x72\\x65\\x64\\x69\\x72\\x00\\x00\\x00\\x0c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.FlushRuleset()\n\n nat := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"nat\",\n })\n\n prerouting := c.AddChain(&nftables.Chain{\n Name: \"prerouting\",\n Hooknum: nftables.ChainHookPrerouting,\n Priority: nftables.ChainPriorityFilter,\n Table: nat,\n Type: nftables.ChainTypeNAT,\n })\n\n c.AddRule(&nftables.Rule{\n Table: nat,\n Chain: prerouting,\n Exprs: []expr.Any{\n // [ meta load l4proto => reg 1 ]\n &expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1},\n // [ cmp eq reg 1 0x00000006 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{unix.IPPROTO_TCP},\n },\n\n // [ payload load 2b @ transport header + 2 => reg 1 ]\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseTransportHeader,\n Offset: 2, // TODO\n Len: 2, // TODO\n },\n // [ cmp eq reg 1 0x00001600 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{0x00, 0x16},\n },\n\n // [ immediate reg 1 0x0000ae08 ]\n &expr.Immediate{\n Register: 1,\n Data: binaryutil.BigEndian.PutUint16(2222),\n },\n\n // [ redir proto_min reg 1 ]\n &expr.Redir{\n RegisterProtoMin: 1,\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestConfigureJumpVerdict(t *testing.T) {\n // The want byte sequences come from stracing nft(8), e.g.:\n // strace -f -v -x -s 2048 -eraw=sendto nft add table ip nat\n //\n // The nft(8) command sequence was taken from:\n // https://wiki.nftables.org/wiki-nftables/index.php/Performing_Network_Address_Translation_(NAT)\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft flush ruleset\n []byte(\"\\x00\\x00\\x00\\x00\"),\n // nft add table ip nat\n []byte(\"\\x02\\x00\\x00\\x00\\x08\\x00\\x01\\x00\\x6e\\x61\\x74\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain nat prerouting '{' type nat hook prerouting priority 0 \\; '}'\n []byte(\"\\x02\\x00\\x00\\x00\\x08\\x00\\x01\\x00\\x6e\\x61\\x74\\x00\\x0f\\x00\\x03\\x00\\x70\\x72\\x65\\x72\\x6f\\x75\\x74\\x69\\x6e\\x67\\x00\\x00\\x14\\x00\\x04\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x08\\x00\\x07\\x00\\x6e\\x61\\x74\\x00\"),\n // nft add rule nat prerouting tcp dport 1-65535 jump istio_redirect\n []byte(\"\\x02\\x00\\x00\\x00\\x08\\x00\\x01\\x00\\x6e\\x61\\x74\\x00\\x0f\\x00\\x02\\x00\\x70\\x72\\x65\\x72\\x6f\\x75\\x74\\x69\\x6e\\x67\\x00\\x00\\x24\\x01\\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\\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\\x05\\x0c\\x00\\x03\\x80\\x06\\x00\\x01\\x00\\x00\\x01\\x00\\x00\\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\\x03\\x0c\\x00\\x03\\x80\\x06\\x00\\x01\\x00\\xff\\xff\\x00\\x00\\x44\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x69\\x6d\\x6d\\x65\\x64\\x69\\x61\\x74\\x65\\x00\\x00\\x00\\x30\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x24\\x00\\x02\\x80\\x20\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\xff\\xff\\xff\\xfd\\x13\\x00\\x02\\x00\\x69\\x73\\x74\\x69\\x6f\\x5f\\x72\\x65\\x64\\x69\\x72\\x65\\x63\\x74\\x00\\x00\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.FlushRuleset()\n\n nat := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"nat\",\n })\n\n prerouting := c.AddChain(&nftables.Chain{\n Name: \"prerouting\",\n Hooknum: nftables.ChainHookPrerouting,\n Priority: nftables.ChainPriorityFilter,\n Table: nat,\n Type: nftables.ChainTypeNAT,\n })\n\n c.AddRule(&nftables.Rule{\n Table: nat,\n Chain: prerouting,\n Exprs: []expr.Any{\n // [ meta load l4proto => reg 1 ]\n &expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1},\n // [ cmp eq reg 1 0x00000006 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{unix.IPPROTO_TCP},\n },\n\n // [ payload load 2b @ transport header + 2 => reg 1 ]\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseTransportHeader,\n Offset: 2, // TODO\n Len: 2, // TODO\n },\n // [ cmp gte reg 1 0x00000100 ]\n &expr.Cmp{\n Op: expr.CmpOpGte,\n Register: 1,\n Data: []byte{0x00, 0x01},\n },\n // [ cmp lte reg 1 0x0000ffff ]\n &expr.Cmp{\n Op: expr.CmpOpLte,\n Register: 1,\n Data: []byte{0xff, 0xff},\n },\n\n // [ immediate reg 0 jump -> istio_redirect ]\n &expr.Verdict{\n Kind: expr.VerdictKind(unix.NFT_JUMP),\n Chain: \"istio_redirect\",\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestConfigureReturnVerdict(t *testing.T) {\n // The want byte sequences come from stracing nft(8), e.g.:\n // strace -f -v -x -s 2048 -eraw=sendto nft add table ip nat\n //\n // The nft(8) command sequence was taken from:\n // https://wiki.nftables.org/wiki-nftables/index.php/Performing_Network_Address_Translation_(NAT)\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft flush ruleset\n []byte(\"\\x00\\x00\\x00\\x00\"),\n // nft add table ip nat\n []byte(\"\\x02\\x00\\x00\\x00\\x08\\x00\\x01\\x00\\x6e\\x61\\x74\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain nat prerouting '{' type nat hook prerouting priority 0 \\; '}'\n []byte(\"\\x02\\x00\\x00\\x00\\x08\\x00\\x01\\x00\\x6e\\x61\\x74\\x00\\x0f\\x00\\x03\\x00\\x70\\x72\\x65\\x72\\x6f\\x75\\x74\\x69\\x6e\\x67\\x00\\x00\\x14\\x00\\x04\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x08\\x00\\x07\\x00\\x6e\\x61\\x74\\x00\"),\n // nft add rule nat prerouting meta skgid 1337 return\n []byte(\"\\x02\\x00\\x00\\x00\\x08\\x00\\x01\\x00\\x6e\\x61\\x74\\x00\\x0f\\x00\\x02\\x00\\x70\\x72\\x65\\x72\\x6f\\x75\\x74\\x69\\x6e\\x67\\x00\\x00\\x84\\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\\x0b\\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\\x08\\x00\\x01\\x00\\x39\\x05\\x00\\x00\\x30\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x69\\x6d\\x6d\\x65\\x64\\x69\\x61\\x74\\x65\\x00\\x00\\x00\\x1c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x10\\x00\\x02\\x80\\x0c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\xff\\xff\\xff\\xfb\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.FlushRuleset()\n\n nat := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"nat\",\n })\n\n prerouting := c.AddChain(&nftables.Chain{\n Name: \"prerouting\",\n Hooknum: nftables.ChainHookPrerouting,\n Priority: nftables.ChainPriorityFilter,\n Table: nat,\n Type: nftables.ChainTypeNAT,\n })\n\n c.AddRule(&nftables.Rule{\n Table: nat,\n Chain: prerouting,\n Exprs: []expr.Any{\n // [ meta load skgid => reg 1 ]\n &expr.Meta{Key: expr.MetaKeySKGID, Register: 1},\n // [ cmp eq reg 1 0x00000539 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{0x39, 0x05, 0x00, 0x00},\n },\n\n // [ immediate reg 0 return ]\n &expr.Verdict{\n Kind: expr.VerdictKind(unix.NFT_RETURN),\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestConfigureRangePort(t *testing.T) {\n // The want byte sequences come from stracing nft(8), e.g.:\n // strace -f -v -x -s 2048 -eraw=sendto nft add rule filter forward tcp sport != 2024-2030 return\n //\n // The nft(8) command sequence was taken from:\n // https://wiki.nftables.org/wiki-nftables/index.php/Quick_reference-nftables_in_10_minutes#Tcp\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft flush ruleset\n []byte(\"\\x00\\x00\\x00\\x00\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain filter forward '{' type filter hook forward priority 0 \\; '}'\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0c\\x00\\x03\\x00\\x66\\x6f\\x72\\x77\\x61\\x72\\x64\\x00\\x14\\x00\\x04\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x02\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x0b\\x00\\x07\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\"),\n // nft add rule filter forward tcp sport != 2024-2030 return\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0c\\x00\\x02\\x00\\x66\\x6f\\x72\\x77\\x61\\x72\\x64\\x00\\xf4\\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\\x00\\x08\\x00\\x04\\x00\\x00\\x00\\x00\\x02\\x3c\\x00\\x01\\x80\\x0a\\x00\\x01\\x00\\x72\\x61\\x6e\\x67\\x65\\x00\\x00\\x00\\x2c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x01\\x0c\\x00\\x03\\x80\\x06\\x00\\x01\\x00\\x07\\xe8\\x00\\x00\\x0c\\x00\\x04\\x80\\x06\\x00\\x01\\x00\\x07\\xee\\x00\\x00\\x30\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x69\\x6d\\x6d\\x65\\x64\\x69\\x61\\x74\\x65\\x00\\x00\\x00\\x1c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x10\\x00\\x02\\x80\\x0c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\xff\\xff\\xff\\xfb\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n forward := c.AddChain(&nftables.Chain{\n Name: \"forward\",\n Table: filter,\n Type: nftables.ChainTypeFilter,\n Hooknum: nftables.ChainHookForward,\n Priority: nftables.ChainPriorityFilter,\n })\n\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: forward,\n Exprs: []expr.Any{\n // [ meta load l4proto => reg 1 ]\n &expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1},\n // [ cmp eq reg 1 0x00000006 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{unix.IPPROTO_TCP},\n },\n // [ payload load 2b @ transport header + 0 => reg 1 ]\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseTransportHeader,\n Offset: 0, // TODO\n Len: 2, // TODO\n },\n // [ range neq reg 1 0x0000e807 0x0000ee07 ]\n &expr.Range{\n Op: expr.CmpOpNeq,\n Register: 1,\n FromData: binaryutil.BigEndian.PutUint16(uint16(2024)),\n ToData: binaryutil.BigEndian.PutUint16(uint16(2030)),\n },\n // [ immediate reg 0 return ]\n &expr.Verdict{\n Kind: expr.VerdictKind(unix.NFT_RETURN),\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestConfigureRangeIPv4(t *testing.T) {\n // The want byte sequences come from stracing nft(8), e.g.:\n // strace -f -v -x -s 2048 -eraw=sendto nft add rule filter forward ip saddr != 192.168.1.0-192.168.2.0 return\n //\n // The nft(8) command sequence was taken from:\n // https://wiki.nftables.org/wiki-nftables/index.php/Quick_reference-nftables_in_10_minutes#Tcp\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft flush ruleset\n []byte(\"\\x00\\x00\\x00\\x00\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain filter forward '{' type filter hook forward priority 0 \\; '}'\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0c\\x00\\x03\\x00\\x66\\x6f\\x72\\x77\\x61\\x72\\x64\\x00\\x14\\x00\\x04\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x02\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x0b\\x00\\x07\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\"),\n // nft add rule filter forward ip saddr != 192.168.1.0-192.168.2.0 return\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0c\\x00\\x02\\x00\\x66\\x6f\\x72\\x77\\x61\\x72\\x64\\x00\\xa4\\x00\\x04\\x80\\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\\x01\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x0c\\x08\\x00\\x04\\x00\\x00\\x00\\x00\\x04\\x3c\\x00\\x01\\x80\\x0a\\x00\\x01\\x00\\x72\\x61\\x6e\\x67\\x65\\x00\\x00\\x00\\x2c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x01\\x0c\\x00\\x03\\x80\\x08\\x00\\x01\\x00\\xc0\\xa8\\x01\\x00\\x0c\\x00\\x04\\x80\\x08\\x00\\x01\\x00\\xc0\\xa8\\x02\\x00\\x30\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x69\\x6d\\x6d\\x65\\x64\\x69\\x61\\x74\\x65\\x00\\x00\\x00\\x1c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x10\\x00\\x02\\x80\\x0c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\xff\\xff\\xff\\xfb\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n forward := c.AddChain(&nftables.Chain{\n Name: \"forward\",\n Table: filter,\n Type: nftables.ChainTypeFilter,\n Hooknum: nftables.ChainHookForward,\n Priority: nftables.ChainPriorityFilter,\n })\n\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: forward,\n Exprs: []expr.Any{\n // [ payload load 4b @ network header + 12 => reg 1 ]\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseNetworkHeader,\n Offset: 12, // TODO\n Len: 4, // TODO\n },\n // [ range neq reg 1 0x0000e807 0x0000ee07 ]\n &expr.Range{\n Op: expr.CmpOpNeq,\n Register: 1,\n FromData: net.ParseIP(\"192.168.1.0\").To4(),\n ToData: net.ParseIP(\"192.168.2.0\").To4(),\n },\n // [ immediate reg 0 return ]\n &expr.Verdict{\n Kind: expr.VerdictKind(unix.NFT_RETURN),\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestConfigureRangeIPv6(t *testing.T) {\n // The want byte sequences come from stracing nft(8), e.g.:\n // strace -f -v -x -s 2048 -eraw=sendto nft add rule ip6 filter forward ip6 saddr != 2001:0001::1-2001:0002::1 return\n //\n // The nft(8) command sequence was taken from:\n // https://wiki.nftables.org/wiki-nftables/index.php/Quick_reference-nftables_in_10_minutes#Tcp\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft flush ruleset\n []byte(\"\\x00\\x00\\x00\\x00\"),\n // nft add table ip6 filter\n []byte(\"\\x0a\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain ip6 filter forward '{' type filter hook forward priority 0 \\; '}'\n []byte(\"\\x0a\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0c\\x00\\x03\\x00\\x66\\x6f\\x72\\x77\\x61\\x72\\x64\\x00\\x14\\x00\\x04\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x02\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x0b\\x00\\x07\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\"),\n // nft add rule ip6 filter forward ip6 saddr != 2001:0001::1-2001:0002::1 return\n []byte(\"\\x0a\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0c\\x00\\x02\\x00\\x66\\x6f\\x72\\x77\\x61\\x72\\x64\\x00\\xbc\\x00\\x04\\x80\\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\\x01\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x08\\x08\\x00\\x04\\x00\\x00\\x00\\x00\\x10\\x54\\x00\\x01\\x80\\x0a\\x00\\x01\\x00\\x72\\x61\\x6e\\x67\\x65\\x00\\x00\\x00\\x44\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x01\\x18\\x00\\x03\\x80\\x14\\x00\\x01\\x00\\x20\\x01\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x01\\x18\\x00\\x04\\x80\\x14\\x00\\x01\\x00\\x20\\x01\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x01\\x30\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x69\\x6d\\x6d\\x65\\x64\\x69\\x61\\x74\\x65\\x00\\x00\\x00\\x1c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x10\\x00\\x02\\x80\\x0c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\xff\\xff\\xff\\xfb\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv6,\n Name: \"filter\",\n })\n\n forward := c.AddChain(&nftables.Chain{\n Name: \"forward\",\n Table: filter,\n Type: nftables.ChainTypeFilter,\n Hooknum: nftables.ChainHookForward,\n Priority: nftables.ChainPriorityFilter,\n })\n\n ip1 := net.ParseIP(\"2001:0001::1\").To16()\n ip2 := net.ParseIP(\"2001:0002::1\").To16()\n\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: forward,\n Exprs: []expr.Any{\n // [ payload load 16b @ network header + 8 => reg 1 ]\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseNetworkHeader,\n Offset: 8, // TODO\n Len: 16, // TODO\n },\n // [ range neq reg 1 0x01000120 0x00000000 0x00000000 0x01000000 0x02000120 0x00000000 0x00000000 0x01000000 ]\n &expr.Range{\n Op: expr.CmpOpNeq,\n Register: 1,\n FromData: ip1,\n ToData: ip2,\n },\n // [ immediate reg 0 return ]\n &expr.Verdict{\n Kind: expr.VerdictKind(unix.NFT_RETURN),\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestSet4(t *testing.T) {\n // The want byte sequences come from stracing nft(8), e.g.:\n // strace-4.21 -f -v -x -s 2048 -etrace=sendto nft add table ip nat\n //\n // Until https://github.com/strace/strace/issues/100 is resolved,\n // you need to use strace 4.21 or apply the patch in the issue.\n //\n // Additional details can be obtained by specifying the --debug=all option\n // when calling nft(8).\n want := [][]byte{\n\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n\n // table ip ipv4table {\n // set test-set {\n // type inet_service\n // flags constant\n // elements = { 12000, 12001, 12345, 12346 }\n // }\n //\n // chain ipv4chain-2 {\n // type nat hook prerouting priority dstnat; policy accept;\n // tcp dport @test-set\n // }\n // }\n\n []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\"),\n\n []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\"),\n\n []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\"),\n\n []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\"),\n\n []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\"),\n\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n tbl := &nftables.Table{\n Name: \"ipv4table\",\n Family: nftables.TableFamilyIPv4,\n }\n defPol := nftables.ChainPolicyAccept\n ch := &nftables.Chain{\n Name: \"ipv4chain-2\",\n Table: tbl,\n Type: nftables.ChainTypeNAT,\n Priority: nftables.ChainPriorityNATDest,\n Hooknum: nftables.ChainHookPrerouting,\n Policy: &defPol,\n }\n set := nftables.Set{\n Anonymous: false,\n Constant: true,\n Name: \"test-set\",\n ID: uint32(1), //rand.Intn(0xffff)),\n Table: tbl,\n KeyType: nftables.TypeInetService,\n }\n c.AddTable(tbl)\n c.AddChain(ch)\n\n re := []expr.Any{}\n re = append(re, &expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1})\n re = append(re, &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{unix.IPPROTO_TCP},\n })\n re = append(re, &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseTransportHeader,\n Offset: 2, // Offset for a transport protocol header\n Len: 2, // 2 bytes for port\n })\n re = append(re, &expr.Lookup{\n SourceRegister: 1,\n Invert: false,\n SetID: set.ID,\n SetName: set.Name,\n })\n\n ports := []uint16{12000, 12001, 12345, 12346}\n setElements := make([]nftables.SetElement, len(ports))\n for i := 0; i < len(ports); i++ {\n setElements[i].Key = binaryutil.BigEndian.PutUint16(ports[i])\n }\n\n if err := c.AddSet(&set, setElements); err != nil {\n t.Fatal(err)\n }\n\n c.AddRule(&nftables.Rule{\n Table: tbl,\n Chain: ch,\n Exprs: re,\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestMasq(t *testing.T) {\n tests := []struct {\n name string\n chain *nftables.Chain\n want [][]byte\n masqExprs []expr.Any\n }{\n {\n name: \"Masquerada\",\n chain: &nftables.Chain{\n Name: \"base-chain\",\n },\n want: [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain ip filter base-chain\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x03\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\"),\n // nft add rule ip filter base-chain ip protocol tcp masquerade\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x02\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\x78\\x00\\x04\\x80\\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\\x01\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x09\\x08\\x00\\x04\\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\\x14\\x00\\x01\\x80\\x09\\x00\\x01\\x00\\x6d\\x61\\x73\\x71\\x00\\x00\\x00\\x00\\x04\\x00\\x02\\x80\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n },\n masqExprs: []expr.Any{\n &expr.Masq{},\n },\n },\n {\n name: \"Masquerada with flags\",\n chain: &nftables.Chain{\n Name: \"base-chain\",\n },\n want: [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain ip filter base-chain\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x03\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\"),\n // nft add rule ip filter base-chain ip protocol tcp masquerade random,fully-random,persistent\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x02\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\x80\\x00\\x04\\x80\\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\\x01\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x09\\x08\\x00\\x04\\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\\x1c\\x00\\x01\\x80\\x09\\x00\\x01\\x00\\x6d\\x61\\x73\\x71\\x00\\x00\\x00\\x00\\x0c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x1c\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n },\n masqExprs: []expr.Any{\n &expr.Masq{Random: true, FullyRandom: true, Persistent: true, ToPorts: false},\n },\n },\n {\n name: \"Masquerada with 1 port\",\n chain: &nftables.Chain{\n Name: \"base-chain\",\n },\n want: [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain ip filter base-chain\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x03\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\"),\n // nft add rule ip filter base-chain ip protocol tcp masquerade to :1024\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x02\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\xac\\x00\\x04\\x80\\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\\x01\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x09\\x08\\x00\\x04\\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\\x2c\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x69\\x6d\\x6d\\x65\\x64\\x69\\x61\\x74\\x65\\x00\\x00\\x00\\x18\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x0c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x04\\x00\\x00\\x00\\x1c\\x00\\x01\\x80\\x09\\x00\\x01\\x00\\x6d\\x61\\x73\\x71\\x00\\x00\\x00\\x00\\x0c\\x00\\x02\\x80\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x01\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n },\n masqExprs: []expr.Any{\n &expr.Immediate{Register: 1, Data: binaryutil.BigEndian.PutUint32(uint32(1024) << 16)},\n &expr.Masq{ToPorts: true, RegProtoMin: 1},\n },\n },\n {\n name: \"Masquerada with port range\",\n chain: &nftables.Chain{\n Name: \"base-chain\",\n },\n want: [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain ip filter base-chain\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x03\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\"),\n // nft add rule ip filter base-chain ip protocol tcp masquerade to :1024-2044\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x02\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\xe0\\x00\\x04\\x80\\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\\x01\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x09\\x08\\x00\\x04\\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\\x2c\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x69\\x6d\\x6d\\x65\\x64\\x69\\x61\\x74\\x65\\x00\\x00\\x00\\x18\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x0c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x04\\x00\\x00\\x00\\x2c\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x69\\x6d\\x6d\\x65\\x64\\x69\\x61\\x74\\x65\\x00\\x00\\x00\\x18\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x02\\x0c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x07\\xfc\\x00\\x00\\x24\\x00\\x01\\x80\\x09\\x00\\x01\\x00\\x6d\\x61\\x73\\x71\\x00\\x00\\x00\\x00\\x14\\x00\\x02\\x80\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x02\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n },\n masqExprs: []expr.Any{\n &expr.Immediate{Register: 1, Data: binaryutil.BigEndian.PutUint32(uint32(1024) << 16)},\n &expr.Immediate{Register: 2, Data: binaryutil.BigEndian.PutUint32(uint32(2044) << 16)},\n &expr.Masq{ToPorts: true, RegProtoMin: 1, RegProtoMax: 2},\n },\n },\n }\n\n for _, tt := range tests {\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(tt.want[idx]) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n got := b\n if !bytes.Equal(got, tt.want[idx]) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(tt.want[idx])))\n }\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n tt.chain.Table = filter\n chain := c.AddChain(tt.chain)\n exprs := []expr.Any{\n // [ payload load 1b @ network header + 9 => reg 1 ]\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseNetworkHeader,\n Offset: 9,\n Len: 1,\n },\n // [ cmp eq reg 1 0x00000006 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{unix.IPPROTO_TCP},\n },\n }\n exprs = append(exprs, tt.masqExprs...)\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: chain,\n Exprs: exprs,\n })\n if err := c.Flush(); err != nil {\n t.Fatalf(\"Test \\\"%s\\\" failed with error: %+v\", tt.name, err)\n }\n }\n}\n\nfunc TestReject(t *testing.T) {\n tests := []struct {\n name string\n chain *nftables.Chain\n want [][]byte\n rejectExprs []expr.Any\n }{\n {\n name: \"Reject\",\n chain: &nftables.Chain{\n Name: \"base-chain\",\n },\n want: [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain ip filter base-chain\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x03\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\"),\n // nft add rule ip filter base-chain reject\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x02\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\x28\\x00\\x04\\x80\\x24\\x00\\x01\\x80\\x0b\\x00\\x01\\x00\\x72\\x65\\x6a\\x65\\x63\\x74\\x00\\x00\\x14\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x05\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n },\n rejectExprs: []expr.Any{\n &expr.Reject{},\n },\n },\n {\n name: \"Reject with tcp reset\",\n chain: &nftables.Chain{\n Name: \"base-chain\",\n },\n want: [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain ip filter base-chain\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x03\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\"),\n // nft add rule ip filter base-chain reject with tcp reset\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x02\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\x28\\x00\\x04\\x80\\x24\\x00\\x01\\x80\\x0b\\x00\\x01\\x00\\x72\\x65\\x6a\\x65\\x63\\x74\\x00\\x00\\x14\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x05\\x00\\x02\\x00\\x01\\x00\\x00\\x00\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n },\n rejectExprs: []expr.Any{\n &expr.Reject{Type: unix.NFT_REJECT_TCP_RST, Code: unix.NFT_REJECT_TCP_RST},\n },\n },\n {\n name: \"Reject with icmp type host-unreachable\",\n chain: &nftables.Chain{\n Name: \"base-chain\",\n },\n want: [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain ip filter base-chain\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x03\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\"),\n // nft add rule ip filter base-chain reject with icmp type host-unreachable\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x02\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\x28\\x00\\x04\\x80\\x24\\x00\\x01\\x80\\x0b\\x00\\x01\\x00\\x72\\x65\\x6a\\x65\\x63\\x74\\x00\\x00\\x14\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x05\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n },\n rejectExprs: []expr.Any{\n &expr.Reject{Type: unix.NFT_REJECT_ICMP_UNREACH, Code: unix.NFT_REJECT_ICMP_UNREACH},\n },\n },\n }\n\n for _, tt := range tests {\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(tt.want[idx]) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n got := b\n if !bytes.Equal(got, tt.want[idx]) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(tt.want[idx])))\n }\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n tt.chain.Table = filter\n chain := c.AddChain(tt.chain)\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: chain,\n Exprs: tt.rejectExprs,\n })\n if err := c.Flush(); err != nil {\n t.Fatalf(\"Test \\\"%s\\\" failed with error: %+v\", tt.name, err)\n }\n }\n}\n\nfunc TestFib(t *testing.T) {\n tests := []struct {\n name string\n chain *nftables.Chain\n want [][]byte\n fibExprs []expr.Any\n }{\n {\n name: \"fib saddr type local\",\n chain: &nftables.Chain{\n Name: \"base-chain\",\n },\n want: [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain ip filter base-chain\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x03\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\"),\n // nft add rule ip filter base-chain fib saddr type local\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x02\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\x2c\\x00\\x04\\x80\\x28\\x00\\x01\\x80\\x08\\x00\\x01\\x00\\x66\\x69\\x62\\x00\\x1c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x03\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n },\n fibExprs: []expr.Any{\n &expr.Fib{\n Register: 1,\n FlagSADDR: true,\n ResultADDRTYPE: true,\n },\n },\n },\n {\n name: \"fib daddr type broadcast\",\n chain: &nftables.Chain{\n Name: \"base-chain\",\n },\n want: [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain ip filter base-chain\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x03\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\"),\n // nft add rule ip filter base-chain fib daddr type broadcast\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x02\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\x2c\\x00\\x04\\x80\\x28\\x00\\x01\\x80\\x08\\x00\\x01\\x00\\x66\\x69\\x62\\x00\\x1c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x02\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x03\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n },\n fibExprs: []expr.Any{\n &expr.Fib{\n Register: 1,\n FlagDADDR: true,\n ResultADDRTYPE: true,\n },\n },\n },\n {\n name: \"fib saddr . iif oif missing\",\n chain: &nftables.Chain{\n Name: \"base-chain\",\n },\n want: [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain ip filter base-chain\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x03\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\"),\n // nft add rule ip filter base-chain fib saddr . iif oif missing\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x02\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\x2c\\x00\\x04\\x80\\x28\\x00\\x01\\x80\\x08\\x00\\x01\\x00\\x66\\x69\\x62\\x00\\x1c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x09\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x01\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n },\n fibExprs: []expr.Any{\n &expr.Fib{\n Register: 1,\n FlagSADDR: true,\n FlagIIF: true,\n ResultOIF: true,\n },\n },\n },\n }\n\n for _, tt := range tests {\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(tt.want[idx]) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n got := b\n if !bytes.Equal(got, tt.want[idx]) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(tt.want[idx])))\n }\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n tt.chain.Table = filter\n chain := c.AddChain(tt.chain)\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: chain,\n Exprs: tt.fibExprs,\n })\n if err := c.Flush(); err != nil {\n t.Fatalf(\"Test \\\"%s\\\" failed with error: %+v\", tt.name, err)\n }\n }\n}\n\nfunc TestNumgen(t *testing.T) {\n tests := []struct {\n name string\n chain *nftables.Chain\n want [][]byte\n numgenExprs []expr.Any\n }{\n {\n name: \"numgen random\",\n chain: &nftables.Chain{\n Name: \"base-chain\",\n },\n want: [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain ip filter base-chain\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x03\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\"),\n // nft add rule ip filter base-chain numgen random mod 1 offset 0 vmap { 0 : drop }\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x02\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\x38\\x00\\x04\\x80\\x34\\x00\\x01\\x80\\x0b\\x00\\x01\\x00\\x6e\\x75\\x6d\\x67\\x65\\x6e\\x00\\x00\\x24\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x04\\x00\\x00\\x00\\x00\\x00\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n },\n numgenExprs: []expr.Any{\n &expr.Numgen{\n Register: 1,\n Type: unix.NFT_NG_RANDOM,\n Modulus: 0x1,\n Offset: 0,\n },\n },\n },\n {\n name: \"numgen incremental\",\n chain: &nftables.Chain{\n Name: \"base-chain\",\n },\n want: [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain ip filter base-chain\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x03\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\"),\n // nft add rule ip filter base-chain numgen inc mod 1 offset 0 vmap { 0 : drop }\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x02\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\x38\\x00\\x04\\x80\\x34\\x00\\x01\\x80\\x0b\\x00\\x01\\x00\\x6e\\x75\\x6d\\x67\\x65\\x6e\\x00\\x00\\x24\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x00\\x08\\x00\\x04\\x00\\x00\\x00\\x00\\x00\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n },\n numgenExprs: []expr.Any{\n &expr.Numgen{\n Register: 1,\n Type: unix.NFT_NG_INCREMENTAL,\n Modulus: 0x1,\n Offset: 0,\n },\n },\n },\n }\n\n for _, tt := range tests {\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(tt.want[idx]) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n got := b\n if !bytes.Equal(got, tt.want[idx]) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(tt.want[idx])))\n }\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n tt.chain.Table = filter\n chain := c.AddChain(tt.chain)\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: chain,\n Exprs: tt.numgenExprs,\n })\n if err := c.Flush(); err != nil {\n t.Fatalf(\"Test \\\"%s\\\" failed with error: %+v\", tt.name, err)\n }\n }\n}\n\nfunc TestMap(t *testing.T) {\n tests := []struct {\n name string\n chain *nftables.Chain\n want [][]byte\n set nftables.Set\n element []nftables.SetElement\n }{\n {\n name: \"map inet_service: inet_service 1 element\",\n chain: &nftables.Chain{\n Name: \"base-chain\",\n },\n want: [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain ip filter base-chain\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x03\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\"),\n // nft add map ip filter test-map { type inet_service: inet_service\\; elements={ 22: 1024 } \\; }\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0d\\x00\\x02\\x00\\x74\\x65\\x73\\x74\\x2d\\x6d\\x61\\x70\\x00\\x00\\x00\\x00\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x08\\x08\\x00\\x04\\x00\\x00\\x00\\x00\\x0d\\x08\\x00\\x05\\x00\\x00\\x00\\x00\\x02\\x08\\x00\\x0a\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x06\\x00\\x00\\x00\\x00\\x0d\\x08\\x00\\x07\\x00\\x00\\x00\\x00\\x02\"),\n []byte(\"\\x02\\x00\\x00\\x00\\x0d\\x00\\x02\\x00\\x74\\x65\\x73\\x74\\x2d\\x6d\\x61\\x70\\x00\\x00\\x00\\x00\\x08\\x00\\x04\\x00\\x00\\x00\\x00\\x01\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x20\\x00\\x03\\x80\\x1c\\x00\\x01\\x80\\x0c\\x00\\x01\\x80\\x06\\x00\\x01\\x00\\x00\\x16\\x00\\x00\\x0c\\x00\\x02\\x80\\x06\\x00\\x01\\x00\\x04\\x00\\x00\\x00\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n },\n set: nftables.Set{\n Name: \"test-map\",\n ID: uint32(1),\n KeyType: nftables.TypeInetService,\n DataType: nftables.TypeInetService,\n IsMap: true,\n },\n element: []nftables.SetElement{\n {\n Key: binaryutil.BigEndian.PutUint16(uint16(22)),\n Val: binaryutil.BigEndian.PutUint16(uint16(1024)),\n },\n },\n },\n }\n\n for _, tt := range tests {\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(tt.want[idx]) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n got := b\n if !bytes.Equal(got, tt.want[idx]) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(tt.want[idx])))\n }\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n tt.chain.Table = filter\n c.AddChain(tt.chain)\n tt.set.Table = filter\n c.AddSet(&tt.set, tt.element)\n if err := c.Flush(); err != nil {\n t.Fatalf(\"Test \\\"%s\\\" failed with error: %+v\", tt.name, err)\n }\n }\n}\n\nfunc TestVmap(t *testing.T) {\n tests := []struct {\n name string\n chain *nftables.Chain\n want [][]byte\n set nftables.Set\n element []nftables.SetElement\n }{\n {\n name: \"map inet_service: drop verdict\",\n chain: &nftables.Chain{\n Name: \"base-chain\",\n },\n want: [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain ip filter base-chain\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x03\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\"),\n // nft add map ip filter test-vmap { type inet_service: verdict\\; elements={ 22: drop } \\; }\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0e\\x00\\x02\\x00\\x74\\x65\\x73\\x74\\x2d\\x76\\x6d\\x61\\x70\\x00\\x00\\x00\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x08\\x08\\x00\\x04\\x00\\x00\\x00\\x00\\x0d\\x08\\x00\\x05\\x00\\x00\\x00\\x00\\x02\\x08\\x00\\x0a\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x06\\x00\\xff\\xff\\xff\\x00\\x08\\x00\\x07\\x00\\x00\\x00\\x00\\x00\"),\n []byte(\"\\x02\\x00\\x00\\x00\\x0e\\x00\\x02\\x00\\x74\\x65\\x73\\x74\\x2d\\x76\\x6d\\x61\\x70\\x00\\x00\\x00\\x08\\x00\\x04\\x00\\x00\\x00\\x00\\x01\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x24\\x00\\x03\\x80\\x20\\x00\\x01\\x80\\x0c\\x00\\x01\\x80\\x06\\x00\\x01\\x00\\x00\\x16\\x00\\x00\\x10\\x00\\x02\\x80\\x0c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n },\n set: nftables.Set{\n Name: \"test-vmap\",\n ID: uint32(1),\n KeyType: nftables.TypeInetService,\n DataType: nftables.TypeVerdict,\n IsMap: true,\n },\n element: []nftables.SetElement{\n {\n Key: binaryutil.BigEndian.PutUint16(uint16(22)),\n VerdictData: &expr.Verdict{\n Kind: expr.VerdictDrop,\n },\n },\n },\n }, {\n name: \"map inet_service: jump to chain verdict\",\n chain: &nftables.Chain{\n Name: \"base-chain\",\n },\n want: [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain ip filter base-chain\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x03\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\"),\n // nft add map ip filter test-vmap { type inet_service: verdict\\; elements={ 22: jump fake-chain } \\; }\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0e\\x00\\x02\\x00\\x74\\x65\\x73\\x74\\x2d\\x76\\x6d\\x61\\x70\\x00\\x00\\x00\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x08\\x08\\x00\\x04\\x00\\x00\\x00\\x00\\x0d\\x08\\x00\\x05\\x00\\x00\\x00\\x00\\x02\\x08\\x00\\x0a\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x06\\x00\\xff\\xff\\xff\\x00\\x08\\x00\\x07\\x00\\x00\\x00\\x00\\x00\"),\n []byte(\"\\x02\\x00\\x00\\x00\\x0e\\x00\\x02\\x00\\x74\\x65\\x73\\x74\\x2d\\x76\\x6d\\x61\\x70\\x00\\x00\\x00\\x08\\x00\\x04\\x00\\x00\\x00\\x00\\x01\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x34\\x00\\x03\\x80\\x30\\x00\\x01\\x80\\x0c\\x00\\x01\\x80\\x06\\x00\\x01\\x00\\x00\\x16\\x00\\x00\\x20\\x00\\x02\\x80\\x1c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\xff\\xff\\xff\\xfd\\x0f\\x00\\x02\\x00\\x66\\x61\\x6b\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n },\n set: nftables.Set{\n Name: \"test-vmap\",\n ID: uint32(1),\n KeyType: nftables.TypeInetService,\n DataType: nftables.TypeVerdict,\n IsMap: true,\n },\n element: []nftables.SetElement{\n {\n Key: binaryutil.BigEndian.PutUint16(uint16(22)),\n VerdictData: &expr.Verdict{\n Kind: unix.NFT_JUMP,\n Chain: \"fake-chain\",\n },\n },\n },\n },\n }\n\n for _, tt := range tests {\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(tt.want[idx]) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n got := b\n if !bytes.Equal(got, tt.want[idx]) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(tt.want[idx])))\n }\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n tt.chain.Table = filter\n c.AddChain(tt.chain)\n tt.set.Table = filter\n c.AddSet(&tt.set, tt.element)\n if err := c.Flush(); err != nil {\n t.Fatalf(\"Test \\\"%s\\\" failed with error: %+v\", tt.name, err)\n }\n }\n}\n\nfunc TestJHash(t *testing.T) {\n // The want byte sequences come from stracing nft(8), e.g.:\n // strace -f -v -x -s 2048 -eraw=sendto nft add rule filter prerouting mark set jhash ip saddr mod 2\n //\n // The nft(8) command sequence was taken from:\n // https://wiki.nftables.org/wiki-nftables/index.php/Quick_reference-nftables_in_10_minutes#Tcp\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft flush ruleset\n []byte(\"\\x00\\x00\\x00\\x00\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain ip filter base-chain { type filter hook prerouting priority 0 \\; }\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x03\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\x14\\x00\\x04\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x0b\\x00\\x07\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\"),\n // nft add rule filter base_chain mark set jhash ip saddr mod 2 seed 0xfeedcafe offset 1\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x02\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\xa8\\x00\\x04\\x80\\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\\x02\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x0c\\x08\\x00\\x04\\x00\\x00\\x00\\x00\\x04\\x4c\\x00\\x01\\x80\\x09\\x00\\x01\\x00\\x68\\x61\\x73\\x68\\x00\\x00\\x00\\x00\\x3c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x02\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x04\\x08\\x00\\x04\\x00\\x00\\x00\\x00\\x02\\x08\\x00\\x05\\x00\\xfe\\xed\\xca\\xfe\\x08\\x00\\x06\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x07\\x00\\x00\\x00\\x00\\x00\\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\\x03\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x01\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n forward := c.AddChain(&nftables.Chain{\n Name: \"base-chain\",\n Table: filter,\n Type: nftables.ChainTypeFilter,\n Hooknum: nftables.ChainHookPrerouting,\n Priority: nftables.ChainPriorityFilter,\n })\n\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: forward,\n Exprs: []expr.Any{\n // [ payload load 4b @ network header + 12 => reg 2 ]\n &expr.Payload{\n DestRegister: 2,\n Base: expr.PayloadBaseNetworkHeader,\n Offset: 12,\n Len: 4,\n },\n // [ hash reg 1 = jhash(reg 2, 4, 0xfeedcafe) % mod 2 offset 1 ]\n &expr.Hash{\n SourceRegister: 2,\n DestRegister: 1,\n Length: 4,\n Modulus: 2,\n Seed: 4276996862,\n Offset: 1,\n Type: expr.HashTypeJenkins,\n },\n // [ meta set mark with reg 1 ]\n &expr.Meta{\n Key: expr.MetaKeyMARK,\n SourceRegister: true,\n Register: 1,\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestDup(t *testing.T) {\n\n // The want byte sequences come from stracing nft(8), e.g.:\n // strace -f -v -x -s 2048 -eraw=sendto nft add rule filter prerouting mark set jhash ip saddr mod 2\n //\n // The nft(8) command sequence was taken from:\n // https://wiki.nftables.org/wiki-nftables/index.php/Quick_reference-nftables_in_10_minutes#Tcp\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n\n // nft flush ruleset\n []byte(\"\\x00\\x00\\x00\\x00\"),\n\n // nft add table ip mangle\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x6d\\x61\\x6e\\x67\\x6c\\x65\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n\n // nft add chain ip mangle base-chain { type filter hook prerouting priority 0 \\; }\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x6d\\x61\\x6e\\x67\\x6c\\x65\\x00\\x00\\x0f\\x00\\x03\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\x14\\x00\\x04\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x0b\\x00\\x07\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\"),\n\n // nft add rule mangle base-chain dup to 127.0.0.50 device lo\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x6d\\x61\\x6e\\x67\\x6c\\x65\\x00\\x00\\x0f\\x00\\x02\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\x7c\\x00\\x04\\x80\\x2c\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x69\\x6d\\x6d\\x65\\x64\\x69\\x61\\x74\\x65\\x00\\x00\\x00\\x18\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x0c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x7f\\x00\\x00\\x32\\x2c\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x69\\x6d\\x6d\\x65\\x64\\x69\\x61\\x74\\x65\\x00\\x00\\x00\\x18\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x02\\x0c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x01\\x00\\x00\\x00\\x20\\x00\\x01\\x80\\x08\\x00\\x01\\x00\\x64\\x75\\x70\\x00\\x14\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x02\"),\n\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.FlushRuleset()\n\n mangle := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"mangle\",\n })\n\n prerouting := c.AddChain(&nftables.Chain{\n Name: \"base-chain\",\n Table: mangle,\n Type: nftables.ChainTypeFilter,\n Hooknum: nftables.ChainHookPrerouting,\n Priority: nftables.ChainPriorityFilter,\n })\n\n lo, err := net.InterfaceByName(\"lo\")\n\n if err != nil {\n t.Fatal(err)\n }\n\n c.AddRule(&nftables.Rule{\n Table: mangle,\n Chain: prerouting,\n Exprs: []expr.Any{\n // [ immediate reg 1 0x3200007f ]\n &expr.Immediate{\n Register: 1,\n Data: net.ParseIP(\"127.0.0.50\").To4(),\n },\n // [ immediate reg 2 0x00000001 ]\n &expr.Immediate{\n Register: 2,\n Data: binaryutil.NativeEndian.PutUint32(uint32(lo.Index)),\n },\n // [ dup sreg_addr 1 sreg_dev 2 ]\n &expr.Dup{\n RegAddr: 1,\n RegDev: 2,\n IsRegDevSet: true,\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestDupWoDev(t *testing.T) {\n\n // The want byte sequences come from stracing nft(8), e.g.:\n // strace -f -v -x -s 2048 -eraw=sendto nft add rule filter prerouting mark set jhash ip saddr mod 2\n //\n // The nft(8) command sequence was taken from:\n // https://wiki.nftables.org/wiki-nftables/index.php/Quick_reference-nftables_in_10_minutes#Tcp\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n\n // nft flush ruleset\n []byte(\"\\x00\\x00\\x00\\x00\"),\n\n // nft add table ip mangle\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x6d\\x61\\x6e\\x67\\x6c\\x65\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n\n // nft add chain ip mangle base-chain { type filter hook prerouting priority 0 \\; }\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x6d\\x61\\x6e\\x67\\x6c\\x65\\x00\\x00\\x0f\\x00\\x03\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\x14\\x00\\x04\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x0b\\x00\\x07\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\"),\n\n // nft add rule mangle base-chain dup to 127.0.0.50\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x6d\\x61\\x6e\\x67\\x6c\\x65\\x00\\x00\\x0f\\x00\\x02\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\x48\\x00\\x04\\x80\\x2c\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x69\\x6d\\x6d\\x65\\x64\\x69\\x61\\x74\\x65\\x00\\x00\\x00\\x18\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x0c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x7f\\x00\\x00\\x32\\x18\\x00\\x01\\x80\\x08\\x00\\x01\\x00\\x64\\x75\\x70\\x00\\x0c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\"),\n\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.FlushRuleset()\n\n mangle := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"mangle\",\n })\n\n prerouting := c.AddChain(&nftables.Chain{\n Name: \"base-chain\",\n Table: mangle,\n Type: nftables.ChainTypeFilter,\n Hooknum: nftables.ChainHookPrerouting,\n Priority: nftables.ChainPriorityFilter,\n })\n\n c.AddRule(&nftables.Rule{\n Table: mangle,\n Chain: prerouting,\n Exprs: []expr.Any{\n // [ immediate reg 1 0x3200007f ]\n &expr.Immediate{\n Register: 1,\n Data: net.ParseIP(\"127.0.0.50\").To4(),\n },\n // [ dup sreg_addr 1 sreg_dev 2 ]\n &expr.Dup{\n RegAddr: 1,\n IsRegDevSet: false,\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestNotrack(t *testing.T) {\n // The want byte sequences come from stracing nft(8), e.g.:\n // strace -f -v -x -s 2048 -eraw=sendto nft add rule filter prerouting mark set jhash ip saddr mod 2\n //\n // The nft(8) command sequence was taken from:\n // https://wiki.nftables.org/wiki-nftables/index.php/Quick_reference-nftables_in_10_minutes#Tcp\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft flush ruleset\n []byte(\"\\x00\\x00\\x00\\x00\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain ip filter base-chain { type filter hook prerouting priority 0 \\; }\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x03\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\x14\\x00\\x04\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x0b\\x00\\x07\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\"),\n // nft add rule filter base_chain notrack\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x02\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\x14\\x00\\x04\\x80\\x10\\x00\\x01\\x80\\x0c\\x00\\x01\\x00\\x6e\\x6f\\x74\\x72\\x61\\x63\\x6b\\x00\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n nftest.MatchRulesetBytes(t,\n func(c *nftables.Conn) {\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n prerouting := c.AddChain(&nftables.Chain{\n Name: \"base-chain\",\n Table: filter,\n Type: nftables.ChainTypeFilter,\n Hooknum: nftables.ChainHookPrerouting,\n Priority: nftables.ChainPriorityFilter,\n })\n\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: prerouting,\n Exprs: []expr.Any{\n // [ notrack ]\n &expr.Notrack{},\n },\n })\n },\n want)\n}\n\nfunc TestQuota(t *testing.T) {\n\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft flush ruleset\n []byte(\"\\x00\\x00\\x00\\x00\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain ip filter regular-chain\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x12\\x00\\x03\\x00\\x72\\x65\\x67\\x75\\x6c\\x61\\x72\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\x00\"),\n // nft add rule ip filter regular-chain quota over 6 bytes\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x12\\x00\\x02\\x00\\x72\\x65\\x67\\x75\\x6c\\x61\\x72\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\x00\\x38\\x00\\x04\\x80\\x34\\x00\\x01\\x80\\x0a\\x00\\x01\\x00\\x71\\x75\\x6f\\x74\\x61\\x00\\x00\\x00\\x24\\x00\\x02\\x80\\x0c\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x06\\x0c\\x00\\x04\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x01\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want[idx]) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n got := b\n if !bytes.Equal(got, want[idx]) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want[idx])))\n }\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n output := c.AddChain(&nftables.Chain{\n Name: \"regular-chain\",\n Table: filter,\n })\n\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: output,\n Exprs: []expr.Any{\n // [ quota bytes 6 consumed 0 flags 1 ]\n &expr.Quota{\n Bytes: 6,\n Consumed: 0,\n Over: true,\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestStatelessNAT(t *testing.T) {\n // The want byte sequences come from stracing nft(8), e.g.:\n // strace -f -v -x -s 2048 -eraw=sendto nft add rule filter prerouting mark set jhash ip saddr mod 2\n //\n // The nft(8) command sequence was taken from:\n // https://wiki.nftables.org/wiki-nftables/index.php/Quick_reference-nftables_in_10_minutes#Tcp\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft flush ruleset\n []byte(\"\\x00\\x00\\x00\\x00\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain ip filter base-chain { type filter hook prerouting priority 0 \\; }\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x03\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\x14\\x00\\x04\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x0b\\x00\\x07\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\"),\n // nft add rule ip filter base-chain ip daddr set 192.168.1.1 notrack\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x02\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\x8c\\x00\\x04\\x80\\x2c\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x69\\x6d\\x6d\\x65\\x64\\x69\\x61\\x74\\x65\\x00\\x00\\x00\\x18\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x0c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\xc0\\xa8\\x01\\x01\\x4c\\x00\\x01\\x80\\x0c\\x00\\x01\\x00\\x70\\x61\\x79\\x6c\\x6f\\x61\\x64\\x00\\x3c\\x00\\x02\\x80\\x08\\x00\\x05\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x10\\x08\\x00\\x04\\x00\\x00\\x00\\x00\\x04\\x08\\x00\\x06\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x07\\x00\\x00\\x00\\x00\\x0a\\x08\\x00\\x08\\x00\\x00\\x00\\x00\\x01\\x10\\x00\\x01\\x80\\x0c\\x00\\x01\\x00\\x6e\\x6f\\x74\\x72\\x61\\x63\\x6b\\x00\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n forward := c.AddChain(&nftables.Chain{\n Name: \"base-chain\",\n Table: filter,\n Type: nftables.ChainTypeFilter,\n Hooknum: nftables.ChainHookPrerouting,\n Priority: nftables.ChainPriorityFilter,\n })\n\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: forward,\n Exprs: []expr.Any{\n &expr.Immediate{\n Register: 1,\n Data: net.ParseIP(\"192.168.1.1\").To4(),\n },\n // [ payload write reg 1 => 4b @ network header + 16 csum_type 1 csum_off 10 csum_flags 0x1 ]\n &expr.Payload{\n OperationType: expr.PayloadWrite,\n SourceRegister: 1,\n Base: expr.PayloadBaseNetworkHeader,\n Offset: 16,\n Len: 4,\n CsumType: expr.CsumTypeInet,\n CsumOffset: 10,\n CsumFlags: unix.NFT_PAYLOAD_L4CSUM_PSEUDOHDR,\n },\n // [ notrack ]\n &expr.Notrack{},\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestGetRulesObjref(t *testing.T) {\n // Create a new network namespace to test these operations,\n // and tear down the namespace at test completion.\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n // Clear all rules at the beginning + end of the test.\n c.FlushRuleset()\n defer c.FlushRuleset()\n\n table := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n chain := c.AddChain(&nftables.Chain{\n Name: \"forward\",\n Table: table,\n Type: nftables.ChainTypeFilter,\n Hooknum: nftables.ChainHookForward,\n Priority: nftables.ChainPriorityFilter,\n })\n\n counterName := \"fwded1\"\n c.AddObj(&nftables.CounterObj{\n Table: table,\n Name: counterName,\n Bytes: 1,\n Packets: 1,\n })\n\n counterRule := c.AddRule(&nftables.Rule{\n Table: table,\n Chain: chain,\n Exprs: []expr.Any{\n &expr.Objref{\n Type: 1,\n Name: counterName,\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Errorf(\"c.Flush() failed: %v\", err)\n }\n\n rules, err := c.GetRules(table, chain)\n if err != nil {\n t.Fatal(err)\n }\n\n if got, want := len(rules), 1; got != want {\n t.Fatalf(\"unexpected number of rules: got %d, want %d\", got, want)\n }\n if got, want := len(rules[0].Exprs), 1; got != want {\n t.Fatalf(\"unexpected number of exprs: got %d, want %d\", got, want)\n }\n objref, objrefOk := rules[0].Exprs[0].(*expr.Objref)\n if !objrefOk {\n t.Fatalf(\"Exprs[0] is type %T, want *expr.Objref\", rules[0].Exprs[0])\n }\n if want := counterRule.Exprs[0]; !reflect.DeepEqual(objref, want) {\n t.Errorf(\"objref expr = %+v, wanted %+v\", objref, want)\n }\n}\n\nfunc TestGetRulesQueue(t *testing.T) {\n // Create a new network namespace to test these operations,\n // and tear down the namespace at test completion.\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n // Clear all rules at the beginning + end of the test.\n c.FlushRuleset()\n defer c.FlushRuleset()\n\n table := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n chain := c.AddChain(&nftables.Chain{\n Name: \"forward\",\n Table: table,\n Type: nftables.ChainTypeFilter,\n Hooknum: nftables.ChainHookForward,\n Priority: nftables.ChainPriorityFilter,\n })\n\n queueRule := c.AddRule(&nftables.Rule{\n Table: table,\n Chain: chain,\n Exprs: []expr.Any{\n &expr.Queue{\n Num: 1000,\n Flag: expr.QueueFlagBypass,\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Errorf(\"c.Flush() failed: %v\", err)\n }\n\n rules, err := c.GetRules(table, chain)\n if err != nil {\n t.Fatal(err)\n }\n\n if got, want := len(rules), 1; got != want {\n t.Fatalf(\"unexpected number of rules: got %d, want %d\", got, want)\n }\n if got, want := len(rules[0].Exprs), 1; got != want {\n t.Fatalf(\"unexpected number of exprs: got %d, want %d\", got, want)\n }\n queueExpr, ok := rules[0].Exprs[0].(*expr.Queue)\n if !ok {\n t.Fatalf(\"Exprs[0] is type %T, want *expr.Queue\", rules[0].Exprs[0])\n }\n if want := queueRule.Exprs[0]; !reflect.DeepEqual(queueExpr, want) {\n t.Errorf(\"queue expr = %+v, wanted %+v\", queueExpr, want)\n }\n}\n\nfunc TestNftablesCompat(t *testing.T) {\n // Create a new network namespace to test these operations,\n // and tear down the namespace at test completion.\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n // Clear all rules at the beginning + end of the test.\n c.FlushRuleset()\n defer c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n input := c.AddChain(&nftables.Chain{\n Name: \"input\",\n Table: filter,\n Type: nftables.ChainTypeFilter,\n Hooknum: nftables.ChainHookInput,\n Priority: nftables.ChainPriorityFilter,\n })\n\n // -tcp --dport 0:65534 --sport 0:65534\n tcpMatch := &expr.Match{\n Name: \"tcp\",\n Info: &xt.Tcp{\n SrcPorts: [2]uint16{0, 65534},\n DstPorts: [2]uint16{0, 65534},\n },\n }\n\n // -udp --dport 0:65534 --sport 0:65534\n udpMatch := &expr.Match{\n Name: \"udp\",\n Info: &xt.Udp{\n SrcPorts: [2]uint16{0, 65534},\n DstPorts: [2]uint16{0, 65534},\n },\n }\n\n // - j TCPMSS --set-mss 1460\n mess := xt.Unknown([]byte{1460 & 0xff, (1460 >> 8) & 0xff})\n tcpMessTarget := &expr.Target{\n Name: \"TCPMSS\",\n Info: &mess,\n }\n\n // -m state --state ESTABLISHED\n ctMatch := &expr.Match{\n Name: \"conntrack\",\n Rev: 1,\n Info: &xt.ConntrackMtinfo1{\n ConntrackMtinfoBase: xt.ConntrackMtinfoBase{\n MatchFlags: 0x2001,\n },\n StateMask: 0x02,\n },\n }\n\n // -p tcp --dport --dport 0:65534 --sport 0:65534 -m state --state ESTABLISHED -j TCPMSS --set-mss 1460\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: input,\n Exprs: []expr.Any{\n tcpMatch,\n ctMatch,\n tcpMessTarget,\n },\n })\n if err := c.Flush(); err != nil {\n t.Fatalf(\"add rule fail %#v\", err)\n }\n\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: input,\n Exprs: []expr.Any{\n udpMatch,\n &expr.Verdict{\n Kind: expr.VerdictAccept,\n },\n },\n })\n if err := c.Flush(); err != nil {\n t.Fatalf(\"add rule %#v fail\", err)\n }\n\n // -m state --state ESTABLISHED -j ACCEPT\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: input,\n Exprs: []expr.Any{\n ctMatch,\n &expr.Verdict{\n Kind: expr.VerdictAccept,\n },\n },\n })\n if err := c.Flush(); err != nil {\n t.Fatalf(\"add rule %#v fail\", err)\n }\n\n // -p udp --dport --dport 0:65534 --sport 0:65534 -m state --state ESTABLISHED -j ACCEPT\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: input,\n Exprs: []expr.Any{\n tcpMatch,\n udpMatch,\n ctMatch,\n &expr.Verdict{\n Kind: expr.VerdictAccept,\n },\n },\n })\n if err := c.Flush(); err == nil {\n t.Fatalf(\"compat policy should conflict and err should not be err\")\n }\n}\n")))
[client-notification] Sat Dec 10 13:24:54 2022:
(:jsonrpc "2.0" :method "workspace/didChangeConfiguration" :params
(:settings #s(hash-table size 1 test eql rehash-size 1.5 rehash-threshold 0.8125 data
())))
[internal] Sat Dec 10 13:25:06 2022:
(:message "Running language server: (gopls -rpc.trace -debug=localhost:9040 -logfile=/tmp/gopls.log)")
[client-request] (id:1) Sat Dec 10 13:25:06 2022:
(:jsonrpc "2.0" :id 1 :method "initialize" :params
(:processId 336544 :rootPath "/home/michael/go/src/github.com/google/nftables/" :rootUri "file:///home/michael/go/src/github.com/google/nftables" :initializationOptions #s(hash-table size 1 test eql rehash-size 1.5 rehash-threshold 0.8125 data
())
:capabilities
(:workspace
(:applyEdit t :executeCommand
(:dynamicRegistration :json-false)
:workspaceEdit
(:documentChanges t)
:didChangeWatchedFiles
(:dynamicRegistration t)
:symbol
(:dynamicRegistration :json-false)
:configuration t :workspaceFolders t)
:textDocument
(:synchronization
(:dynamicRegistration :json-false :willSave t :willSaveWaitUntil t :didSave t)
:completion
(:dynamicRegistration :json-false :completionItem
(:snippetSupport :json-false :deprecatedSupport t :tagSupport
(:valueSet
[1]))
:contextSupport t)
:hover
(:dynamicRegistration :json-false :contentFormat
["markdown" "plaintext"])
:signatureHelp
(:dynamicRegistration :json-false :signatureInformation
(:parameterInformation
(:labelOffsetSupport t)
:activeParameterSupport t))
:references
(:dynamicRegistration :json-false)
:definition
(:dynamicRegistration :json-false :linkSupport t)
:declaration
(:dynamicRegistration :json-false :linkSupport t)
:implementation
(:dynamicRegistration :json-false :linkSupport t)
:typeDefinition
(:dynamicRegistration :json-false :linkSupport t)
:documentSymbol
(:dynamicRegistration :json-false :hierarchicalDocumentSymbolSupport t :symbolKind
(:valueSet
[1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26]))
:documentHighlight
(:dynamicRegistration :json-false)
:codeAction
(:dynamicRegistration :json-false :codeActionLiteralSupport
(:codeActionKind
(:valueSet
["quickfix" "refactor" "refactor.extract" "refactor.inline" "refactor.rewrite" "source" "source.organizeImports"]))
:isPreferredSupport t)
:formatting
(:dynamicRegistration :json-false)
:rangeFormatting
(:dynamicRegistration :json-false)
:rename
(:dynamicRegistration :json-false)
:publishDiagnostics
(:relatedInformation :json-false :codeDescriptionSupport :json-false :tagSupport
(:valueSet
[1 2])))
:experimental #s(hash-table size 1 test eql rehash-size 1.5 rehash-threshold 0.8125 data
()))
:workspaceFolders
[(:uri "file:///home/michael/go/src/github.com/google/nftables" :name "~/go/src/github.com/google/nftables/")]))
[server-reply] (id:1) Sat Dec 10 13:25:06 2022:
(:jsonrpc "2.0" :result
(:capabilities
(:textDocumentSync
(:openClose t :change 2 :save nil)
:completionProvider
(:triggerCharacters
["."])
:hoverProvider t :signatureHelpProvider
(:triggerCharacters
["(" ","])
:definitionProvider t :typeDefinitionProvider t :implementationProvider t :referencesProvider t :documentHighlightProvider t :documentSymbolProvider t :codeActionProvider
(:codeActionKinds
["quickfix" "refactor.extract" "refactor.rewrite" "source.fixAll" "source.organizeImports"])
:codeLensProvider nil :documentLinkProvider nil :workspaceSymbolProvider t :documentFormattingProvider t :renameProvider t :foldingRangeProvider t :executeCommandProvider
(:commands
["gopls.add_dependency" "gopls.add_import" "gopls.apply_fix" "gopls.check_upgrades" "gopls.edit_go_directive" "gopls.gc_details" "gopls.generate" "gopls.generate_gopls_mod" "gopls.go_get_package" "gopls.list_imports" "gopls.list_known_packages" "gopls.regenerate_cgo" "gopls.remove_dependency" "gopls.reset_go_mod_diagnostics" "gopls.run_tests" "gopls.run_vulncheck_exp" "gopls.start_debugging" "gopls.test" "gopls.tidy" "gopls.toggle_gc_details" "gopls.update_go_sum" "gopls.upgrade_dependency" "gopls.vendor"])
:callHierarchyProvider t :inlayHintProvider nil :workspace
(:workspaceFolders
(:supported t :changeNotifications "workspace/didChangeWorkspaceFolders")
:fileOperations nil))
:serverInfo
(:name "gopls" :version "{\"GoVersion\":\"go1.19.3\",\"Path\":\"golang.org/x/tools/gopls\",\"Main\":{\"Path\":\"golang.org/x/tools/gopls\",\"Version\":\"(devel)\",\"Sum\":\"\",\"Replace\":null},\"Deps\":[{\"Path\":\"github.com/BurntSushi/toml\",\"Version\":\"v1.2.0\",\"Sum\":\"\",\"Replace\":null},{\"Path\":\"github.com/google/go-cmp\",\"Version\":\"v0.5.8\",\"Sum\":\"\",\"Replace\":null},{\"Path\":\"github.com/sergi/go-diff\",\"Version\":\"v1.1.0\",\"Sum\":\"\",\"Replace\":null},{\"Path\":\"golang.org/x/exp\",\"Version\":\"v0.0.0-20220722155223-a9213eeb770e\",\"Sum\":\"\",\"Replace\":null},{\"Path\":\"golang.org/x/exp/typeparams\",\"Version\":\"v0.0.0-20220722155223-a9213eeb770e\",\"Sum\":\"\",\"Replace\":null},{\"Path\":\"golang.org/x/mod\",\"Version\":\"v0.6.0\",\"Sum\":\"\",\"Replace\":null},{\"Path\":\"golang.org/x/sync\",\"Version\":\"v0.0.0-20220722155255-886fb9371eb4\",\"Sum\":\"\",\"Replace\":null},{\"Path\":\"golang.org/x/sys\",\"Version\":\"v0.1.0\",\"Sum\":\"\",\"Replace\":null},{\"Path\":\"golang.org/x/text\",\"Version\":\"v0.4.0\",\"Sum\":\"\",\"Replace\":null},{\"Path\":\"golang.org/x/tools\",\"Version\":\"v0.2.1-0.20221101170700-b5bc717366b2\",\"Sum\":\"\",\"Replace\":null},{\"Path\":\"golang.org/x/vuln\",\"Version\":\"v0.0.0-20221010193109-563322be2ea9\",\"Sum\":\"\",\"Replace\":null},{\"Path\":\"honnef.co/go/tools\",\"Version\":\"v0.3.3\",\"Sum\":\"\",\"Replace\":null},{\"Path\":\"mvdan.cc/gofumpt\",\"Version\":\"v0.3.1\",\"Sum\":\"\",\"Replace\":null},{\"Path\":\"mvdan.cc/xurls/v2\",\"Version\":\"v2.4.0\",\"Sum\":\"\",\"Replace\":null}],\"Settings\":[{\"Key\":\"-compiler\",\"Value\":\"gc\"},{\"Key\":\"-trimpath\",\"Value\":\"true\"},{\"Key\":\"CGO_ENABLED\",\"Value\":\"1\"},{\"Key\":\"GOARCH\",\"Value\":\"amd64\"},{\"Key\":\"GOOS\",\"Value\":\"linux\"},{\"Key\":\"GOAMD64\",\"Value\":\"v1\"}],\"Version\":\"v0.10.1\"}"))
:id 1)
[client-notification] Sat Dec 10 13:25:06 2022:
(:jsonrpc "2.0" :method "initialized" :params #s(hash-table size 1 test eql rehash-size 1.5 rehash-threshold 0.8125 data
()))
[server-notification] Sat Dec 10 13:25:06 2022:
(:jsonrpc "2.0" :method "window/showMessage" :params
(:type 4 :message "Loading packages..."))
[server-request] (id:1) Sat Dec 10 13:25:06 2022:
(:jsonrpc "2.0" :method "workspace/configuration" :params
(:items
[(:scopeUri "file:///home/michael/go/src/github.com/google/nftables" :section "gopls")])
:id 1)
[client-reply] (id:1) Sat Dec 10 13:25:06 2022:
(:jsonrpc "2.0" :id 1 :result
[nil])
[client-notification] Sat Dec 10 13:25:06 2022:
(:jsonrpc "2.0" :method "textDocument/didOpen" :params
(:textDocument
(:uri "file:///home/michael/go/src/github.com/google/nftables/nftables_test.go" :version 0 :languageId "go" :text "// Copyright 2018 Google LLC. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage nftables_test\n\nimport (\n \"bytes\"\n \"errors\"\n \"flag\"\n \"fmt\"\n \"net\"\n \"os\"\n \"reflect\"\n \"runtime\"\n \"strings\"\n \"testing\"\n \"time\"\n\n \"github.com/google/nftables\"\n \"github.com/google/nftables/binaryutil\"\n \"github.com/google/nftables/expr\"\n \"github.com/google/nftables/internal/nftest\"\n \"github.com/google/nftables/xt\"\n \"github.com/mdlayher/netlink\"\n \"github.com/vishvananda/netns\"\n \"golang.org/x/sys/unix\"\n)\n\nvar (\n enableSysTests = flag.Bool(\"run_system_tests\", false, \"Run tests that operate against the live kernel\")\n)\n\n// nfdump returns a hexdump of 4 bytes per line (like nft --debug=all), allowing\n// users to make sense of large byte literals more easily.\nfunc nfdump(b []byte) string {\n var buf bytes.Buffer\n i := 0\n for ; i < len(b); i += 4 {\n // TODO: show printable characters as ASCII\n fmt.Fprintf(&buf, \"%02x %02x %02x %02x\\n\",\n b[i],\n b[i+1],\n b[i+2],\n b[i+3])\n }\n for ; i < len(b); i++ {\n fmt.Fprintf(&buf, \"%02x \", b[i])\n }\n return buf.String()\n}\n\n// linediff returns a side-by-side diff of two nfdump() return values, flagging\n// lines which are not equal with an exclamation point prefix.\nfunc linediff(a, b string) string {\n var buf bytes.Buffer\n fmt.Fprintf(&buf, \"got -- want\\n\")\n linesA := strings.Split(a, \"\\n\")\n linesB := strings.Split(b, \"\\n\")\n for idx, lineA := range linesA {\n if idx >= len(linesB) {\n break\n }\n lineB := linesB[idx]\n prefix := \"! \"\n if lineA == lineB {\n prefix = \" \"\n }\n fmt.Fprintf(&buf, \"%s%s -- %s\\n\", prefix, lineA, lineB)\n }\n return buf.String()\n}\n\nfunc ifname(n string) []byte {\n b := make([]byte, 16)\n copy(b, []byte(n+\"\\x00\"))\n return b\n}\n\n// openSystemNFTConn returns a netlink connection that tests against\n// the running kernel in a separate network namespace.\n// cleanupSystemNFTConn() must be called from a defer to cleanup\n// created network namespace.\nfunc openSystemNFTConn(t *testing.T) (*nftables.Conn, netns.NsHandle) {\n t.Helper()\n if !*enableSysTests {\n t.SkipNow()\n }\n // We lock the goroutine into the current thread, as namespace operations\n // such as those invoked by `netns.New()` are thread-local. This is undone\n // in cleanupSystemNFTConn().\n runtime.LockOSThread()\n\n ns, err := netns.New()\n if err != nil {\n t.Fatalf(\"netns.New() failed: %v\", err)\n }\n c, err := nftables.New(nftables.WithNetNSFd(int(ns)))\n if err != nil {\n t.Fatalf(\"nftables.New() failed: %v\", err)\n }\n return c, ns\n}\n\nfunc cleanupSystemNFTConn(t *testing.T, newNS netns.NsHandle) {\n defer runtime.UnlockOSThread()\n\n if err := newNS.Close(); err != nil {\n t.Fatalf(\"newNS.Close() failed: %v\", err)\n }\n}\n\nfunc TestRuleOperations(t *testing.T) {\n\n // Create a new network namespace to test these operations,\n // and tear down the namespace at test completion.\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n // Clear all rules at the beginning + end of the test.\n c.FlushRuleset()\n defer c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n prerouting := c.AddChain(&nftables.Chain{\n Name: \"base-chain\",\n Table: filter,\n Type: nftables.ChainTypeFilter,\n Hooknum: nftables.ChainHookPrerouting,\n Priority: nftables.ChainPriorityFilter,\n })\n\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: prerouting,\n Exprs: []expr.Any{\n &expr.Verdict{\n // [ immediate reg 0 drop ]\n Kind: expr.VerdictDrop,\n },\n },\n })\n\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: prerouting,\n Exprs: []expr.Any{\n &expr.Verdict{\n // [ immediate reg 0 drop ]\n Kind: expr.VerdictDrop,\n },\n },\n })\n\n c.InsertRule(&nftables.Rule{\n Table: filter,\n Chain: prerouting,\n Exprs: []expr.Any{\n &expr.Verdict{\n // [ immediate reg 0 accept ]\n Kind: expr.VerdictAccept,\n },\n },\n })\n\n c.InsertRule(&nftables.Rule{\n Table: filter,\n Chain: prerouting,\n Exprs: []expr.Any{\n &expr.Verdict{\n // [ immediate reg 0 queue ]\n Kind: expr.VerdictQueue,\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n\n rules, _ := c.GetRules(filter, prerouting)\n\n want := []expr.VerdictKind{\n expr.VerdictQueue,\n expr.VerdictAccept,\n expr.VerdictDrop,\n expr.VerdictDrop,\n }\n\n for i, r := range rules {\n rr, _ := r.Exprs[0].(*expr.Verdict)\n\n if rr.Kind != want[i] {\n t.Fatalf(\"bad verdict kind at %d\", i)\n }\n }\n\n c.ReplaceRule(&nftables.Rule{\n Table: filter,\n Chain: prerouting,\n Handle: rules[2].Handle,\n Exprs: []expr.Any{\n &expr.Verdict{\n // [ immediate reg 0 accept ]\n Kind: expr.VerdictAccept,\n },\n },\n })\n\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: prerouting,\n Position: rules[2].Handle,\n Exprs: []expr.Any{\n &expr.Verdict{\n // [ immediate reg 0 drop ]\n Kind: expr.VerdictDrop,\n },\n },\n })\n\n c.InsertRule(&nftables.Rule{\n Table: filter,\n Chain: prerouting,\n Position: rules[2].Handle,\n Exprs: []expr.Any{\n &expr.Verdict{\n // [ immediate reg 0 queue ]\n Kind: expr.VerdictQueue,\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n\n rules, _ = c.GetRules(filter, prerouting)\n\n want = []expr.VerdictKind{\n expr.VerdictQueue,\n expr.VerdictAccept,\n expr.VerdictQueue,\n expr.VerdictAccept,\n expr.VerdictDrop,\n expr.VerdictDrop,\n }\n\n for i, r := range rules {\n rr, _ := r.Exprs[0].(*expr.Verdict)\n\n if rr.Kind != want[i] {\n t.Fatalf(\"bad verdict kind at %d\", i)\n }\n }\n}\n\nfunc TestConfigureNAT(t *testing.T) {\n // The want byte sequences come from stracing nft(8), e.g.:\n // strace -f -v -x -s 2048 -eraw=sendto nft add table ip nat\n //\n // The nft(8) command sequence was taken from:\n // https://wiki.nftables.org/wiki-nftables/index.php/Performing_Network_Address_Translation_(NAT)\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft flush ruleset\n []byte(\"\\x00\\x00\\x00\\x00\"),\n // nft add table ip nat\n []byte(\"\\x02\\x00\\x00\\x00\\x08\\x00\\x01\\x00\\x6e\\x61\\x74\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain nat prerouting '{' type nat hook prerouting priority 0 \\; '}'\n []byte(\"\\x02\\x00\\x00\\x00\\x08\\x00\\x01\\x00\\x6e\\x61\\x74\\x00\\x0f\\x00\\x03\\x00\\x70\\x72\\x65\\x72\\x6f\\x75\\x74\\x69\\x6e\\x67\\x00\\x00\\x14\\x00\\x04\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x08\\x00\\x07\\x00\\x6e\\x61\\x74\\x00\"),\n // nft add chain nat postrouting '{' type nat hook postrouting priority 100 \\; '}'\n []byte(\"\\x02\\x00\\x00\\x00\\x08\\x00\\x01\\x00\\x6e\\x61\\x74\\x00\\x10\\x00\\x03\\x00\\x70\\x6f\\x73\\x74\\x72\\x6f\\x75\\x74\\x69\\x6e\\x67\\x00\\x14\\x00\\x04\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x04\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x64\\x08\\x00\\x07\\x00\\x6e\\x61\\x74\\x00\"),\n // nft add rule nat postrouting oifname uplink0 masquerade\n []byte(\"\\x02\\x00\\x00\\x00\\x08\\x00\\x01\\x00\\x6e\\x61\\x74\\x00\\x10\\x00\\x02\\x00\\x70\\x6f\\x73\\x74\\x72\\x6f\\x75\\x74\\x69\\x6e\\x67\\x00\\x74\\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\\x07\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x38\\x00\\x01\\x80\\x08\\x00\\x01\\x00\\x63\\x6d\\x70\\x00\\x2c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x18\\x00\\x03\\x80\\x14\\x00\\x01\\x00\\x75\\x70\\x6c\\x69\\x6e\\x6b\\x30\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x14\\x00\\x01\\x80\\x09\\x00\\x01\\x00\\x6d\\x61\\x73\\x71\\x00\\x00\\x00\\x00\\x04\\x00\\x02\\x80\"),\n // nft add rule nat prerouting iif uplink0 tcp dport 4070 dnat 192.168.23.2:4080\n []byte(\"\\x02\\x00\\x00\\x00\\x08\\x00\\x01\\x00\\x6e\\x61\\x74\\x00\\x0f\\x00\\x02\\x00\\x70\\x72\\x65\\x72\\x6f\\x75\\x74\\x69\\x6e\\x67\\x00\\x00\\x98\\x01\\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\\x06\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x38\\x00\\x01\\x80\\x08\\x00\\x01\\x00\\x63\\x6d\\x70\\x00\\x2c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x18\\x00\\x03\\x80\\x14\\x00\\x01\\x00\\x75\\x70\\x6c\\x69\\x6e\\x6b\\x30\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\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\\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\\x06\\x00\\x01\\x00\\x0f\\xe6\\x00\\x00\\x2c\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x69\\x6d\\x6d\\x65\\x64\\x69\\x61\\x74\\x65\\x00\\x00\\x00\\x18\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x0c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\xc0\\xa8\\x17\\x02\\x2c\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x69\\x6d\\x6d\\x65\\x64\\x69\\x61\\x74\\x65\\x00\\x00\\x00\\x18\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x02\\x0c\\x00\\x02\\x80\\x06\\x00\\x01\\x00\\x0f\\xf0\\x00\\x00\\x30\\x00\\x01\\x80\\x08\\x00\\x01\\x00\\x6e\\x61\\x74\\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\\x01\\x08\\x00\\x05\\x00\\x00\\x00\\x00\\x02\"),\n // nft add rule nat prerouting iifname uplink0 udp dport 4070-4090 dnat 192.168.23.2:4070-4090\n []byte(\"\\x02\\x00\\x00\\x00\\x08\\x00\\x01\\x00\\x6e\\x61\\x74\\x00\\x0f\\x00\\x02\\x00\\x70\\x72\\x65\\x72\\x6f\\x75\\x74\\x69\\x6e\\x67\\x00\\x00\\xf8\\x01\\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\\x06\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x38\\x00\\x01\\x80\\x08\\x00\\x01\\x00\\x63\\x6d\\x70\\x00\\x2c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x18\\x00\\x03\\x80\\x14\\x00\\x01\\x00\\x75\\x70\\x6c\\x69\\x6e\\x6b\\x30\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\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\\x11\\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\\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\\x05\\x0c\\x00\\x03\\x80\\x06\\x00\\x01\\x00\\x0f\\xe6\\x00\\x00\\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\\x03\\x0c\\x00\\x03\\x80\\x06\\x00\\x01\\x00\\x0f\\xfa\\x00\\x00\\x2c\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x69\\x6d\\x6d\\x65\\x64\\x69\\x61\\x74\\x65\\x00\\x00\\x00\\x18\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x0c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\xc0\\xa8\\x17\\x02\\x2c\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x69\\x6d\\x6d\\x65\\x64\\x69\\x61\\x74\\x65\\x00\\x00\\x00\\x18\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x02\\x0c\\x00\\x02\\x80\\x06\\x00\\x01\\x00\\x0f\\xe6\\x00\\x00\\x2c\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x69\\x6d\\x6d\\x65\\x64\\x69\\x61\\x74\\x65\\x00\\x00\\x00\\x18\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x03\\x0c\\x00\\x02\\x80\\x06\\x00\\x01\\x00\\x0f\\xfa\\x00\\x00\\x38\\x00\\x01\\x80\\x08\\x00\\x01\\x00\\x6e\\x61\\x74\\x00\\x2c\\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\\x01\\x08\\x00\\x05\\x00\\x00\\x00\\x00\\x02\\x08\\x00\\x06\\x00\\x00\\x00\\x00\\x03\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.FlushRuleset()\n\n nat := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"nat\",\n })\n\n prerouting := c.AddChain(&nftables.Chain{\n Name: \"prerouting\",\n Hooknum: nftables.ChainHookPrerouting,\n Priority: nftables.ChainPriorityFilter,\n Table: nat,\n Type: nftables.ChainTypeNAT,\n })\n\n postrouting := c.AddChain(&nftables.Chain{\n Name: \"postrouting\",\n Hooknum: nftables.ChainHookPostrouting,\n Priority: nftables.ChainPriorityNATSource,\n Table: nat,\n Type: nftables.ChainTypeNAT,\n })\n\n c.AddRule(&nftables.Rule{\n Table: nat,\n Chain: postrouting,\n Exprs: []expr.Any{\n // meta load oifname => reg 1\n &expr.Meta{Key: expr.MetaKeyOIFNAME, Register: 1},\n // cmp eq reg 1 0x696c7075 0x00306b6e 0x00000000 0x00000000\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: ifname(\"uplink0\"),\n },\n // masq\n &expr.Masq{},\n },\n })\n\n c.AddRule(&nftables.Rule{\n Table: nat,\n Chain: prerouting,\n Exprs: []expr.Any{\n // [ meta load iifname => reg 1 ]\n &expr.Meta{Key: expr.MetaKeyIIFNAME, Register: 1},\n // [ cmp eq reg 1 0x696c7075 0x00306b6e 0x00000000 0x00000000 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: ifname(\"uplink0\"),\n },\n\n // [ meta load l4proto => reg 1 ]\n &expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1},\n // [ cmp eq reg 1 0x00000006 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{unix.IPPROTO_TCP},\n },\n\n // [ payload load 2b @ transport header + 2 => reg 1 ]\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseTransportHeader,\n Offset: 2, // TODO\n Len: 2, // TODO\n },\n // [ cmp eq reg 1 0x0000e60f ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: binaryutil.BigEndian.PutUint16(4070),\n },\n\n // [ immediate reg 1 0x0217a8c0 ]\n &expr.Immediate{\n Register: 1,\n Data: net.ParseIP(\"192.168.23.2\").To4(),\n },\n // [ immediate reg 2 0x0000f00f ]\n &expr.Immediate{\n Register: 2,\n Data: binaryutil.BigEndian.PutUint16(4080),\n },\n // [ nat dnat ip addr_min reg 1 addr_max reg 0 proto_min reg 2 proto_max reg 0 ]\n &expr.NAT{\n Type: expr.NATTypeDestNAT,\n Family: unix.NFPROTO_IPV4,\n RegAddrMin: 1,\n RegProtoMin: 2,\n },\n },\n })\n\n c.AddRule(&nftables.Rule{\n Table: nat,\n Chain: prerouting,\n Exprs: []expr.Any{\n // [ meta load iifname => reg 1 ]\n &expr.Meta{Key: expr.MetaKeyIIFNAME, Register: 1},\n // [ cmp eq reg 1 0x696c7075 0x00306b6e 0x00000000 0x00000000 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: ifname(\"uplink0\"),\n },\n\n // [ meta load l4proto => reg 1 ]\n &expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1},\n // [ cmp eq reg 1 0x00000006 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{unix.IPPROTO_UDP},\n },\n\n // [ payload load 2b @ transport header + 2 => reg 1 ]\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseTransportHeader,\n Offset: 2, // TODO\n Len: 2, // TODO\n },\n // [ cmp gte reg 1 0x0000e60f ]\n &expr.Cmp{\n Op: expr.CmpOpGte,\n Register: 1,\n Data: binaryutil.BigEndian.PutUint16(4070),\n },\n // [ cmp lte reg 1 0x0000fa0f ]\n &expr.Cmp{\n Op: expr.CmpOpLte,\n Register: 1,\n Data: binaryutil.BigEndian.PutUint16(4090),\n },\n\n // [ immediate reg 1 0x0217a8c0 ]\n &expr.Immediate{\n Register: 1,\n Data: net.ParseIP(\"192.168.23.2\").To4(),\n },\n // [ immediate reg 2 0x0000f00f ]\n &expr.Immediate{\n Register: 2,\n Data: binaryutil.BigEndian.PutUint16(4070),\n },\n // [ immediate reg 3 0x0000fa0f ]\n &expr.Immediate{\n Register: 3,\n Data: binaryutil.BigEndian.PutUint16(4090),\n },\n // [ nat dnat ip addr_min reg 1 addr_max reg 0 proto_min reg 2 proto_max reg 3 ]\n &expr.NAT{\n Type: expr.NATTypeDestNAT,\n Family: unix.NFPROTO_IPV4,\n RegAddrMin: 1,\n RegProtoMin: 2,\n RegProtoMax: 3,\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestConfigureNATSourceAddress(t *testing.T) {\n // The want byte sequences come from stracing nft(8), e.g.:\n // strace -f -v -x -s 2048 -eraw=sendto nft add table ip nat\n //\n // The nft(8) command sequence was taken from:\n // https://wiki.nftables.org/wiki-nftables/index.php/Performing_Network_Address_Translation_(NAT)\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft flush ruleset\n []byte(\"\\x00\\x00\\x00\\x00\"),\n // nft add table ip nat\n []byte(\"\\x02\\x00\\x00\\x00\\x08\\x00\\x01\\x00\\x6e\\x61\\x74\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain nat postrouting '{' type nat hook postrouting priority 100 \\; '}'\n []byte(\"\\x02\\x00\\x00\\x00\\x08\\x00\\x01\\x00\\x6e\\x61\\x74\\x00\\x10\\x00\\x03\\x00\\x70\\x6f\\x73\\x74\\x72\\x6f\\x75\\x74\\x69\\x6e\\x67\\x00\\x14\\x00\\x04\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x04\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x64\\x08\\x00\\x07\\x00\\x6e\\x61\\x74\\x00\"),\n // nft add rule nat postrouting ip saddr 192.168.69.2 masquerade\n []byte(\"\\x02\\x00\\x00\\x00\\x08\\x00\\x01\\x00\\x6e\\x61\\x74\\x00\\x10\\x00\\x02\\x00\\x70\\x6f\\x73\\x74\\x72\\x6f\\x75\\x74\\x69\\x6e\\x67\\x00\\x78\\x00\\x04\\x80\\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\\x01\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x0c\\x08\\x00\\x04\\x00\\x00\\x00\\x00\\x04\\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\\x08\\x00\\x01\\x00\\xc0\\xa8\\x45\\x02\\x14\\x00\\x01\\x80\\x09\\x00\\x01\\x00\\x6d\\x61\\x73\\x71\\x00\\x00\\x00\\x00\\x04\\x00\\x02\\x80\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.FlushRuleset()\n\n nat := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"nat\",\n })\n\n postrouting := c.AddChain(&nftables.Chain{\n Name: \"postrouting\",\n Hooknum: nftables.ChainHookPostrouting,\n Priority: nftables.ChainPriorityNATSource,\n Table: nat,\n Type: nftables.ChainTypeNAT,\n })\n\n c.AddRule(&nftables.Rule{\n Table: nat,\n Chain: postrouting,\n Exprs: []expr.Any{\n // payload load 4b @ network header + 12 => reg 1\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseNetworkHeader,\n Offset: 12,\n Len: 4,\n },\n // cmp eq reg 1 0x0245a8c0\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: net.ParseIP(\"192.168.69.2\").To4(),\n },\n\n // masq\n &expr.Masq{},\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestExprLogOptions(t *testing.T) {\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n\n c.FlushRuleset()\n defer c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n input := c.AddChain(&nftables.Chain{\n Name: \"input\",\n Table: filter,\n Type: nftables.ChainTypeFilter,\n Hooknum: nftables.ChainHookInput,\n Priority: nftables.ChainPriorityFilter,\n })\n forward := c.AddChain(&nftables.Chain{\n Name: \"forward\",\n Table: filter,\n Type: nftables.ChainTypeFilter,\n Hooknum: nftables.ChainHookInput,\n Priority: nftables.ChainPriorityFilter,\n })\n\n keyGQ := uint32((1 << unix.NFTA_LOG_GROUP) | (1 << unix.NFTA_LOG_QTHRESHOLD) | (1 << unix.NFTA_LOG_SNAPLEN))\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: input,\n Exprs: []expr.Any{\n &expr.Log{\n Key: keyGQ,\n QThreshold: uint16(20),\n Group: uint16(1),\n Snaplen: uint32(132),\n },\n },\n })\n\n keyPL := uint32((1 << unix.NFTA_LOG_PREFIX) | (1 << unix.NFTA_LOG_LEVEL) | (1 << unix.NFTA_LOG_FLAGS))\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: forward,\n Exprs: []expr.Any{\n &expr.Log{\n Key: keyPL,\n Data: []byte(\"LOG FORWARD\"),\n Level: expr.LogLevelDebug,\n Flags: expr.LogFlagsTCPOpt | expr.LogFlagsIPOpt,\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Errorf(\"c.Flush() failed: %v\", err)\n }\n\n rules, err := c.GetRules(\n &nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n },\n &nftables.Chain{\n Name: \"input\",\n },\n )\n if err != nil {\n t.Fatal(err)\n }\n\n if got, want := len(rules), 1; got != want {\n t.Fatalf(\"unexpected number of rules: got %d, want %d\", got, want)\n }\n\n rule := rules[0]\n if got, want := len(rule.Exprs), 1; got != want {\n t.Fatalf(\"unexpected number of exprs: got %d, want %d\", got, want)\n }\n\n le, ok := rule.Exprs[0].(*expr.Log)\n if !ok {\n t.Fatalf(\"unexpected expression type: got %T, want *expr.Log\", rule.Exprs[0])\n }\n\n if got, want := le.Key, keyGQ; got != want {\n t.Fatalf(\"unexpected log key: got %d, want %d\", got, want)\n }\n\n if got, want := le.Group, uint16(1); got != want {\n t.Fatalf(\"unexpected group: got %d, want %d\", got, want)\n }\n\n if got, want := le.QThreshold, uint16(20); got != want {\n t.Fatalf(\"unexpected queue-threshold: got %d, want %d\", got, want)\n }\n\n if got, want := le.Snaplen, uint32(132); got != want {\n t.Fatalf(\"unexpected snaplen: got %d, want %d\", got, want)\n }\n\n rules, err = c.GetRules(\n &nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n },\n &nftables.Chain{\n Name: \"forward\",\n },\n )\n if err != nil {\n t.Fatal(err)\n }\n\n if got, want := len(rules), 1; got != want {\n t.Fatalf(\"unexpected number of rules: got %d, want %d\", got, want)\n }\n\n rule = rules[0]\n if got, want := len(rule.Exprs), 1; got != want {\n t.Fatalf(\"unexpected number of exprs: got %d, want %d\", got, want)\n }\n\n le, ok = rule.Exprs[0].(*expr.Log)\n if !ok {\n t.Fatalf(\"unexpected expression type: got %T, want *expr.Log\", rule.Exprs[0])\n }\n\n if got, want := le.Key, keyPL; got != want {\n t.Fatalf(\"unexpected log key: got %d, want %d\", got, want)\n }\n\n if got, want := string(le.Data), \"LOG FORWARD\"; got != want {\n t.Fatalf(\"unexpected prefix data: got %s, want %s\", got, want)\n }\n\n if got, want := le.Level, expr.LogLevelDebug; got != want {\n t.Fatalf(\"unexpected log level: got %d, want %d\", got, want)\n }\n\n if got, want := le.Flags, expr.LogFlagsTCPOpt|expr.LogFlagsIPOpt; got != want {\n t.Fatalf(\"unexpected log flags: got %d, want %d\", got, want)\n }\n}\n\nfunc TestExprLogPrefix(t *testing.T) {\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n\n c.FlushRuleset()\n defer c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n input := c.AddChain(&nftables.Chain{\n Name: \"input\",\n Table: filter,\n Type: nftables.ChainTypeFilter,\n Hooknum: nftables.ChainHookInput,\n Priority: nftables.ChainPriorityFilter,\n })\n\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: input,\n Exprs: []expr.Any{\n &expr.Log{\n Key: 1 << unix.NFTA_LOG_PREFIX,\n Data: []byte(\"LOG INPUT\"),\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Errorf(\"c.Flush() failed: %v\", err)\n }\n\n rules, err := c.GetRules(\n &nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n },\n &nftables.Chain{\n Name: \"input\",\n },\n )\n if err != nil {\n t.Fatal(err)\n }\n\n if got, want := len(rules), 1; got != want {\n t.Fatalf(\"unexpected number of rules: got %d, want %d\", got, want)\n }\n if got, want := len(rules[0].Exprs), 1; got != want {\n t.Fatalf(\"unexpected number of exprs: got %d, want %d\", got, want)\n }\n\n logExpr, ok := rules[0].Exprs[0].(*expr.Log)\n if !ok {\n t.Fatalf(\"Exprs[0] is type %T, want *expr.Log\", rules[0].Exprs[0])\n }\n\n // nftables defaults to warn log level when no level is specified and group is not defined\n // see https://wiki.nftables.org/wiki-nftables/index.php/Logging_traffic\n if got, want := logExpr.Key, uint32((1<<unix.NFTA_LOG_PREFIX)|(1<<unix.NFTA_LOG_LEVEL)); got != want {\n t.Fatalf(\"unexpected *expr.Log key: got %d, want %d\", got, want)\n }\n if got, want := string(logExpr.Data), \"LOG INPUT\"; got != want {\n t.Fatalf(\"unexpected *expr.Log data: got %s, want %s\", got, want)\n }\n if got, want := logExpr.Level, expr.LogLevelWarning; got != want {\n t.Fatalf(\"unexpected *expr.Log level: got %d, want %d\", got, want)\n }\n}\n\nfunc TestAddCounter(t *testing.T) {\n // The want byte sequences come from stracing nft(8), e.g.:\n // strace -f -v -x -s 2048 -eraw=sendto nft add table ip nat\n //\n // The nft(8) command sequence was taken from:\n // https://wiki.nftables.org/wiki-nftables/index.php/Performing_Network_Address_Translation_(NAT)\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft add counter ip filter fwded\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0a\\x00\\x02\\x00\\x66\\x77\\x64\\x65\\x64\\x00\\x00\\x00\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x01\\x1c\\x00\\x04\\x80\\x0c\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x0c\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"),\n // nft add rule ip filter forward counter name fwded\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0c\\x00\\x02\\x00\\x66\\x6f\\x72\\x77\\x61\\x72\\x64\\x00\\x2c\\x00\\x04\\x80\\x28\\x00\\x01\\x80\\x0b\\x00\\x01\\x00\\x6f\\x62\\x6a\\x72\\x65\\x66\\x00\\x00\\x18\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x09\\x00\\x02\\x00\\x66\\x77\\x64\\x65\\x64\\x00\\x00\\x00\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.AddObj(&nftables.CounterObj{\n Table: &nftables.Table{Name: \"filter\", Family: nftables.TableFamilyIPv4},\n Name: \"fwded\",\n Bytes: 0,\n Packets: 0,\n })\n\n c.AddRule(&nftables.Rule{\n Table: &nftables.Table{Name: \"filter\", Family: nftables.TableFamilyIPv4},\n Chain: &nftables.Chain{Name: \"forward\", Type: nftables.ChainTypeFilter},\n Exprs: []expr.Any{\n &expr.Objref{\n Type: 1,\n Name: \"fwded\",\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestDeleteCounter(t *testing.T) {\n // The want byte sequences come from stracing nft(8), e.g.:\n // strace -f -v -x -s 2048 -eraw=sendto nft add table ip nat\n //\n // The nft(8) command sequence was taken from:\n // https://wiki.nftables.org/wiki-nftables/index.php/Performing_Network_Address_Translation_(NAT)\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft add counter ip filter fwded\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0a\\x00\\x02\\x00\\x66\\x77\\x64\\x65\\x64\\x00\\x00\\x00\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x01\\x1c\\x00\\x04\\x80\\x0c\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x0c\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"),\n // nft delete counter ip filter fwded\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0a\\x00\\x02\\x00\\x66\\x77\\x64\\x65\\x64\\x00\\x00\\x00\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x01\\x04\\x00\\x04\\x80\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.AddObj(&nftables.CounterObj{\n Table: &nftables.Table{Name: \"filter\", Family: nftables.TableFamilyIPv4},\n Name: \"fwded\",\n Bytes: 0,\n Packets: 0,\n })\n\n c.DeleteObject(&nftables.CounterObj{\n Table: &nftables.Table{Name: \"filter\", Family: nftables.TableFamilyIPv4},\n Name: \"fwded\",\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestDelRule(t *testing.T) {\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft delete rule ipv4table ipv4chain-1 handle 9\n []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\\x31\\x00\\x0c\\x00\\x03\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x09\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.DelRule(&nftables.Rule{\n Table: &nftables.Table{Name: \"ipv4table\", Family: nftables.TableFamilyIPv4},\n Chain: &nftables.Chain{Name: \"ipv4chain-1\", Type: nftables.ChainTypeFilter},\n Handle: uint64(9),\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestLog(t *testing.T) {\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft add rule ipv4table ipv4chain-1 log prefix nftables\n []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\\x31\\x00\\x24\\x00\\x04\\x80\\x20\\x00\\x01\\x80\\x08\\x00\\x01\\x00\\x6c\\x6f\\x67\\x00\\x14\\x00\\x02\\x80\\x0d\\x00\\x02\\x00\\x6e\\x66\\x74\\x61\\x62\\x6c\\x65\\x73\\x00\\x00\\x00\\x00\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.AddRule(&nftables.Rule{\n Table: &nftables.Table{Name: \"ipv4table\", Family: nftables.TableFamilyIPv4},\n Chain: &nftables.Chain{Name: \"ipv4chain-1\", Type: nftables.ChainTypeFilter},\n Exprs: []expr.Any{\n &expr.Log{\n Key: 1 << unix.NFTA_LOG_PREFIX,\n Data: []byte(\"nftables\"),\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestTProxy(t *testing.T) {\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft add rule filter divert ip protocol tcp tproxy to :50080\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0b\\x00\\x02\\x00\\x64\\x69\\x76\\x65\\x72\\x74\\x00\\x00\\xb4\\x00\\x04\\x80\\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\\x01\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x09\\x08\\x00\\x04\\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\\x2c\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x69\\x6d\\x6d\\x65\\x64\\x69\\x61\\x74\\x65\\x00\\x00\\x00\\x18\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x0c\\x00\\x02\\x80\\x06\\x00\\x01\\x00\\xc3\\xa0\\x00\\x00\\x24\\x00\\x01\\x80\\x0b\\x00\\x01\\x00\\x74\\x70\\x72\\x6f\\x78\\x79\\x00\\x00\\x14\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x02\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x01\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.AddRule(&nftables.Rule{\n Table: &nftables.Table{Name: \"filter\", Family: nftables.TableFamilyIPv4},\n Chain: &nftables.Chain{\n Name: \"divert\",\n Type: nftables.ChainTypeFilter,\n Hooknum: nftables.ChainHookPrerouting,\n Priority: nftables.ChainPriorityRef(-150),\n },\n Exprs: []expr.Any{\n // [ payload load 1b @ network header + 9 => reg 1 ]\n &expr.Payload{DestRegister: 1, Base: expr.PayloadBaseNetworkHeader, Offset: 9, Len: 1},\n // [ cmp eq reg 1 0x00000006 ]\n &expr.Cmp{Op: expr.CmpOpEq, Register: 1, Data: []byte{unix.IPPROTO_TCP}},\n // [ immediate reg 1 0x0000a0c3 ]\n &expr.Immediate{Register: 1, Data: binaryutil.BigEndian.PutUint16(50080)},\n // [ tproxy ip port reg 1 ]\n &expr.TProxy{\n Family: byte(nftables.TableFamilyIPv4),\n TableFamily: byte(nftables.TableFamilyIPv4),\n RegPort: 1,\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestCt(t *testing.T) {\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // sudo nft add rule ipv4table ipv4chain-5 ct mark 123 counter\n []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\\x35\\x00\\x24\\x00\\x04\\x80\\x20\\x00\\x01\\x80\\x07\\x00\\x01\\x00\\x63\\x74\\x00\\x00\\x14\\x00\\x02\\x80\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x03\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.AddRule(&nftables.Rule{\n Table: &nftables.Table{Name: \"ipv4table\", Family: nftables.TableFamilyIPv4},\n Chain: &nftables.Chain{\n Name: \"ipv4chain-5\",\n },\n Exprs: []expr.Any{\n // [ ct load mark => reg 1 ]\n &expr.Ct{\n Key: unix.NFT_CT_MARK,\n Register: 1,\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestCtSet(t *testing.T) {\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // sudo nft add rule filter forward ct mark set 1\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0c\\x00\\x02\\x00\\x66\\x6f\\x72\\x77\\x61\\x72\\x64\\x00\\x50\\x00\\x04\\x80\\x2c\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x69\\x6d\\x6d\\x65\\x64\\x69\\x61\\x74\\x65\\x00\\x00\\x00\\x18\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x0c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x01\\x00\\x00\\x00\\x20\\x00\\x01\\x80\\x07\\x00\\x01\\x00\\x63\\x74\\x00\\x00\\x14\\x00\\x02\\x80\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x03\\x08\\x00\\x04\\x00\\x00\\x00\\x00\\x01\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.AddRule(&nftables.Rule{\n Table: &nftables.Table{Name: \"filter\", Family: nftables.TableFamilyIPv4},\n Chain: &nftables.Chain{\n Name: \"forward\",\n },\n Exprs: []expr.Any{\n // [ immediate reg 1 0x00000001 ]\n &expr.Immediate{\n Register: 1,\n Data: binaryutil.NativeEndian.PutUint32(1),\n },\n // [ ct set mark with reg 1 ]\n &expr.Ct{\n Key: expr.CtKeyMARK,\n Register: 1,\n SourceRegister: true,\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestCtStat(t *testing.T) {\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // ct state established,related accept\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0b\\x00\\x02\\x00\\x6f\\x75\\x74\\x70\\x75\\x74\\x00\\x00\\xc4\\x00\\x04\\x80\\x20\\x00\\x01\\x80\\x07\\x00\\x01\\x00\\x63\\x74\\x00\\x00\\x14\\x00\\x02\\x80\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x44\\x00\\x01\\x80\\x0c\\x00\\x01\\x00\\x62\\x69\\x74\\x77\\x69\\x73\\x65\\x00\\x34\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x04\\x0c\\x00\\x04\\x80\\x08\\x00\\x01\\x00\\x06\\x00\\x00\\x00\\x0c\\x00\\x05\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\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\\x01\\x0c\\x00\\x03\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x30\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x69\\x6d\\x6d\\x65\\x64\\x69\\x61\\x74\\x65\\x00\\x00\\x00\\x1c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x10\\x00\\x02\\x80\\x0c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.AddRule(&nftables.Rule{\n Table: &nftables.Table{Name: \"filter\", Family: nftables.TableFamilyIPv4},\n Chain: &nftables.Chain{\n Name: \"output\",\n },\n Exprs: []expr.Any{\n &expr.Ct{Register: 1, SourceRegister: false, Key: expr.CtKeySTATE},\n &expr.Bitwise{\n SourceRegister: 1,\n DestRegister: 1,\n Len: 4,\n Mask: binaryutil.NativeEndian.PutUint32(expr.CtStateBitESTABLISHED | expr.CtStateBitRELATED),\n Xor: binaryutil.NativeEndian.PutUint32(0),\n },\n &expr.Cmp{Op: expr.CmpOpNeq, Register: 1, Data: []byte{0, 0, 0, 0}},\n &expr.Verdict{Kind: expr.VerdictAccept},\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestAddRuleWithPosition(t *testing.T) {\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft add rule ip ipv4table ipv4chain-1 position 2 ip version 6\n []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\\x31\\x00\\xa8\\x00\\x04\\x80\\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\\x01\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x00\\x08\\x00\\x04\\x00\\x00\\x00\\x00\\x01\\x44\\x00\\x01\\x80\\x0c\\x00\\x01\\x00\\x62\\x69\\x74\\x77\\x69\\x73\\x65\\x00\\x34\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x01\\x0c\\x00\\x04\\x80\\x05\\x00\\x01\\x00\\xf0\\x00\\x00\\x00\\x0c\\x00\\x05\\x80\\x05\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\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\\x60\\x00\\x00\\x00\\x0c\\x00\\x06\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.AddRule(&nftables.Rule{\n Position: 2,\n Table: &nftables.Table{Name: \"ipv4table\", Family: nftables.TableFamilyIPv4},\n Chain: &nftables.Chain{\n Name: \"ipv4chain-1\",\n Type: nftables.ChainTypeFilter,\n Hooknum: nftables.ChainHookPrerouting,\n Priority: nftables.ChainPriorityRef(0),\n },\n\n Exprs: []expr.Any{\n // [ payload load 1b @ network header + 0 => reg 1 ]\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseNetworkHeader,\n Offset: 0, // Offset for a transport protocol header\n Len: 1, // 1 bytes for port\n },\n // [ bitwise reg 1 = (reg=1 & 0x000000f0 ) ^ 0x00000000 ]\n &expr.Bitwise{\n SourceRegister: 1,\n DestRegister: 1,\n Len: 1,\n Mask: []byte{0xf0},\n Xor: []byte{0x0},\n },\n // [ cmp eq reg 1 0x00000060 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{(0x6 << 4)},\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestLastingConnection(t *testing.T) {\n testdialerr := errors.New(\"test dial sentinel error\")\n dialCount := 0\n c, err := nftables.New(\n nftables.AsLasting(),\n nftables.WithTestDial(func(req []netlink.Message) ([]netlink.Message, error) {\n dialCount++\n return nil, testdialerr\n }))\n if err != nil {\n t.Errorf(\"creating lasting netlink connection failed %v\", err)\n return\n }\n defer func() {\n if err := c.CloseLasting(); err != nil {\n t.Errorf(\"closing lasting netlink connection failed %v\", err)\n }\n }()\n\n _, err = c.ListTables()\n if !errors.Is(err, testdialerr) {\n t.Errorf(\"non-testdialerr error returned from TestDial %v\", err)\n return\n }\n if dialCount != 1 {\n t.Errorf(\"internal test error with TestDial invocations %v\", dialCount)\n return\n }\n\n // While a lasting netlink connection is open, replacing TestDial must be\n // ineffective as there is no need to dial again and activating a new\n // TestDial function. The newly set TestDial function must be getting\n // ignored.\n c.TestDial = func(req []netlink.Message) ([]netlink.Message, error) {\n dialCount--\n return nil, errors.New(\"transient netlink connection error\")\n }\n _, err = c.ListTables()\n if !errors.Is(err, testdialerr) {\n t.Errorf(\"non-testdialerr error returned from TestDial %v\", err)\n return\n }\n if dialCount != 2 {\n t.Errorf(\"internal test error with TestDial invocations %v\", dialCount)\n return\n }\n\n for i := 0; i < 2; i++ {\n err = c.CloseLasting()\n if err != nil {\n t.Errorf(\"closing lasting netlink connection failed in attempt no. %d: %v\", i, err)\n return\n }\n }\n _, err = c.ListTables()\n if errors.Is(err, testdialerr) {\n t.Error(\"testdialerr error returned from TestDial when expecting different error\")\n return\n }\n if dialCount != 1 {\n t.Errorf(\"internal test error with TestDial invocations %v\", dialCount)\n return\n }\n\n // fall into defer'ed second CloseLasting which must not cause any errors.\n}\n\nfunc TestListChains(t *testing.T) {\n polDrop := nftables.ChainPolicyDrop\n polAcpt := nftables.ChainPolicyAccept\n reply := [][]byte{\n // chain input { type filter hook input priority filter; policy accept; }\n []byte(\"\\x70\\x00\\x00\\x00\\x03\\x0a\\x02\\x00\\x00\\x00\\x00\\x00\\xb8\\x76\\x02\\x00\\x01\\x00\\x00\\xc3\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0c\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x01\\x0a\\x00\\x03\\x00\\x69\\x6e\\x70\\x75\\x74\\x00\\x00\\x00\\x14\\x00\\x04\\x00\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x08\\x00\\x05\\x00\\x00\\x00\\x00\\x01\\x0b\\x00\\x07\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x0a\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x06\\x00\\x00\\x00\\x00\\x00\"),\n // chain forward { type filter hook forward priority filter; policy drop; }\n []byte(\"\\x70\\x00\\x00\\x00\\x03\\x0a\\x02\\x00\\x00\\x00\\x00\\x01\\xb8\\x76\\x02\\x00\\x01\\x00\\x00\\xc3\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0c\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x0c\\x00\\x03\\x00\\x66\\x6f\\x72\\x77\\x61\\x72\\x64\\x00\\x14\\x00\\x04\\x00\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x02\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x08\\x00\\x05\\x00\\x00\\x00\\x00\\x00\\x0b\\x00\\x07\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x0a\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x06\\x00\\x00\\x00\\x00\\x00\"),\n // chain output { type filter hook output priority filter; policy accept; }\n []byte(\"\\x70\\x00\\x00\\x00\\x03\\x0a\\x02\\x00\\x00\\x00\\x00\\x02\\xb8\\x76\\x02\\x00\\x01\\x00\\x00\\xc3\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0c\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x03\\x0b\\x00\\x03\\x00\\x6f\\x75\\x74\\x70\\x75\\x74\\x00\\x00\\x14\\x00\\x04\\x00\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x03\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x08\\x00\\x05\\x00\\x00\\x00\\x00\\x01\\x0b\\x00\\x07\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x0a\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x06\\x00\\x00\\x00\\x00\\x00\"),\n // chain undef { counter packets 56235 bytes 175436495 return }\n []byte(\"\\x40\\x00\\x00\\x00\\x03\\x0a\\x02\\x00\\x00\\x00\\x00\\x03\\xb8\\x76\\x02\\x00\\x01\\x00\\x00\\xc3\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0c\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x04\\x0a\\x00\\x03\\x00\\x75\\x6e\\x64\\x65\\x66\\x00\\x00\\x00\\x08\\x00\\x06\\x00\\x00\\x00\\x00\\x01\"),\n []byte(\"\\x14\\x00\\x00\\x00\\x03\\x00\\x02\\x00\\x00\\x00\\x00\\x04\\xb8\\x76\\x02\\x00\\x00\\x00\\x00\\x00\"),\n }\n\n want := []*nftables.Chain{\n {\n Name: \"input\",\n Hooknum: nftables.ChainHookInput,\n Priority: nftables.ChainPriorityFilter,\n Type: nftables.ChainTypeFilter,\n Policy: &polAcpt,\n },\n {\n Name: \"forward\",\n Hooknum: nftables.ChainHookForward,\n Priority: nftables.ChainPriorityFilter,\n Type: nftables.ChainTypeFilter,\n Policy: &polDrop,\n },\n {\n Name: \"output\",\n Hooknum: nftables.ChainHookOutput,\n Priority: nftables.ChainPriorityFilter,\n Type: nftables.ChainTypeFilter,\n Policy: &polAcpt,\n },\n {\n Name: \"undef\",\n Hooknum: nil,\n Priority: nil,\n Policy: nil,\n },\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n msgReply := make([]netlink.Message, len(reply))\n for i, r := range reply {\n nm := &netlink.Message{}\n nm.UnmarshalBinary(r)\n nm.Header.Sequence = req[0].Header.Sequence\n nm.Header.PID = req[0].Header.PID\n msgReply[i] = *nm\n }\n return msgReply, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n chains, err := c.ListChains()\n if err != nil {\n t.Errorf(\"error returned from TestDial %v\", err)\n return\n }\n\n if len(chains) != len(want) {\n t.Errorf(\"number of chains %d != number of want %d\", len(chains), len(want))\n return\n }\n\n validate := func(got interface{}, want interface{}, name string, index int) {\n if got != want {\n t.Errorf(\"chain %d: chain %s mismatch, got %v want %v\", index, name, got, want)\n }\n }\n\n for i, chain := range chains {\n validate(chain.Name, want[i].Name, \"name\", i)\n if want[i].Hooknum != nil && chain.Hooknum != nil {\n validate(*chain.Hooknum, *want[i].Hooknum, \"hooknum value\", i)\n } else {\n validate(chain.Hooknum, want[i].Hooknum, \"hooknum pointer\", i)\n }\n if want[i].Priority != nil && chain.Priority != nil {\n validate(*chain.Priority, *want[i].Priority, \"priority value\", i)\n } else {\n validate(chain.Priority, want[i].Priority, \"priority pointer\", i)\n }\n validate(chain.Type, want[i].Type, \"type\", i)\n\n if want[i].Policy != nil && chain.Policy != nil {\n validate(*chain.Policy, *want[i].Policy, \"policy value\", i)\n } else {\n validate(chain.Policy, want[i].Policy, \"policy pointer\", i)\n }\n }\n\n}\n\nfunc TestAddChain(t *testing.T) {\n tests := []struct {\n name string\n chain *nftables.Chain\n want [][]byte\n }{\n {\n name: \"Base chain\",\n chain: &nftables.Chain{\n Name: \"base-chain\",\n Hooknum: nftables.ChainHookPrerouting,\n Priority: nftables.ChainPriorityRef(0),\n Type: nftables.ChainTypeFilter,\n },\n want: [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain ip filter base-chain { type filter hook prerouting priority 0 \\; }\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x03\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\x14\\x00\\x04\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x0b\\x00\\x07\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n },\n },\n {\n name: \"Regular chain\",\n chain: &nftables.Chain{\n Name: \"regular-chain\",\n },\n want: [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain ip filter regular-chain\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x12\\x00\\x03\\x00\\x72\\x65\\x67\\x75\\x6c\\x61\\x72\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\x00\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n },\n },\n }\n\n for _, tt := range tests {\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(tt.want[idx]) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n got := b\n if !bytes.Equal(got, tt.want[idx]) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(tt.want[idx])))\n }\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n tt.chain.Table = filter\n c.AddChain(tt.chain)\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n }\n}\n\nfunc TestDelChain(t *testing.T) {\n tests := []struct {\n name string\n chain *nftables.Chain\n want [][]byte\n }{\n {\n name: \"Base chain\",\n chain: &nftables.Chain{\n Name: \"base-chain\",\n Hooknum: nftables.ChainHookPrerouting,\n Priority: nftables.ChainPriorityRef(0),\n Type: nftables.ChainTypeFilter,\n },\n want: [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft delete chain ip filter base-chain\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x03\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n },\n },\n {\n name: \"Regular chain\",\n chain: &nftables.Chain{\n Name: \"regular-chain\",\n },\n want: [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft delete chain ip filter regular-chain\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x12\\x00\\x03\\x00\\x72\\x65\\x67\\x75\\x6c\\x61\\x72\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\x00\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n },\n },\n }\n\n for _, tt := range tests {\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(tt.want[idx]) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n got := b\n if !bytes.Equal(got, tt.want[idx]) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(tt.want[idx])))\n }\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n tt.chain.Table = &nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n }\n c.DelChain(tt.chain)\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n }\n}\nfunc TestGetObjReset(t *testing.T) {\n // The want byte sequences come from stracing nft(8), e.g.:\n // strace -f -v -x -s 2048 -eraw=sendto nft list chain ip filter forward\n\n want := [][]byte{\n []byte{0x2, 0x0, 0x0, 0x0, 0xb, 0x0, 0x1, 0x0, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x0, 0x0, 0xa, 0x0, 0x2, 0x0, 0x66, 0x77, 0x64, 0x65, 0x64, 0x0, 0x0, 0x0, 0x8, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x1},\n }\n\n // The reply messages come from adding log.Printf(\"msgs: %#v\", msgs) to\n // (*github.com/mdlayher/netlink/Conn).receive\n reply := [][]netlink.Message{\n nil,\n []netlink.Message{netlink.Message{Header: netlink.Header{Length: 0x64, Type: 0xa12, Flags: 0x802, Sequence: 0x9acb0443, PID: 0xde9}, Data: []uint8{0x2, 0x0, 0x0, 0x10, 0xb, 0x0, 0x1, 0x0, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x0, 0x0, 0xa, 0x0, 0x2, 0x0, 0x66, 0x77, 0x64, 0x65, 0x64, 0x0, 0x0, 0x0, 0x8, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x1, 0x8, 0x0, 0x5, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1c, 0x0, 0x4, 0x0, 0xc, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x61, 0xc, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9, 0xc, 0x0, 0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}}},\n []netlink.Message{netlink.Message{Header: netlink.Header{Length: 0x14, Type: 0x3, Flags: 0x2, Sequence: 0x9acb0443, PID: 0xde9}, Data: []uint8{0x0, 0x0, 0x0, 0x0}}},\n []netlink.Message{netlink.Message{Header: netlink.Header{Length: 36, Type: netlink.Error, Flags: 0x100, Sequence: 0x9acb0443, PID: 0xde9}, Data: []uint8{0, 0, 0, 0, 88, 0, 0, 0, 12, 10, 5, 4, 143, 109, 199, 146, 236, 9, 0, 0}}},\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n rep := reply[0]\n reply = reply[1:]\n return rep, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n filter := &nftables.Table{Name: \"filter\", Family: nftables.TableFamilyIPv4}\n obj, err := c.ResetObject(&nftables.CounterObj{\n Table: filter,\n Name: \"fwded\",\n })\n\n if err != nil {\n t.Fatal(err)\n }\n\n co, ok := obj.(*nftables.CounterObj)\n if !ok {\n t.Fatalf(\"unexpected type: got %T, want *nftables.CounterObj\", obj)\n }\n if got, want := co.Table.Name, filter.Name; got != want {\n t.Errorf(\"unexpected table name: got %q, want %q\", got, want)\n }\n if got, want := co.Table.Family, filter.Family; got != want {\n t.Errorf(\"unexpected table family: got %d, want %d\", got, want)\n }\n if got, want := co.Packets, uint64(9); got != want {\n t.Errorf(\"unexpected number of packets: got %d, want %d\", got, want)\n }\n if got, want := co.Bytes, uint64(1121); got != want {\n t.Errorf(\"unexpected number of bytes: got %d, want %d\", got, want)\n }\n}\n\nfunc TestObjAPI(t *testing.T) {\n if os.Getenv(\"TRAVIS\") == \"true\" {\n t.SkipNow()\n }\n\n // Create a new network namespace to test these operations,\n // and tear down the namespace at test completion.\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n\n // Clear all rules at the beginning + end of the test.\n c.FlushRuleset()\n defer c.FlushRuleset()\n\n table := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n tableOther := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"foo\",\n })\n\n chain := c.AddChain(&nftables.Chain{\n Name: \"chain\",\n Table: table,\n Type: nftables.ChainTypeFilter,\n Hooknum: nftables.ChainHookPostrouting,\n Priority: nftables.ChainPriorityFilter,\n })\n\n counter1 := c.AddObj(&nftables.CounterObj{\n Table: table,\n Name: \"fwded1\",\n Bytes: 1,\n Packets: 1,\n })\n\n counter2 := c.AddObj(&nftables.CounterObj{\n Table: table,\n Name: \"fwded2\",\n Bytes: 1,\n Packets: 1,\n })\n\n c.AddObj(&nftables.CounterObj{\n Table: tableOther,\n Name: \"fwdedOther\",\n Bytes: 0,\n Packets: 0,\n })\n\n c.AddRule(&nftables.Rule{\n Table: table,\n Chain: chain,\n Exprs: []expr.Any{\n &expr.Objref{\n Type: 1,\n Name: \"fwded1\",\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatalf(err.Error())\n }\n\n objs, err := c.GetObjects(table)\n\n if err != nil {\n t.Errorf(\"c.GetObjects(table) failed: %v failed\", err)\n }\n\n if got := len(objs); got != 2 {\n t.Fatalf(\"unexpected number of objects: got %d, want %d\", got, 2)\n }\n\n objsOther, err := c.GetObjects(tableOther)\n\n if err != nil {\n t.Errorf(\"c.GetObjects(tableOther) failed: %v failed\", err)\n }\n\n if got := len(objsOther); got != 1 {\n t.Fatalf(\"unexpected number of objects: got %d, want %d\", got, 1)\n }\n\n obj1, err := c.GetObject(counter1)\n\n if err != nil {\n t.Errorf(\"c.GetObject(counter1) failed: %v failed\", err)\n }\n\n rcounter1, ok := obj1.(*nftables.CounterObj)\n\n if !ok {\n t.Fatalf(\"unexpected type: got %T, want *nftables.CounterObj\", rcounter1)\n }\n\n if rcounter1.Name != \"fwded1\" {\n t.Fatalf(\"unexpected counter name: got %s, want %s\", rcounter1.Name, \"fwded1\")\n }\n\n obj2, err := c.GetObject(counter2)\n\n if err != nil {\n t.Errorf(\"c.GetObject(counter2) failed: %v failed\", err)\n }\n\n rcounter2, ok := obj2.(*nftables.CounterObj)\n\n if !ok {\n t.Fatalf(\"unexpected type: got %T, want *nftables.CounterObj\", rcounter2)\n }\n\n if rcounter2.Name != \"fwded2\" {\n t.Fatalf(\"unexpected counter name: got %s, want %s\", rcounter2.Name, \"fwded2\")\n }\n\n _, err = c.ResetObject(counter1)\n\n if err != nil {\n t.Errorf(\"c.ResetObjects(table) failed: %v failed\", err)\n }\n\n obj1, err = c.GetObject(counter1)\n\n if err != nil {\n t.Errorf(\"c.GetObject(counter1) failed: %v failed\", err)\n }\n\n if counter1 := obj1.(*nftables.CounterObj); counter1.Packets > 0 {\n t.Errorf(\"unexpected packets number: got %d, want %d\", counter1.Packets, 0)\n }\n\n obj2, err = c.GetObject(counter2)\n\n if err != nil {\n t.Errorf(\"c.GetObject(counter2) failed: %v failed\", err)\n }\n\n if counter2 := obj2.(*nftables.CounterObj); counter2.Packets != 1 {\n t.Errorf(\"unexpected packets number: got %d, want %d\", counter2.Packets, 1)\n }\n\n legacy, err := c.GetObj(counter1)\n\n if err != nil {\n t.Errorf(\"c.GetObj(counter1) failed: %v failed\", err)\n }\n\n if len(legacy) != 2 {\n t.Errorf(\"unexpected number of objects: got %d, want %d\", len(legacy), 2)\n }\n\n legacyReset, err := c.GetObjReset(counter1)\n\n if err != nil {\n t.Errorf(\"c.GetObjReset(counter1) failed: %v failed\", err)\n }\n\n if len(legacyReset) != 2 {\n t.Errorf(\"unexpected number of objects: got %d, want %d\", len(legacyReset), 2)\n }\n\n}\n\nfunc TestConfigureClamping(t *testing.T) {\n // The want byte sequences come from stracing nft(8), e.g.:\n // strace -f -v -x -s 2048 -eraw=sendto nft add table ip nat\n //\n // The nft(8) command sequence was taken from:\n // https://wiki.nftables.org/wiki-nftables/index.php/Mangle_TCP_options\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft flush ruleset\n []byte(\"\\x00\\x00\\x00\\x00\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain filter forward '{' type filter hook forward priority 0 \\; '}'\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0c\\x00\\x03\\x00\\x66\\x6f\\x72\\x77\\x61\\x72\\x64\\x00\\x14\\x00\\x04\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x02\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x0b\\x00\\x07\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\"),\n // nft add rule ip filter forward oifname uplink0 tcp flags syn tcp option maxseg size set rt mtu\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0c\\x00\\x02\\x00\\x66\\x6f\\x72\\x77\\x61\\x72\\x64\\x00\\xf0\\x01\\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\\x07\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x38\\x00\\x01\\x80\\x08\\x00\\x01\\x00\\x63\\x6d\\x70\\x00\\x2c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x18\\x00\\x03\\x80\\x14\\x00\\x01\\x00\\x75\\x70\\x6c\\x69\\x6e\\x6b\\x30\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\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\\x0d\\x08\\x00\\x04\\x00\\x00\\x00\\x00\\x01\\x44\\x00\\x01\\x80\\x0c\\x00\\x01\\x00\\x62\\x69\\x74\\x77\\x69\\x73\\x65\\x00\\x34\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x01\\x0c\\x00\\x04\\x80\\x05\\x00\\x01\\x00\\x02\\x00\\x00\\x00\\x0c\\x00\\x05\\x80\\x05\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\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\\x01\\x0c\\x00\\x03\\x80\\x05\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x20\\x00\\x01\\x80\\x07\\x00\\x01\\x00\\x72\\x74\\x00\\x00\\x14\\x00\\x02\\x80\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x03\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x40\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x62\\x79\\x74\\x65\\x6f\\x72\\x64\\x65\\x72\\x00\\x00\\x00\\x2c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x04\\x00\\x00\\x00\\x00\\x02\\x08\\x00\\x05\\x00\\x00\\x00\\x00\\x02\\x3c\\x00\\x01\\x80\\x0b\\x00\\x01\\x00\\x65\\x78\\x74\\x68\\x64\\x72\\x00\\x00\\x2c\\x00\\x02\\x80\\x08\\x00\\x07\\x00\\x00\\x00\\x00\\x01\\x05\\x00\\x02\\x00\\x02\\x00\\x00\\x00\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x02\\x08\\x00\\x04\\x00\\x00\\x00\\x00\\x02\\x08\\x00\\x06\\x00\\x00\\x00\\x00\\x01\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n forward := c.AddChain(&nftables.Chain{\n Name: \"forward\",\n Table: filter,\n Type: nftables.ChainTypeFilter,\n Hooknum: nftables.ChainHookForward,\n Priority: nftables.ChainPriorityFilter,\n })\n\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: forward,\n Exprs: []expr.Any{\n // [ meta load oifname => reg 1 ]\n &expr.Meta{Key: expr.MetaKeyOIFNAME, Register: 1},\n // [ cmp eq reg 1 0x30707070 0x00000000 0x00000000 0x00000000 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: ifname(\"uplink0\"),\n },\n\n // [ meta load l4proto => reg 1 ]\n &expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1},\n // [ cmp eq reg 1 0x00000006 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{unix.IPPROTO_TCP},\n },\n\n // [ payload load 1b @ transport header + 13 => reg 1 ]\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseTransportHeader,\n Offset: 13, // TODO\n Len: 1, // TODO\n },\n // [ bitwise reg 1 = (reg=1 & 0x00000002 ) ^ 0x00000000 ]\n &expr.Bitwise{\n DestRegister: 1,\n SourceRegister: 1,\n Len: 1,\n Mask: []byte{0x02},\n Xor: []byte{0x00},\n },\n // [ cmp neq reg 1 0x00000000 ]\n &expr.Cmp{\n Op: expr.CmpOpNeq,\n Register: 1,\n Data: []byte{0x00},\n },\n\n // [ rt load tcpmss => reg 1 ]\n &expr.Rt{\n Register: 1,\n Key: expr.RtTCPMSS,\n },\n // [ byteorder reg 1 = hton(reg 1, 2, 2) ]\n &expr.Byteorder{\n DestRegister: 1,\n SourceRegister: 1,\n Op: expr.ByteorderHton,\n Len: 2,\n Size: 2,\n },\n // [ exthdr write tcpopt reg 1 => 2b @ 2 + 2 ]\n &expr.Exthdr{\n SourceRegister: 1,\n Type: 2, // TODO\n Offset: 2,\n Len: 2,\n Op: expr.ExthdrOpTcpopt,\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestMatchPacketHeader(t *testing.T) {\n // The want byte sequences come from stracing nft(8), e.g.:\n // strace -f -v -x -s 2048 -eraw=sendto nft add table ip nat\n //\n // The nft(8) command sequence was adopted from:\n // https://wiki.nftables.org/wiki-nftables/index.php/Matching_packet_headers\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft flush ruleset\n []byte(\"\\x00\\x00\\x00\\x00\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain filter input '{' type filter hook forward priority filter \\; '}'\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0a\\x00\\x03\\x00\\x69\\x6e\\x70\\x75\\x74\\x00\\x00\\x00\\x14\\x00\\x04\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x0b\\x00\\x07\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\"),\n // nft add rule ip filter input tcp flags syn tcp option maxseg size 1-500 drop\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0a\\x00\\x02\\x00\\x69\\x6e\\x70\\x75\\x74\\x00\\x00\\x00\\xc4\\x01\\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\\x0d\\x08\\x00\\x04\\x00\\x00\\x00\\x00\\x01\\x44\\x00\\x01\\x80\\x0c\\x00\\x01\\x00\\x62\\x69\\x74\\x77\\x69\\x73\\x65\\x00\\x34\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x01\\x0c\\x00\\x04\\x80\\x05\\x00\\x01\\x00\\x02\\x00\\x00\\x00\\x0c\\x00\\x05\\x80\\x05\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\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\\x01\\x0c\\x00\\x03\\x80\\x05\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x44\\x00\\x01\\x80\\x0b\\x00\\x01\\x00\\x65\\x78\\x74\\x68\\x64\\x72\\x00\\x00\\x34\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x05\\x00\\x02\\x00\\x02\\x00\\x00\\x00\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x02\\x08\\x00\\x04\\x00\\x00\\x00\\x00\\x02\\x08\\x00\\x06\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x05\\x00\\x00\\x00\\x00\\x00\\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\\x05\\x0c\\x00\\x03\\x80\\x06\\x00\\x01\\x00\\x00\\x01\\x00\\x00\\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\\x03\\x0c\\x00\\x03\\x80\\x06\\x00\\x01\\x00\\x01\\xf4\\x00\\x00\\x30\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x69\\x6d\\x6d\\x65\\x64\\x69\\x61\\x74\\x65\\x00\\x00\\x00\\x1c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x10\\x00\\x02\\x80\\x0c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n input := c.AddChain(&nftables.Chain{\n Name: \"input\",\n Table: filter,\n Type: nftables.ChainTypeFilter,\n Hooknum: nftables.ChainHookInput,\n Priority: nftables.ChainPriorityFilter,\n })\n\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: input,\n Exprs: []expr.Any{\n // [ meta load l4proto => reg 1 ]\n &expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1},\n // [ cmp eq reg 1 0x00000006 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{unix.IPPROTO_TCP},\n },\n\n // [ payload load 1b @ transport header + 13 => reg 1 ]\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseTransportHeader,\n Offset: 13, // TODO\n Len: 1, // TODO\n },\n // [ bitwise reg 1 = (reg=1 & 0x00000002 ) ^ 0x00000000 ]\n &expr.Bitwise{\n DestRegister: 1,\n SourceRegister: 1,\n Len: 1,\n Mask: []byte{0x02},\n Xor: []byte{0x00},\n },\n // [ cmp neq reg 1 0x00000000 ]\n &expr.Cmp{\n Op: expr.CmpOpNeq,\n Register: 1,\n Data: []byte{0x00},\n },\n\n // [ exthdr load tcpopt 2b @ 2 + 2 => reg 1 ]\n &expr.Exthdr{\n DestRegister: 1,\n Type: 2, // TODO\n Offset: 2,\n Len: 2,\n Op: expr.ExthdrOpTcpopt,\n },\n\n // [ cmp gte reg 1 0x00000100 ]\n &expr.Cmp{\n Op: expr.CmpOpGte,\n Register: 1,\n Data: binaryutil.BigEndian.PutUint16(uint16(1)),\n },\n // [ cmp lte reg 1 0x0000f401 ]\n &expr.Cmp{\n Op: expr.CmpOpLte,\n Register: 1,\n Data: binaryutil.BigEndian.PutUint16(uint16(500)),\n },\n // [ immediate reg 0 drop ]\n &expr.Verdict{\n Kind: expr.VerdictDrop,\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestDropVerdict(t *testing.T) {\n // The want byte sequences come from stracing nft(8), e.g.:\n // strace -f -v -x -s 2048 -eraw=sendto nft add table ip nat\n //\n // The nft(8) command sequence was taken from:\n // https://wiki.nftables.org/wiki-nftables/index.php/Mangle_TCP_options\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft flush ruleset\n []byte(\"\\x00\\x00\\x00\\x00\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain filter forward '{' type filter hook forward priority 0 \\; '}'\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0c\\x00\\x03\\x00\\x66\\x6f\\x72\\x77\\x61\\x72\\x64\\x00\\x14\\x00\\x04\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x02\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x0b\\x00\\x07\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\"),\n // nft add rule filter forward tcp dport 1234 drop\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0c\\x00\\x02\\x00\\x66\\x6f\\x72\\x77\\x61\\x72\\x64\\x00\\xe4\\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\\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\\x06\\x00\\x01\\x00\\x04\\xd2\\x00\\x00\\x30\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x69\\x6d\\x6d\\x65\\x64\\x69\\x61\\x74\\x65\\x00\\x00\\x00\\x1c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x10\\x00\\x02\\x80\\x0c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n forward := c.AddChain(&nftables.Chain{\n Name: \"forward\",\n Table: filter,\n Type: nftables.ChainTypeFilter,\n Hooknum: nftables.ChainHookForward,\n Priority: nftables.ChainPriorityFilter,\n })\n\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: forward,\n Exprs: []expr.Any{\n // [ meta load l4proto => reg 1 ]\n &expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1},\n // [ cmp eq reg 1 0x00000006 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{unix.IPPROTO_TCP},\n },\n\n // [ payload load 2b @ transport header + 2 => reg 1 ]\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseTransportHeader,\n Offset: 2,\n Len: 2,\n },\n // [ cmp eq reg 1 0x0000d204 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{0x04, 0xd2},\n },\n // [ immediate reg 0 drop ]\n &expr.Verdict{\n Kind: expr.VerdictDrop,\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestCreateUseAnonymousSet(t *testing.T) {\n // The want byte sequences come from stracing nft(8), e.g.:\n // strace -f -v -x -s 2048 -eraw=sendto nft add table ip nat\n //\n // The nft(8) command sequence was taken from:\n // https://wiki.nftables.org/wiki-nftables/index.php/Mangle_TCP_options\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft flush ruleset\n []byte(\"\\x00\\x00\\x00\\x00\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // Create anonymous set with key len of 2 bytes and data len of 0 bytes\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0c\\x00\\x02\\x00\\x5f\\x5f\\x73\\x65\\x74\\x25\\x64\\x00\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x03\\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\\x02\\x0a\\x00\\x0d\\x00\\x00\\x04\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // Assign the two values to the aforementioned anonymous set\n []byte(\"\\x02\\x00\\x00\\x00\\x0c\\x00\\x02\\x00\\x5f\\x5f\\x73\\x65\\x74\\x25\\x64\\x00\\x08\\x00\\x04\\x00\\x00\\x00\\x00\\x01\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x24\\x00\\x03\\x80\\x10\\x00\\x01\\x80\\x0c\\x00\\x01\\x80\\x06\\x00\\x01\\x00\\x00\\x45\\x00\\x00\\x10\\x00\\x02\\x80\\x0c\\x00\\x01\\x80\\x06\\x00\\x01\\x00\\x04\\x8b\\x00\\x00\"),\n // nft add rule filter forward tcp dport {69, 1163} drop\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0c\\x00\\x02\\x00\\x66\\x6f\\x72\\x77\\x61\\x72\\x64\\x00\\xe8\\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\\x30\\x00\\x01\\x80\\x0b\\x00\\x01\\x00\\x6c\\x6f\\x6f\\x6b\\x75\\x70\\x00\\x00\\x20\\x00\\x02\\x80\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x01\\x0c\\x00\\x01\\x00\\x5f\\x5f\\x73\\x65\\x74\\x25\\x64\\x00\\x08\\x00\\x04\\x00\\x00\\x00\\x00\\x01\\x30\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x69\\x6d\\x6d\\x65\\x64\\x69\\x61\\x74\\x65\\x00\\x00\\x00\\x1c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x10\\x00\\x02\\x80\\x0c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n set := &nftables.Set{\n Anonymous: true,\n Constant: true,\n Table: filter,\n KeyType: nftables.TypeInetService,\n }\n\n if err := c.AddSet(set, []nftables.SetElement{\n {Key: binaryutil.BigEndian.PutUint16(69)},\n {Key: binaryutil.BigEndian.PutUint16(1163)},\n }); err != nil {\n t.Errorf(\"c.AddSet() failed: %v\", err)\n }\n\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: &nftables.Chain{Name: \"forward\", Type: nftables.ChainTypeFilter},\n Exprs: []expr.Any{\n // [ meta load l4proto => reg 1 ]\n &expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1},\n // [ cmp eq reg 1 0x00000006 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{unix.IPPROTO_TCP},\n },\n\n // [ payload load 2b @ transport header + 2 => reg 1 ]\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseTransportHeader,\n Offset: 2,\n Len: 2,\n },\n // [ lookup reg 1 set __set%d ]\n &expr.Lookup{\n SourceRegister: 1,\n SetName: set.Name,\n SetID: set.ID,\n },\n // [ immediate reg 0 drop ]\n &expr.Verdict{\n Kind: expr.VerdictDrop,\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestCappedErrMsgOnSets(t *testing.T) {\n c, newNS := openSystemNFTConn(t)\n c, err := nftables.New(nftables.WithNetNSFd(int(newNS)), nftables.AsLasting())\n if err != nil {\n t.Fatalf(\"nftables.New() failed: %v\", err)\n }\n defer cleanupSystemNFTConn(t, newNS)\n c.FlushRuleset()\n defer c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n if err := c.Flush(); err != nil {\n t.Errorf(\"failed adding table: %v\", err)\n }\n tables, err := c.ListTablesOfFamily(nftables.TableFamilyIPv4)\n if err != nil {\n t.Errorf(\"failed to list IPv4 tables: %v\", err)\n }\n\n for _, t := range tables {\n if t.Name == \"filter\" {\n filter = t\n break\n }\n }\n\n ifSet := &nftables.Set{\n Table: filter,\n Name: \"if_set\",\n KeyType: nftables.TypeIFName,\n }\n if err := c.AddSet(ifSet, nil); err != nil {\n t.Errorf(\"c.AddSet(ifSet) failed: %v\", err)\n }\n if err := c.Flush(); err != nil {\n t.Errorf(\"failed adding set ifSet: %v\", err)\n }\n ifSet, err = c.GetSetByName(filter, \"if_set\")\n if err != nil {\n t.Fatalf(\"failed getting set by name: %v\", err)\n }\n\n elems, err := c.GetSetElements(ifSet)\n if err != nil {\n t.Errorf(\"failed getting set elements (ifSet): %v\", err)\n }\n\n if got, want := len(elems), 0; got != want {\n t.Errorf(\"first GetSetElements(ifSet) call len not equal: got %d, want %d\", got, want)\n }\n\n elements := []nftables.SetElement{\n {Key: []byte(\"012345678912345\\x00\")},\n }\n if err := c.SetAddElements(ifSet, elements); err != nil {\n t.Errorf(\"adding SetElements(ifSet) failed: %v\", err)\n }\n if err := c.Flush(); err != nil {\n t.Errorf(\"failed adding set elements ifSet: %v\", err)\n }\n\n elems, err = c.GetSetElements(ifSet)\n if err != nil {\n t.Fatalf(\"failed getting set elements (ifSet): %v\", err)\n }\n\n if got, want := len(elems), 1; got != want {\n t.Fatalf(\"second GetSetElements(ifSet) call len not equal: got %d, want %d\", got, want)\n }\n\n if got, want := elems, elements; !reflect.DeepEqual(elems, elements) {\n t.Errorf(\"SetElements(ifSet) not equal: got %v, want %v\", got, want)\n }\n}\n\nfunc TestCreateUseNamedSet(t *testing.T) {\n // Create a new network namespace to test these operations,\n // and tear down the namespace at test completion.\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n // Clear all rules at the beginning + end of the test.\n c.FlushRuleset()\n defer c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n portSet := &nftables.Set{\n Table: filter,\n Name: \"test\",\n KeyType: nftables.TypeInetService,\n }\n if err := c.AddSet(portSet, nil); err != nil {\n t.Errorf(\"c.AddSet(portSet) failed: %v\", err)\n }\n if err := c.SetAddElements(portSet, []nftables.SetElement{{Key: binaryutil.BigEndian.PutUint16(22)}}); err != nil {\n t.Errorf(\"c.SetVal(portSet) failed: %v\", err)\n }\n\n ipSet := &nftables.Set{\n Table: filter,\n Name: \"IPs_4_dayz\",\n KeyType: nftables.TypeIPAddr,\n }\n if err := c.AddSet(ipSet, []nftables.SetElement{{Key: []byte(net.ParseIP(\"192.168.1.64\").To4())}}); err != nil {\n t.Errorf(\"c.AddSet(ipSet) failed: %v\", err)\n }\n if err := c.SetAddElements(ipSet, []nftables.SetElement{{Key: []byte(net.ParseIP(\"192.168.1.42\").To4())}}); err != nil {\n t.Errorf(\"c.SetVal(ipSet) failed: %v\", err)\n }\n if err := c.Flush(); err != nil {\n t.Errorf(\"c.Flush() failed: %v\", err)\n }\n\n sets, err := c.GetSets(filter)\n if err != nil {\n t.Errorf(\"c.GetSets() failed: %v\", err)\n }\n if len(sets) != 2 {\n t.Fatalf(\"len(sets) = %d, want 2\", len(sets))\n }\n if sets[0].Name != \"test\" {\n t.Errorf(\"set[0].Name = %q, want test\", sets[0].Name)\n }\n if sets[1].Name != \"IPs_4_dayz\" {\n t.Errorf(\"set[1].Name = %q, want IPs_4_dayz\", sets[1].Name)\n }\n}\n\nfunc TestIP6SetAddElements(t *testing.T) {\n\n // Create a new network namespace to test these operations,\n // and tear down the namespace at test completion.\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n // Clear all rules at the beginning + end of the test.\n c.FlushRuleset()\n defer c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv6,\n Name: \"filter\",\n })\n portSet := &nftables.Set{\n Table: filter,\n Name: \"ports\",\n KeyType: nftables.TypeInetService,\n }\n if err := c.AddSet(portSet, nil); err != nil {\n t.Errorf(\"c.AddSet(portSet) failed: %v\", err)\n }\n if err := c.SetAddElements(portSet, []nftables.SetElement{\n {Key: binaryutil.BigEndian.PutUint16(22)},\n {Key: binaryutil.BigEndian.PutUint16(80)},\n }); err != nil {\n t.Errorf(\"c.SetVal(portSet) failed: %v\", err)\n }\n\n if err := c.Flush(); err != nil {\n t.Errorf(\"c.Flush() failed: %v\", err)\n }\n\n sets, err := c.GetSets(filter)\n if err != nil {\n t.Errorf(\"c.GetSets() failed: %v\", err)\n }\n if len(sets) != 1 {\n t.Fatalf(\"len(sets) = %d, want 1\", len(sets))\n }\n\n elements, err := c.GetSetElements(sets[0])\n if err != nil {\n t.Errorf(\"c.GetSetElements(portSet) failed: %v\", err)\n }\n if len(elements) != 2 {\n t.Fatalf(\"len(portSetElements) = %d, want 2\", len(sets))\n }\n}\n\nfunc TestCreateUseCounterSet(t *testing.T) {\n // Create a new network namespace to test these operations,\n // and tear down the namespace at test completion.\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n // Clear all rules at the beginning + end of the test.\n c.FlushRuleset()\n defer c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n portSet := &nftables.Set{\n Table: filter,\n Name: \"test\",\n KeyType: nftables.TypeInetService,\n Counter: true,\n }\n if err := c.AddSet(portSet, nil); err != nil {\n t.Errorf(\"c.AddSet(portSet) failed: %v\", err)\n }\n if err := c.SetAddElements(portSet, []nftables.SetElement{{Key: binaryutil.BigEndian.PutUint16(22)}}); err != nil {\n t.Errorf(\"c.SetVal(portSet) failed: %v\", err)\n }\n\n if err := c.Flush(); err != nil {\n t.Errorf(\"c.Flush() failed: %v\", err)\n }\n\n sets, err := c.GetSets(filter)\n if err != nil {\n t.Errorf(\"c.GetSets() failed: %v\", err)\n }\n if len(sets) != 1 {\n t.Fatalf(\"len(sets) = %d, want 1\", len(sets))\n }\n if sets[0].Name != \"test\" {\n t.Errorf(\"set[0].Name = %q, want test\", sets[0].Name)\n }\n}\n\nfunc TestCreateDeleteNamedSet(t *testing.T) {\n // Create a new network namespace to test these operations,\n // and tear down the namespace at test completion.\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n // Clear all rules at the beginning + end of the test.\n c.FlushRuleset()\n defer c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n portSet := &nftables.Set{\n Table: filter,\n Name: \"test\",\n KeyType: nftables.TypeInetService,\n }\n if err := c.AddSet(portSet, nil); err != nil {\n t.Errorf(\"c.AddSet(portSet) failed: %v\", err)\n }\n if err := c.Flush(); err != nil {\n t.Errorf(\"c.Flush() failed: %v\", err)\n }\n\n c.DelSet(portSet)\n\n if err := c.Flush(); err != nil {\n t.Errorf(\"Second c.Flush() failed: %v\", err)\n }\n\n sets, err := c.GetSets(filter)\n if err != nil {\n t.Errorf(\"c.GetSets() failed: %v\", err)\n }\n if len(sets) != 0 {\n t.Fatalf(\"len(sets) = %d, want 0\", len(sets))\n }\n}\n\nfunc TestDeleteElementNamedSet(t *testing.T) {\n // Create a new network namespace to test these operations,\n // and tear down the namespace at test completion.\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n // Clear all rules at the beginning + end of the test.\n c.FlushRuleset()\n defer c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n portSet := &nftables.Set{\n Table: filter,\n Name: \"test\",\n KeyType: nftables.TypeInetService,\n }\n if err := c.AddSet(portSet, []nftables.SetElement{{Key: []byte{0, 22}}, {Key: []byte{0, 23}}}); err != nil {\n t.Errorf(\"c.AddSet(portSet) failed: %v\", err)\n }\n if err := c.Flush(); err != nil {\n t.Errorf(\"c.Flush() failed: %v\", err)\n }\n\n c.SetDeleteElements(portSet, []nftables.SetElement{{Key: []byte{0, 23}}})\n\n if err := c.Flush(); err != nil {\n t.Errorf(\"Second c.Flush() failed: %v\", err)\n }\n\n elems, err := c.GetSetElements(portSet)\n if err != nil {\n t.Errorf(\"c.GetSets() failed: %v\", err)\n }\n if len(elems) != 1 {\n t.Fatalf(\"len(elems) = %d, want 1\", len(elems))\n }\n if !bytes.Equal(elems[0].Key, []byte{0, 22}) {\n t.Errorf(\"elems[0].Key = %v, want 22\", elems[0].Key)\n }\n}\n\nfunc TestFlushNamedSet(t *testing.T) {\n if os.Getenv(\"TRAVIS\") == \"true\" {\n t.SkipNow()\n }\n // Create a new network namespace to test these operations,\n // and tear down the namespace at test completion.\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n // Clear all rules at the beginning + end of the test.\n c.FlushRuleset()\n defer c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n portSet := &nftables.Set{\n Table: filter,\n Name: \"test\",\n KeyType: nftables.TypeInetService,\n }\n if err := c.AddSet(portSet, []nftables.SetElement{{Key: []byte{0, 22}}, {Key: []byte{0, 23}}}); err != nil {\n t.Errorf(\"c.AddSet(portSet) failed: %v\", err)\n }\n if err := c.Flush(); err != nil {\n t.Errorf(\"c.Flush() failed: %v\", err)\n }\n\n c.FlushSet(portSet)\n\n if err := c.Flush(); err != nil {\n t.Errorf(\"Second c.Flush() failed: %v\", err)\n }\n\n elems, err := c.GetSetElements(portSet)\n if err != nil {\n t.Errorf(\"c.GetSets() failed: %v\", err)\n }\n if len(elems) != 0 {\n t.Fatalf(\"len(elems) = %d, want 0\", len(elems))\n }\n}\n\nfunc TestSetElementsInterval(t *testing.T) {\n // Create a new network namespace to test these operations,\n // and tear down the namespace at test completion.\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n // Clear all rules at the beginning + end of the test.\n c.FlushRuleset()\n defer c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv6,\n Name: \"filter\",\n })\n portSet := &nftables.Set{\n Table: filter,\n Name: \"ports\",\n KeyType: nftables.MustConcatSetType(nftables.TypeIP6Addr, nftables.TypeInetService, nftables.TypeIP6Addr),\n Interval: true,\n Concatenation: true,\n }\n if err := c.AddSet(portSet, nil); err != nil {\n t.Errorf(\"c.AddSet(portSet) failed: %v\", err)\n }\n\n // { 777c:ab4b:85f0:1614:49e5:d29b:aa7b:cc90 . 50000 . 8709:1cb9:163e:9b55:357f:ef64:708a:edcb }\n keyBytes := []byte{119, 124, 171, 75, 133, 240, 22, 20, 73, 229, 210, 155, 170, 123, 204, 144, 195, 80, 0, 0, 135, 9, 28, 185, 22, 62, 155, 85, 53, 127, 239, 100, 112, 138, 237, 203}\n // { 777c:ab4b:85f0:1614:49e5:d29b:aa7b:cc90 . 60000 . 8709:1cb9:163e:9b55:357f:ef64:708a:edcb }\n keyEndBytes := []byte{119, 124, 171, 75, 133, 240, 22, 20, 73, 229, 210, 155, 170, 123, 204, 144, 234, 96, 0, 0, 135, 9, 28, 185, 22, 62, 155, 85, 53, 127, 239, 100, 112, 138, 237, 203}\n // elements = { 777c:ab4b:85f0:1614:49e5:d29b:aa7b:cc90 . 50000-60000 . 8709:1cb9:163e:9b55:357f:ef64:708a:edcb }\n if err := c.SetAddElements(portSet, []nftables.SetElement{\n {Key: keyBytes, KeyEnd: keyEndBytes},\n }); err != nil {\n t.Errorf(\"c.SetVal(portSet) failed: %v\", err)\n }\n\n if err := c.Flush(); err != nil {\n t.Errorf(\"c.Flush() failed: %v\", err)\n }\n\n sets, err := c.GetSets(filter)\n if err != nil {\n t.Errorf(\"c.GetSets() failed: %v\", err)\n }\n if len(sets) != 1 {\n t.Fatalf(\"len(sets) = %d, want 1\", len(sets))\n }\n\n elements, err := c.GetSetElements(sets[0])\n if err != nil {\n t.Errorf(\"c.GetSetElements(portSet) failed: %v\", err)\n }\n if len(elements) != 1 {\n t.Fatalf(\"len(portSetElements) = %d, want 1\", len(sets))\n }\n\n element := elements[0]\n if len(element.Key) == 0 {\n t.Fatal(\"len(portSetElements.Key) = 0\")\n }\n if len(element.KeyEnd) == 0 {\n t.Fatal(\"len(portSetElements.KeyEnd) = 0\")\n }\n if !bytes.Equal(element.Key, keyBytes) {\n t.Fatal(\"element.Key != keyBytes\")\n }\n if !bytes.Equal(element.KeyEnd, keyEndBytes) {\n t.Fatal(\"element.KeyEnd != keyEndBytes\")\n }\n}\n\nfunc TestCreateListFlowtable(t *testing.T) {\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n c.FlushRuleset()\n defer c.FlushRuleset()\n\n filter := &nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n }\n\n flowtable := &nftables.Flowtable{\n Table: filter,\n Name: \"flowtable_test\",\n }\n\n c.AddTable(filter)\n c.AddFlowtable(flowtable)\n\n if err := c.Flush(); err != nil {\n t.Fatalf(\"c.Flush() failed: %v\", err)\n }\n\n flowtables, err := c.ListFlowtables(filter)\n if err != nil {\n t.Fatalf(\"c.ListFlowtables() failed: %v\", err)\n }\n\n if got, want := len(flowtables), 1; got != want {\n t.Fatalf(\"flowtable entry length mismatch: got %d, want %d\", got, want)\n }\n}\n\nfunc TestCreateListFlowtableWithDevices(t *testing.T) {\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n c.FlushRuleset()\n defer c.FlushRuleset()\n\n filter := &nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n }\n\n lo, err := net.InterfaceByName(\"lo\")\n if err != nil {\n t.Fatalf(\"net.InterfaceByName() failed: %v\", err)\n }\n\n flowtable := &nftables.Flowtable{\n Table: filter,\n Name: \"flowtable_test\",\n Devices: []string{lo.Name},\n Hooknum: nftables.FlowtableHookIngress,\n Priority: nftables.FlowtablePriorityRef(5),\n }\n\n c.AddTable(filter)\n c.AddFlowtable(flowtable)\n\n if err := c.Flush(); err != nil {\n t.Fatalf(\"c.Flush() failed: %v\", err)\n }\n\n flowtables, err := c.ListFlowtables(filter)\n if err != nil {\n t.Fatalf(\"c.ListFlowtables() failed: %v\", err)\n }\n\n if got, want := len(flowtables), 1; got != want {\n t.Fatalf(\"flowtable entry length mismatch: got %d, want %d\", got, want)\n }\n\n sysFlowtable := flowtables[0]\n if got, want := sysFlowtable.Table, flowtable.Table; got != want {\n t.Errorf(\"flowtables table mismatch: got %v, want %v\", got, want)\n }\n\n if got, want := sysFlowtable.Name, flowtable.Name; got != want {\n t.Errorf(\"flowtables name mismatch: got %s, want %s\", got, want)\n }\n\n if len(sysFlowtable.Devices) != 1 {\n t.Fatalf(\"expected 1 device in flowtable, got %d\", len(sysFlowtable.Devices))\n }\n\n if got, want := sysFlowtable.Devices, flowtable.Devices; !reflect.DeepEqual(got, want) {\n t.Errorf(\"flowtables device mismatch: got %v, want %v\", got, want)\n }\n\n if got, want := *sysFlowtable.Hooknum, *flowtable.Hooknum; got != want {\n t.Errorf(\"flowtables hook mismatch: got %v, want %v\", got, want)\n }\n\n if got, want := *sysFlowtable.Priority, *flowtable.Priority; got != want {\n t.Errorf(\"flowtables prio mismatch: got %v, want %v\", got, want)\n }\n}\n\nfunc TestCreateDeleteFlowtable(t *testing.T) {\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n c.FlushRuleset()\n defer c.FlushRuleset()\n\n filter := &nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n }\n\n flowtable := &nftables.Flowtable{\n Table: filter,\n Name: \"flowtable_test\",\n }\n\n c.AddTable(filter)\n c.AddFlowtable(flowtable)\n flowtable.Name = \"flowtable_test_to_delete\"\n c.AddFlowtable(flowtable)\n\n if err := c.Flush(); err != nil {\n t.Fatalf(\"c.Flush() failed: %v\", err)\n }\n\n flowtables, err := c.ListFlowtables(filter)\n if err != nil {\n t.Fatalf(\"c.ListFlowtables() failed: %v\", err)\n }\n\n if got, want := len(flowtables), 2; got != want {\n t.Fatalf(\"flowtable entry length mismatch: got %d, want %d\", got, want)\n }\n\n c.DelFlowtable(flowtable)\n if err := c.Flush(); err != nil {\n t.Fatalf(\"c.Flush() failed: %v\", err)\n }\n\n flowtables, err = c.ListFlowtables(filter)\n if err != nil {\n t.Fatalf(\"c.ListFlowtables() after deletion failed: %v\", err)\n }\n\n if got, want := len(flowtables), 1; got != want {\n t.Errorf(\"flowtable entry length mismatch: got %d, want %d\", got, want)\n }\n\n if got, removed := flowtables[0].Name, flowtable.Name; got == removed {\n t.Errorf(\"wrong flowtable entry deleted\")\n }\n}\n\nfunc TestOffload(t *testing.T) {\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n c.FlushRuleset()\n defer c.FlushRuleset()\n\n filter := &nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n }\n\n accept := nftables.ChainPolicyAccept\n forward := &nftables.Chain{\n Name: \"forward\",\n Table: filter,\n Type: nftables.ChainTypeFilter,\n Priority: nftables.ChainPriorityFilter,\n Hooknum: nftables.ChainHookForward,\n Policy: &accept,\n }\n\n flowtable := &nftables.Flowtable{\n Table: filter,\n Name: \"flowtable_test\",\n }\n\n c.AddTable(filter)\n c.AddChain(forward)\n c.AddFlowtable(flowtable)\n\n if err := c.Flush(); err != nil {\n t.Fatalf(\"c.Flush() failed: %v\", err)\n }\n\n rule := &nftables.Rule{\n Table: filter,\n Chain: forward,\n Exprs: []expr.Any{\n &expr.Payload{\n OperationType: expr.PayloadLoad,\n Base: expr.PayloadBaseNetworkHeader,\n Len: 1,\n Offset: 9,\n DestRegister: 1,\n },\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{0x06, 0x00, 0x00, 0x00},\n },\n &expr.FlowOffload{\n Name: flowtable.Name,\n },\n },\n }\n c.AddRule(rule)\n\n if err := c.Flush(); err != nil {\n t.Fatalf(\"c.Flush() offload failed: %v\", err)\n }\n\n rules, err := c.GetRule(filter, forward)\n if err != nil {\n t.Fatalf(\"c.GetRule() failed: %v\", err)\n }\n\n if got, want := len(rules), 1; got != want {\n t.Fatalf(\"rule count mismatch: got %d, want %d\", got, want)\n }\n\n sysRule := rules[0]\n if got, want := sysRule.Exprs, rule.Exprs; !reflect.DeepEqual(got, want) {\n t.Errorf(\"rule content mismatch: got %v, want %v\", got, want)\n }\n}\n\nfunc TestFlushChain(t *testing.T) {\n // Create a new network namespace to test these operations,\n // and tear down the namespace at test completion.\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n // Clear all rules at the beginning + end of the test.\n c.FlushRuleset()\n defer c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n forward := c.AddChain(&nftables.Chain{\n Table: filter,\n Name: \"forward\",\n })\n\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: forward,\n Exprs: []expr.Any{\n // [ meta load l4proto => reg 1 ]\n &expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1},\n // [ cmp eq reg 1 0x00000006 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{unix.IPPROTO_TCP},\n },\n\n // [ payload load 2b @ transport header + 2 => reg 1 ]\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseTransportHeader,\n Offset: 2,\n Len: 2,\n },\n // [ cmp eq reg 1 0x0000d204 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{0x04, 0xd2},\n },\n // [ immediate reg 0 drop ]\n &expr.Verdict{\n Kind: expr.VerdictDrop,\n },\n },\n })\n\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: forward,\n Exprs: []expr.Any{\n // [ meta load l4proto => reg 1 ]\n &expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1},\n // [ cmp eq reg 1 0x00000006 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{unix.IPPROTO_TCP},\n },\n\n // [ payload load 2b @ transport header + 2 => reg 1 ]\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseTransportHeader,\n Offset: 2,\n Len: 2,\n },\n // [ cmp eq reg 1 0x000010e1 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{0xe1, 0x10},\n },\n // [ immediate reg 0 drop ]\n &expr.Verdict{\n Kind: expr.VerdictDrop,\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Errorf(\"c.Flush() failed: %v\", err)\n }\n rules, err := c.GetRules(filter, forward)\n if err != nil {\n t.Errorf(\"c.GetRules() failed: %v\", err)\n }\n if len(rules) != 2 {\n t.Fatalf(\"len(rules) = %d, want 2\", len(rules))\n }\n\n c.FlushChain(forward)\n\n if err := c.Flush(); err != nil {\n t.Errorf(\"Second c.Flush() failed: %v\", err)\n }\n\n rules, err = c.GetRules(filter, forward)\n if err != nil {\n t.Errorf(\"c.GetRules() failed: %v\", err)\n }\n if len(rules) != 0 {\n t.Fatalf(\"len(rules) = %d, want 0\", len(rules))\n }\n}\n\nfunc TestFlushTable(t *testing.T) {\n if os.Getenv(\"TRAVIS\") == \"true\" {\n t.SkipNow()\n }\n // Create a new network namespace to test these operations,\n // and tear down the namespace at test completion.\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n // Clear all rules at the beginning + end of the test.\n c.FlushRuleset()\n defer c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n nat := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"nat\",\n })\n\n forward := c.AddChain(&nftables.Chain{\n Table: filter,\n Name: \"forward\",\n })\n\n input := c.AddChain(&nftables.Chain{\n Table: filter,\n Name: \"input\",\n })\n\n prerouting := c.AddChain(&nftables.Chain{\n Table: nat,\n Name: \"prerouting\",\n })\n\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: forward,\n Exprs: []expr.Any{\n // [ meta load l4proto => reg 1 ]\n &expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1},\n // [ cmp eq reg 1 0x00000006 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{unix.IPPROTO_TCP},\n },\n\n // [ payload load 2b @ transport header + 2 => reg 1 ]\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseTransportHeader,\n Offset: 2,\n Len: 2,\n },\n // [ cmp eq reg 1 0x0000d204 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{0x04, 0xd2},\n },\n // [ immediate reg 0 drop ]\n &expr.Verdict{\n Kind: expr.VerdictDrop,\n },\n },\n })\n\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: forward,\n Exprs: []expr.Any{\n // [ meta load l4proto => reg 1 ]\n &expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1},\n // [ cmp eq reg 1 0x00000006 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{unix.IPPROTO_TCP},\n },\n\n // [ payload load 2b @ transport header + 2 => reg 1 ]\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseTransportHeader,\n Offset: 2,\n Len: 2,\n },\n // [ cmp eq reg 1 0x000010e1 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{0xe1, 0x10},\n },\n // [ immediate reg 0 drop ]\n &expr.Verdict{\n Kind: expr.VerdictDrop,\n },\n },\n })\n\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: input,\n Exprs: []expr.Any{\n // [ meta load l4proto => reg 1 ]\n &expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1},\n // [ cmp eq reg 1 0x00000006 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{unix.IPPROTO_TCP},\n },\n\n // [ payload load 2b @ transport header + 2 => reg 1 ]\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseTransportHeader,\n Offset: 2,\n Len: 2,\n },\n // [ cmp eq reg 1 0x0000162e ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{0x2e, 0x16},\n },\n // [ immediate reg 0 drop ]\n &expr.Verdict{\n Kind: expr.VerdictDrop,\n },\n },\n })\n\n c.AddRule(&nftables.Rule{\n Table: nat,\n Chain: prerouting,\n Exprs: []expr.Any{\n // [ meta load l4proto => reg 1 ]\n &expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1},\n // [ cmp eq reg 1 0x00000006 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{unix.IPPROTO_TCP},\n },\n\n // [ payload load 2b @ transport header + 2 => reg 1 ]\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseTransportHeader,\n Offset: 2, // TODO\n Len: 2, // TODO\n },\n // [ cmp eq reg 1 0x00001600 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{0x00, 0x16},\n },\n\n // [ immediate reg 1 0x0000ae08 ]\n &expr.Immediate{\n Register: 1,\n Data: binaryutil.BigEndian.PutUint16(2222),\n },\n\n // [ redir proto_min reg 1 ]\n &expr.Redir{\n RegisterProtoMin: 1,\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Errorf(\"c.Flush() failed: %v\", err)\n }\n rules, err := c.GetRules(filter, forward)\n if err != nil {\n t.Errorf(\"c.GetRules() failed: %v\", err)\n }\n if len(rules) != 2 {\n t.Fatalf(\"len(rules) = %d, want 2\", len(rules))\n }\n rules, err = c.GetRules(filter, input)\n if err != nil {\n t.Errorf(\"c.GetRules() failed: %v\", err)\n }\n if len(rules) != 1 {\n t.Fatalf(\"len(rules) = %d, want 1\", len(rules))\n }\n rules, err = c.GetRules(nat, prerouting)\n if err != nil {\n t.Errorf(\"c.GetRules() failed: %v\", err)\n }\n if len(rules) != 1 {\n t.Fatalf(\"len(rules) = %d, want 1\", len(rules))\n }\n\n c.FlushTable(filter)\n\n if err := c.Flush(); err != nil {\n t.Errorf(\"Second c.Flush() failed: %v\", err)\n }\n\n rules, err = c.GetRules(filter, forward)\n if err != nil {\n t.Errorf(\"c.GetRules() failed: %v\", err)\n }\n if len(rules) != 0 {\n t.Fatalf(\"len(rules) = %d, want 0\", len(rules))\n }\n rules, err = c.GetRules(filter, input)\n if err != nil {\n t.Errorf(\"c.GetRules() failed: %v\", err)\n }\n if len(rules) != 0 {\n t.Fatalf(\"len(rules) = %d, want 0\", len(rules))\n }\n rules, err = c.GetRules(nat, prerouting)\n if err != nil {\n t.Errorf(\"c.GetRules() failed: %v\", err)\n }\n if len(rules) != 1 {\n t.Fatalf(\"len(rules) = %d, want 1\", len(rules))\n }\n}\n\nfunc TestGetLookupExprDestSet(t *testing.T) {\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n c.FlushRuleset()\n defer c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n forward := c.AddChain(&nftables.Chain{\n Name: \"forward\",\n Table: filter,\n Type: nftables.ChainTypeFilter,\n Hooknum: nftables.ChainHookForward,\n Priority: nftables.ChainPriorityFilter,\n })\n\n set := &nftables.Set{\n Table: filter,\n Name: \"test\",\n IsMap: true,\n KeyType: nftables.TypeInetService,\n DataType: nftables.TypeVerdict,\n }\n if err := c.AddSet(set, nil); err != nil {\n t.Errorf(\"c.AddSet(set) failed: %v\", err)\n }\n if err := c.Flush(); err != nil {\n t.Errorf(\"c.Flush() failed: %v\", err)\n }\n\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: forward,\n Exprs: []expr.Any{\n &expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1},\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{unix.IPPROTO_TCP},\n },\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseTransportHeader,\n Offset: 2,\n Len: 2,\n },\n &expr.Lookup{\n SourceRegister: 1,\n SetName: set.Name,\n SetID: set.ID,\n DestRegister: 0,\n IsDestRegSet: true,\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Errorf(\"c.Flush() failed: %v\", err)\n }\n\n rules, err := c.GetRules(\n &nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n },\n &nftables.Chain{\n Name: \"forward\",\n },\n )\n if err != nil {\n t.Fatal(err)\n }\n\n if got, want := len(rules), 1; got != want {\n t.Fatalf(\"unexpected number of rules: got %d, want %d\", got, want)\n }\n if got, want := len(rules[0].Exprs), 4; got != want {\n t.Fatalf(\"unexpected number of exprs: got %d, want %d\", got, want)\n }\n\n lookup, lookupOk := rules[0].Exprs[3].(*expr.Lookup)\n if !lookupOk {\n t.Fatalf(\"Exprs[3] is type %T, want *expr.Lookup\", rules[0].Exprs[3])\n }\n if want := (&expr.Lookup{\n SourceRegister: 1,\n SetName: set.Name,\n DestRegister: 0,\n IsDestRegSet: true,\n }); !reflect.DeepEqual(lookup, want) {\n t.Errorf(\"lookup expr = %+v, wanted %+v\", lookup, want)\n }\n}\n\nfunc TestGetRuleLookupVerdictImmediate(t *testing.T) {\n // Create a new network namespace to test these operations,\n // and tear down the namespace at test completion.\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n // Clear all rules at the beginning + end of the test.\n c.FlushRuleset()\n defer c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n forward := c.AddChain(&nftables.Chain{\n Name: \"forward\",\n Table: filter,\n Type: nftables.ChainTypeFilter,\n Hooknum: nftables.ChainHookForward,\n Priority: nftables.ChainPriorityFilter,\n })\n\n set := &nftables.Set{\n Table: filter,\n Name: \"test\",\n KeyType: nftables.TypeInetService,\n }\n if err := c.AddSet(set, nil); err != nil {\n t.Errorf(\"c.AddSet(portSet) failed: %v\", err)\n }\n if err := c.Flush(); err != nil {\n t.Errorf(\"c.Flush() failed: %v\", err)\n }\n\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: forward,\n Exprs: []expr.Any{\n // [ meta load l4proto => reg 1 ]\n &expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1},\n // [ cmp eq reg 1 0x00000006 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{unix.IPPROTO_TCP},\n },\n // [ payload load 2b @ transport header + 2 => reg 1 ]\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseTransportHeader,\n Offset: 2,\n Len: 2,\n },\n // [ lookup reg 1 set __set%d ]\n &expr.Lookup{\n SourceRegister: 1,\n SetName: set.Name,\n SetID: set.ID,\n },\n // [ immediate reg 0 drop ]\n &expr.Verdict{\n Kind: expr.VerdictAccept,\n },\n // [ immediate reg 2 test ]\n &expr.Immediate{\n Register: 2,\n Data: []byte(\"test\"),\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Errorf(\"c.Flush() failed: %v\", err)\n }\n\n rules, err := c.GetRules(\n &nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n },\n &nftables.Chain{\n Name: \"forward\",\n },\n )\n if err != nil {\n t.Fatal(err)\n }\n\n if got, want := len(rules), 1; got != want {\n t.Fatalf(\"unexpected number of rules: got %d, want %d\", got, want)\n }\n if got, want := len(rules[0].Exprs), 6; got != want {\n t.Fatalf(\"unexpected number of exprs: got %d, want %d\", got, want)\n }\n\n lookup, lookupOk := rules[0].Exprs[3].(*expr.Lookup)\n if !lookupOk {\n t.Fatalf(\"Exprs[3] is type %T, want *expr.Lookup\", rules[0].Exprs[3])\n }\n if want := (&expr.Lookup{\n SourceRegister: 1,\n SetName: set.Name,\n }); !reflect.DeepEqual(lookup, want) {\n t.Errorf(\"lookup expr = %+v, wanted %+v\", lookup, want)\n }\n\n verdict, verdictOk := rules[0].Exprs[4].(*expr.Verdict)\n if !verdictOk {\n t.Fatalf(\"Exprs[4] is type %T, want *expr.Verdict\", rules[0].Exprs[4])\n }\n if want := (&expr.Verdict{\n Kind: expr.VerdictAccept,\n }); !reflect.DeepEqual(verdict, want) {\n t.Errorf(\"verdict expr = %+v, wanted %+v\", verdict, want)\n }\n\n imm, immOk := rules[0].Exprs[5].(*expr.Immediate)\n if !immOk {\n t.Fatalf(\"Exprs[4] is type %T, want *expr.Immediate\", rules[0].Exprs[5])\n }\n if want := (&expr.Immediate{\n Register: 2,\n Data: []byte(\"test\"),\n }); !reflect.DeepEqual(imm, want) {\n t.Errorf(\"verdict expr = %+v, wanted %+v\", imm, want)\n }\n}\n\nfunc TestDynset(t *testing.T) {\n // Create a new network namespace to test these operations,\n // and tear down the namespace at test completion.\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n // Clear all rules at the beginning + end of the test.\n c.FlushRuleset()\n defer c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n forward := c.AddChain(&nftables.Chain{\n Name: \"forward\",\n Table: filter,\n Type: nftables.ChainTypeFilter,\n Hooknum: nftables.ChainHookForward,\n Priority: nftables.ChainPriorityFilter,\n })\n\n set := &nftables.Set{\n Table: filter,\n Name: \"dynamic-set\",\n KeyType: nftables.TypeIPAddr,\n HasTimeout: true,\n Timeout: time.Duration(600 * time.Second),\n }\n if err := c.AddSet(set, nil); err != nil {\n t.Errorf(\"c.AddSet(portSet) failed: %v\", err)\n }\n if err := c.Flush(); err != nil {\n t.Errorf(\"c.Flush() failed: %v\", err)\n }\n\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: forward,\n Exprs: []expr.Any{\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseNetworkHeader,\n Offset: uint32(12),\n Len: uint32(4),\n },\n &expr.Dynset{\n SrcRegKey: 1,\n SetName: set.Name,\n SetID: set.ID,\n Operation: uint32(unix.NFT_DYNSET_OP_UPDATE),\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Errorf(\"c.Flush() failed: %v\", err)\n }\n\n rules, err := c.GetRules(\n &nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n },\n &nftables.Chain{\n Name: \"forward\",\n },\n )\n if err != nil {\n t.Fatal(err)\n }\n\n if got, want := len(rules), 1; got != want {\n t.Fatalf(\"unexpected number of rules: got %d, want %d\", got, want)\n }\n if got, want := len(rules[0].Exprs), 2; got != want {\n t.Fatalf(\"unexpected number of exprs: got %d, want %d\", got, want)\n }\n\n dynset, dynsetOk := rules[0].Exprs[1].(*expr.Dynset)\n if !dynsetOk {\n t.Fatalf(\"Exprs[0] is type %T, want *expr.Dynset\", rules[0].Exprs[1])\n }\n if want := (&expr.Dynset{\n SrcRegKey: 1,\n SetName: set.Name,\n Operation: uint32(unix.NFT_DYNSET_OP_UPDATE),\n }); !reflect.DeepEqual(dynset, want) {\n t.Errorf(\"dynset expr = %+v, wanted %+v\", dynset, want)\n }\n}\n\nfunc TestDynsetWithOneExpression(t *testing.T) {\n // Create a new network namespace to test these operations,\n // and tear down the namespace at test completion.\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n // Clear all rules at the beginning + end of the test.\n c.FlushRuleset()\n defer c.FlushRuleset()\n table := &nftables.Table{\n Name: \"filter\",\n Family: nftables.TableFamilyIPv4,\n }\n chain := &nftables.Chain{\n Name: \"forward\",\n Hooknum: nftables.ChainHookForward,\n Table: table,\n Priority: nftables.ChainPriorityRef(0),\n Type: nftables.ChainTypeFilter,\n }\n set := &nftables.Set{\n Table: table,\n Name: \"myMeter\",\n KeyType: nftables.TypeIPAddr,\n Dynamic: true,\n }\n c.AddTable(table)\n c.AddChain(chain)\n if err := c.AddSet(set, nil); err != nil {\n t.Errorf(\"c.AddSet(myMeter) failed: %v\", err)\n }\n if err := c.Flush(); err != nil {\n t.Errorf(\"c.Flush() failed: %v\", err)\n }\n\n rule := &nftables.Rule{\n Table: table,\n Chain: chain,\n Exprs: []expr.Any{\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseNetworkHeader,\n Offset: uint32(12),\n Len: uint32(4),\n },\n &expr.Dynset{\n SrcRegKey: 1,\n SetName: set.Name,\n Operation: uint32(unix.NFT_DYNSET_OP_ADD),\n Exprs: []expr.Any{\n &expr.Limit{\n Type: expr.LimitTypePkts,\n Rate: 200,\n Unit: expr.LimitTimeSecond,\n Burst: 5,\n },\n },\n },\n &expr.Verdict{\n Kind: expr.VerdictDrop,\n },\n },\n }\n c.AddRule(rule)\n if err := c.Flush(); err != nil {\n t.Errorf(\"c.Flush() failed: %v\", err)\n }\n\n rules, err := c.GetRules(table, chain)\n if err != nil {\n t.Fatal(err)\n }\n\n if got, want := len(rules), 1; got != want {\n t.Fatalf(\"unexpected number of rules: got %d, want %d\", got, want)\n }\n if got, want := len(rules[0].Exprs), 3; got != want {\n t.Fatalf(\"unexpected number of exprs: got %d, want %d\", got, want)\n }\n\n dynset, dynsetOk := rules[0].Exprs[1].(*expr.Dynset)\n if !dynsetOk {\n t.Fatalf(\"Exprs[0] is type %T, want *expr.Dynset\", rules[0].Exprs[1])\n }\n\n if got, want := len(dynset.Exprs), 1; got != want {\n t.Fatalf(\"unexpected number of dynset.Exprs: got %d, want %d\", got, want)\n }\n\n if got, want := dynset.SetName, set.Name; got != want {\n t.Fatalf(\"dynset.SetName is %s, want %s\", got, want)\n }\n\n if want := (&expr.Limit{\n Type: expr.LimitTypePkts,\n Rate: 200,\n Unit: expr.LimitTimeSecond,\n Burst: 5,\n }); !reflect.DeepEqual(dynset.Exprs[0], want) {\n t.Errorf(\"dynset.Exprs[0] expr = %+v, wanted %+v\", dynset.Exprs[0], want)\n }\n}\n\nfunc TestDynsetWithMultipleExpressions(t *testing.T) {\n // Create a new network namespace to test these operations,\n // and tear down the namespace at test completion.\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n // Clear all rules at the beginning + end of the test.\n c.FlushRuleset()\n defer c.FlushRuleset()\n table := &nftables.Table{\n Name: \"filter\",\n Family: nftables.TableFamilyIPv4,\n }\n chain := &nftables.Chain{\n Name: \"forward\",\n Hooknum: nftables.ChainHookForward,\n Table: table,\n Priority: nftables.ChainPriorityRef(0),\n Type: nftables.ChainTypeFilter,\n }\n set := &nftables.Set{\n Table: table,\n Name: \"myMeter\",\n KeyType: nftables.TypeIPAddr,\n Dynamic: true,\n }\n c.AddTable(table)\n c.AddChain(chain)\n if err := c.AddSet(set, nil); err != nil {\n t.Errorf(\"c.AddSet(myMeter) failed: %v\", err)\n }\n if err := c.Flush(); err != nil {\n t.Errorf(\"c.Flush() failed: %v\", err)\n }\n\n rule := &nftables.Rule{\n Table: table,\n Chain: chain,\n Exprs: []expr.Any{\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseNetworkHeader,\n Offset: uint32(12),\n Len: uint32(4),\n },\n &expr.Dynset{\n SrcRegKey: 1,\n SetName: set.Name,\n Operation: uint32(unix.NFT_DYNSET_OP_ADD),\n Exprs: []expr.Any{\n &expr.Connlimit{\n Count: 20,\n Flags: 1,\n },\n &expr.Limit{\n Type: expr.LimitTypePkts,\n Rate: 10,\n Unit: expr.LimitTimeSecond,\n Burst: 2,\n },\n },\n },\n &expr.Verdict{\n Kind: expr.VerdictDrop,\n },\n },\n }\n c.AddRule(rule)\n if err := c.Flush(); err != nil {\n t.Errorf(\"c.Flush() failed: %v\", err)\n }\n\n rules, err := c.GetRules(table, chain)\n if err != nil {\n t.Fatal(err)\n }\n\n if got, want := len(rules), 1; got != want {\n t.Fatalf(\"unexpected number of rules: got %d, want %d\", got, want)\n }\n if got, want := len(rules[0].Exprs), 3; got != want {\n t.Fatalf(\"unexpected number of exprs: got %d, want %d\", got, want)\n }\n\n dynset, dynsetOk := rules[0].Exprs[1].(*expr.Dynset)\n if !dynsetOk {\n t.Fatalf(\"Exprs[0] is type %T, want *expr.Dynset\", rules[0].Exprs[1])\n }\n\n if got, want := len(dynset.Exprs), 2; got != want {\n t.Fatalf(\"unexpected number of dynset.Exprs: got %d, want %d\", got, want)\n }\n\n if got, want := dynset.SetName, set.Name; got != want {\n t.Fatalf(\"dynset.SetName is %s, want %s\", got, want)\n }\n\n if want := (&expr.Connlimit{\n Count: 20,\n Flags: 1,\n }); !reflect.DeepEqual(dynset.Exprs[0], want) {\n t.Errorf(\"dynset.Exprs[0] expr = %+v, wanted %+v\", dynset.Exprs[0], want)\n }\n\n if want := (&expr.Limit{\n Type: expr.LimitTypePkts,\n Rate: 10,\n Unit: expr.LimitTimeSecond,\n Burst: 2,\n }); !reflect.DeepEqual(dynset.Exprs[1], want) {\n t.Errorf(\"dynset.Exprs[1] expr = %+v, wanted %+v\", dynset.Exprs[1], want)\n }\n}\n\nfunc TestConfigureNATRedirect(t *testing.T) {\n // The want byte sequences come from stracing nft(8), e.g.:\n // strace -f -v -x -s 2048 -eraw=sendto nft add table ip nat\n //\n // The nft(8) command sequence was taken from:\n // https://wiki.nftables.org/wiki-nftables/index.php/Performing_Network_Address_Translation_(NAT)\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft flush ruleset\n []byte(\"\\x00\\x00\\x00\\x00\"),\n // nft add table ip nat\n []byte(\"\\x02\\x00\\x00\\x00\\x08\\x00\\x01\\x00\\x6e\\x61\\x74\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain nat prerouting '{' type nat hook prerouting priority 0 \\; '}'\n []byte(\"\\x02\\x00\\x00\\x00\\x08\\x00\\x01\\x00\\x6e\\x61\\x74\\x00\\x0f\\x00\\x03\\x00\\x70\\x72\\x65\\x72\\x6f\\x75\\x74\\x69\\x6e\\x67\\x00\\x00\\x14\\x00\\x04\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x08\\x00\\x07\\x00\\x6e\\x61\\x74\\x00\"),\n // nft add rule nat prerouting tcp dport 22 redirect to 2222\n []byte(\"\\x02\\x00\\x00\\x00\\x08\\x00\\x01\\x00\\x6e\\x61\\x74\\x00\\x0f\\x00\\x02\\x00\\x70\\x72\\x65\\x72\\x6f\\x75\\x74\\x69\\x6e\\x67\\x00\\x00\\xfc\\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\\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\\x06\\x00\\x01\\x00\\x00\\x16\\x00\\x00\\x2c\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x69\\x6d\\x6d\\x65\\x64\\x69\\x61\\x74\\x65\\x00\\x00\\x00\\x18\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x0c\\x00\\x02\\x80\\x06\\x00\\x01\\x00\\x08\\xae\\x00\\x00\\x1c\\x00\\x01\\x80\\x0a\\x00\\x01\\x00\\x72\\x65\\x64\\x69\\x72\\x00\\x00\\x00\\x0c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.FlushRuleset()\n\n nat := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"nat\",\n })\n\n prerouting := c.AddChain(&nftables.Chain{\n Name: \"prerouting\",\n Hooknum: nftables.ChainHookPrerouting,\n Priority: nftables.ChainPriorityFilter,\n Table: nat,\n Type: nftables.ChainTypeNAT,\n })\n\n c.AddRule(&nftables.Rule{\n Table: nat,\n Chain: prerouting,\n Exprs: []expr.Any{\n // [ meta load l4proto => reg 1 ]\n &expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1},\n // [ cmp eq reg 1 0x00000006 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{unix.IPPROTO_TCP},\n },\n\n // [ payload load 2b @ transport header + 2 => reg 1 ]\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseTransportHeader,\n Offset: 2, // TODO\n Len: 2, // TODO\n },\n // [ cmp eq reg 1 0x00001600 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{0x00, 0x16},\n },\n\n // [ immediate reg 1 0x0000ae08 ]\n &expr.Immediate{\n Register: 1,\n Data: binaryutil.BigEndian.PutUint16(2222),\n },\n\n // [ redir proto_min reg 1 ]\n &expr.Redir{\n RegisterProtoMin: 1,\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestConfigureJumpVerdict(t *testing.T) {\n // The want byte sequences come from stracing nft(8), e.g.:\n // strace -f -v -x -s 2048 -eraw=sendto nft add table ip nat\n //\n // The nft(8) command sequence was taken from:\n // https://wiki.nftables.org/wiki-nftables/index.php/Performing_Network_Address_Translation_(NAT)\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft flush ruleset\n []byte(\"\\x00\\x00\\x00\\x00\"),\n // nft add table ip nat\n []byte(\"\\x02\\x00\\x00\\x00\\x08\\x00\\x01\\x00\\x6e\\x61\\x74\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain nat prerouting '{' type nat hook prerouting priority 0 \\; '}'\n []byte(\"\\x02\\x00\\x00\\x00\\x08\\x00\\x01\\x00\\x6e\\x61\\x74\\x00\\x0f\\x00\\x03\\x00\\x70\\x72\\x65\\x72\\x6f\\x75\\x74\\x69\\x6e\\x67\\x00\\x00\\x14\\x00\\x04\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x08\\x00\\x07\\x00\\x6e\\x61\\x74\\x00\"),\n // nft add rule nat prerouting tcp dport 1-65535 jump istio_redirect\n []byte(\"\\x02\\x00\\x00\\x00\\x08\\x00\\x01\\x00\\x6e\\x61\\x74\\x00\\x0f\\x00\\x02\\x00\\x70\\x72\\x65\\x72\\x6f\\x75\\x74\\x69\\x6e\\x67\\x00\\x00\\x24\\x01\\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\\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\\x05\\x0c\\x00\\x03\\x80\\x06\\x00\\x01\\x00\\x00\\x01\\x00\\x00\\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\\x03\\x0c\\x00\\x03\\x80\\x06\\x00\\x01\\x00\\xff\\xff\\x00\\x00\\x44\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x69\\x6d\\x6d\\x65\\x64\\x69\\x61\\x74\\x65\\x00\\x00\\x00\\x30\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x24\\x00\\x02\\x80\\x20\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\xff\\xff\\xff\\xfd\\x13\\x00\\x02\\x00\\x69\\x73\\x74\\x69\\x6f\\x5f\\x72\\x65\\x64\\x69\\x72\\x65\\x63\\x74\\x00\\x00\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.FlushRuleset()\n\n nat := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"nat\",\n })\n\n prerouting := c.AddChain(&nftables.Chain{\n Name: \"prerouting\",\n Hooknum: nftables.ChainHookPrerouting,\n Priority: nftables.ChainPriorityFilter,\n Table: nat,\n Type: nftables.ChainTypeNAT,\n })\n\n c.AddRule(&nftables.Rule{\n Table: nat,\n Chain: prerouting,\n Exprs: []expr.Any{\n // [ meta load l4proto => reg 1 ]\n &expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1},\n // [ cmp eq reg 1 0x00000006 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{unix.IPPROTO_TCP},\n },\n\n // [ payload load 2b @ transport header + 2 => reg 1 ]\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseTransportHeader,\n Offset: 2, // TODO\n Len: 2, // TODO\n },\n // [ cmp gte reg 1 0x00000100 ]\n &expr.Cmp{\n Op: expr.CmpOpGte,\n Register: 1,\n Data: []byte{0x00, 0x01},\n },\n // [ cmp lte reg 1 0x0000ffff ]\n &expr.Cmp{\n Op: expr.CmpOpLte,\n Register: 1,\n Data: []byte{0xff, 0xff},\n },\n\n // [ immediate reg 0 jump -> istio_redirect ]\n &expr.Verdict{\n Kind: expr.VerdictKind(unix.NFT_JUMP),\n Chain: \"istio_redirect\",\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestConfigureReturnVerdict(t *testing.T) {\n // The want byte sequences come from stracing nft(8), e.g.:\n // strace -f -v -x -s 2048 -eraw=sendto nft add table ip nat\n //\n // The nft(8) command sequence was taken from:\n // https://wiki.nftables.org/wiki-nftables/index.php/Performing_Network_Address_Translation_(NAT)\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft flush ruleset\n []byte(\"\\x00\\x00\\x00\\x00\"),\n // nft add table ip nat\n []byte(\"\\x02\\x00\\x00\\x00\\x08\\x00\\x01\\x00\\x6e\\x61\\x74\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain nat prerouting '{' type nat hook prerouting priority 0 \\; '}'\n []byte(\"\\x02\\x00\\x00\\x00\\x08\\x00\\x01\\x00\\x6e\\x61\\x74\\x00\\x0f\\x00\\x03\\x00\\x70\\x72\\x65\\x72\\x6f\\x75\\x74\\x69\\x6e\\x67\\x00\\x00\\x14\\x00\\x04\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x08\\x00\\x07\\x00\\x6e\\x61\\x74\\x00\"),\n // nft add rule nat prerouting meta skgid 1337 return\n []byte(\"\\x02\\x00\\x00\\x00\\x08\\x00\\x01\\x00\\x6e\\x61\\x74\\x00\\x0f\\x00\\x02\\x00\\x70\\x72\\x65\\x72\\x6f\\x75\\x74\\x69\\x6e\\x67\\x00\\x00\\x84\\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\\x0b\\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\\x08\\x00\\x01\\x00\\x39\\x05\\x00\\x00\\x30\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x69\\x6d\\x6d\\x65\\x64\\x69\\x61\\x74\\x65\\x00\\x00\\x00\\x1c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x10\\x00\\x02\\x80\\x0c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\xff\\xff\\xff\\xfb\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.FlushRuleset()\n\n nat := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"nat\",\n })\n\n prerouting := c.AddChain(&nftables.Chain{\n Name: \"prerouting\",\n Hooknum: nftables.ChainHookPrerouting,\n Priority: nftables.ChainPriorityFilter,\n Table: nat,\n Type: nftables.ChainTypeNAT,\n })\n\n c.AddRule(&nftables.Rule{\n Table: nat,\n Chain: prerouting,\n Exprs: []expr.Any{\n // [ meta load skgid => reg 1 ]\n &expr.Meta{Key: expr.MetaKeySKGID, Register: 1},\n // [ cmp eq reg 1 0x00000539 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{0x39, 0x05, 0x00, 0x00},\n },\n\n // [ immediate reg 0 return ]\n &expr.Verdict{\n Kind: expr.VerdictKind(unix.NFT_RETURN),\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestConfigureRangePort(t *testing.T) {\n // The want byte sequences come from stracing nft(8), e.g.:\n // strace -f -v -x -s 2048 -eraw=sendto nft add rule filter forward tcp sport != 2024-2030 return\n //\n // The nft(8) command sequence was taken from:\n // https://wiki.nftables.org/wiki-nftables/index.php/Quick_reference-nftables_in_10_minutes#Tcp\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft flush ruleset\n []byte(\"\\x00\\x00\\x00\\x00\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain filter forward '{' type filter hook forward priority 0 \\; '}'\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0c\\x00\\x03\\x00\\x66\\x6f\\x72\\x77\\x61\\x72\\x64\\x00\\x14\\x00\\x04\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x02\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x0b\\x00\\x07\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\"),\n // nft add rule filter forward tcp sport != 2024-2030 return\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0c\\x00\\x02\\x00\\x66\\x6f\\x72\\x77\\x61\\x72\\x64\\x00\\xf4\\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\\x00\\x08\\x00\\x04\\x00\\x00\\x00\\x00\\x02\\x3c\\x00\\x01\\x80\\x0a\\x00\\x01\\x00\\x72\\x61\\x6e\\x67\\x65\\x00\\x00\\x00\\x2c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x01\\x0c\\x00\\x03\\x80\\x06\\x00\\x01\\x00\\x07\\xe8\\x00\\x00\\x0c\\x00\\x04\\x80\\x06\\x00\\x01\\x00\\x07\\xee\\x00\\x00\\x30\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x69\\x6d\\x6d\\x65\\x64\\x69\\x61\\x74\\x65\\x00\\x00\\x00\\x1c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x10\\x00\\x02\\x80\\x0c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\xff\\xff\\xff\\xfb\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n forward := c.AddChain(&nftables.Chain{\n Name: \"forward\",\n Table: filter,\n Type: nftables.ChainTypeFilter,\n Hooknum: nftables.ChainHookForward,\n Priority: nftables.ChainPriorityFilter,\n })\n\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: forward,\n Exprs: []expr.Any{\n // [ meta load l4proto => reg 1 ]\n &expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1},\n // [ cmp eq reg 1 0x00000006 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{unix.IPPROTO_TCP},\n },\n // [ payload load 2b @ transport header + 0 => reg 1 ]\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseTransportHeader,\n Offset: 0, // TODO\n Len: 2, // TODO\n },\n // [ range neq reg 1 0x0000e807 0x0000ee07 ]\n &expr.Range{\n Op: expr.CmpOpNeq,\n Register: 1,\n FromData: binaryutil.BigEndian.PutUint16(uint16(2024)),\n ToData: binaryutil.BigEndian.PutUint16(uint16(2030)),\n },\n // [ immediate reg 0 return ]\n &expr.Verdict{\n Kind: expr.VerdictKind(unix.NFT_RETURN),\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestConfigureRangeIPv4(t *testing.T) {\n // The want byte sequences come from stracing nft(8), e.g.:\n // strace -f -v -x -s 2048 -eraw=sendto nft add rule filter forward ip saddr != 192.168.1.0-192.168.2.0 return\n //\n // The nft(8) command sequence was taken from:\n // https://wiki.nftables.org/wiki-nftables/index.php/Quick_reference-nftables_in_10_minutes#Tcp\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft flush ruleset\n []byte(\"\\x00\\x00\\x00\\x00\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain filter forward '{' type filter hook forward priority 0 \\; '}'\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0c\\x00\\x03\\x00\\x66\\x6f\\x72\\x77\\x61\\x72\\x64\\x00\\x14\\x00\\x04\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x02\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x0b\\x00\\x07\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\"),\n // nft add rule filter forward ip saddr != 192.168.1.0-192.168.2.0 return\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0c\\x00\\x02\\x00\\x66\\x6f\\x72\\x77\\x61\\x72\\x64\\x00\\xa4\\x00\\x04\\x80\\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\\x01\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x0c\\x08\\x00\\x04\\x00\\x00\\x00\\x00\\x04\\x3c\\x00\\x01\\x80\\x0a\\x00\\x01\\x00\\x72\\x61\\x6e\\x67\\x65\\x00\\x00\\x00\\x2c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x01\\x0c\\x00\\x03\\x80\\x08\\x00\\x01\\x00\\xc0\\xa8\\x01\\x00\\x0c\\x00\\x04\\x80\\x08\\x00\\x01\\x00\\xc0\\xa8\\x02\\x00\\x30\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x69\\x6d\\x6d\\x65\\x64\\x69\\x61\\x74\\x65\\x00\\x00\\x00\\x1c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x10\\x00\\x02\\x80\\x0c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\xff\\xff\\xff\\xfb\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n forward := c.AddChain(&nftables.Chain{\n Name: \"forward\",\n Table: filter,\n Type: nftables.ChainTypeFilter,\n Hooknum: nftables.ChainHookForward,\n Priority: nftables.ChainPriorityFilter,\n })\n\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: forward,\n Exprs: []expr.Any{\n // [ payload load 4b @ network header + 12 => reg 1 ]\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseNetworkHeader,\n Offset: 12, // TODO\n Len: 4, // TODO\n },\n // [ range neq reg 1 0x0000e807 0x0000ee07 ]\n &expr.Range{\n Op: expr.CmpOpNeq,\n Register: 1,\n FromData: net.ParseIP(\"192.168.1.0\").To4(),\n ToData: net.ParseIP(\"192.168.2.0\").To4(),\n },\n // [ immediate reg 0 return ]\n &expr.Verdict{\n Kind: expr.VerdictKind(unix.NFT_RETURN),\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestConfigureRangeIPv6(t *testing.T) {\n // The want byte sequences come from stracing nft(8), e.g.:\n // strace -f -v -x -s 2048 -eraw=sendto nft add rule ip6 filter forward ip6 saddr != 2001:0001::1-2001:0002::1 return\n //\n // The nft(8) command sequence was taken from:\n // https://wiki.nftables.org/wiki-nftables/index.php/Quick_reference-nftables_in_10_minutes#Tcp\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft flush ruleset\n []byte(\"\\x00\\x00\\x00\\x00\"),\n // nft add table ip6 filter\n []byte(\"\\x0a\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain ip6 filter forward '{' type filter hook forward priority 0 \\; '}'\n []byte(\"\\x0a\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0c\\x00\\x03\\x00\\x66\\x6f\\x72\\x77\\x61\\x72\\x64\\x00\\x14\\x00\\x04\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x02\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x0b\\x00\\x07\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\"),\n // nft add rule ip6 filter forward ip6 saddr != 2001:0001::1-2001:0002::1 return\n []byte(\"\\x0a\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0c\\x00\\x02\\x00\\x66\\x6f\\x72\\x77\\x61\\x72\\x64\\x00\\xbc\\x00\\x04\\x80\\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\\x01\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x08\\x08\\x00\\x04\\x00\\x00\\x00\\x00\\x10\\x54\\x00\\x01\\x80\\x0a\\x00\\x01\\x00\\x72\\x61\\x6e\\x67\\x65\\x00\\x00\\x00\\x44\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x01\\x18\\x00\\x03\\x80\\x14\\x00\\x01\\x00\\x20\\x01\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x01\\x18\\x00\\x04\\x80\\x14\\x00\\x01\\x00\\x20\\x01\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x01\\x30\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x69\\x6d\\x6d\\x65\\x64\\x69\\x61\\x74\\x65\\x00\\x00\\x00\\x1c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x10\\x00\\x02\\x80\\x0c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\xff\\xff\\xff\\xfb\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv6,\n Name: \"filter\",\n })\n\n forward := c.AddChain(&nftables.Chain{\n Name: \"forward\",\n Table: filter,\n Type: nftables.ChainTypeFilter,\n Hooknum: nftables.ChainHookForward,\n Priority: nftables.ChainPriorityFilter,\n })\n\n ip1 := net.ParseIP(\"2001:0001::1\").To16()\n ip2 := net.ParseIP(\"2001:0002::1\").To16()\n\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: forward,\n Exprs: []expr.Any{\n // [ payload load 16b @ network header + 8 => reg 1 ]\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseNetworkHeader,\n Offset: 8, // TODO\n Len: 16, // TODO\n },\n // [ range neq reg 1 0x01000120 0x00000000 0x00000000 0x01000000 0x02000120 0x00000000 0x00000000 0x01000000 ]\n &expr.Range{\n Op: expr.CmpOpNeq,\n Register: 1,\n FromData: ip1,\n ToData: ip2,\n },\n // [ immediate reg 0 return ]\n &expr.Verdict{\n Kind: expr.VerdictKind(unix.NFT_RETURN),\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestSet4(t *testing.T) {\n // The want byte sequences come from stracing nft(8), e.g.:\n // strace-4.21 -f -v -x -s 2048 -etrace=sendto nft add table ip nat\n //\n // Until https://github.com/strace/strace/issues/100 is resolved,\n // you need to use strace 4.21 or apply the patch in the issue.\n //\n // Additional details can be obtained by specifying the --debug=all option\n // when calling nft(8).\n want := [][]byte{\n\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n\n // table ip ipv4table {\n // set test-set {\n // type inet_service\n // flags constant\n // elements = { 12000, 12001, 12345, 12346 }\n // }\n //\n // chain ipv4chain-2 {\n // type nat hook prerouting priority dstnat; policy accept;\n // tcp dport @test-set\n // }\n // }\n\n []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\"),\n\n []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\"),\n\n []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\"),\n\n []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\"),\n\n []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\"),\n\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n tbl := &nftables.Table{\n Name: \"ipv4table\",\n Family: nftables.TableFamilyIPv4,\n }\n defPol := nftables.ChainPolicyAccept\n ch := &nftables.Chain{\n Name: \"ipv4chain-2\",\n Table: tbl,\n Type: nftables.ChainTypeNAT,\n Priority: nftables.ChainPriorityNATDest,\n Hooknum: nftables.ChainHookPrerouting,\n Policy: &defPol,\n }\n set := nftables.Set{\n Anonymous: false,\n Constant: true,\n Name: \"test-set\",\n ID: uint32(1), //rand.Intn(0xffff)),\n Table: tbl,\n KeyType: nftables.TypeInetService,\n }\n c.AddTable(tbl)\n c.AddChain(ch)\n\n re := []expr.Any{}\n re = append(re, &expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1})\n re = append(re, &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{unix.IPPROTO_TCP},\n })\n re = append(re, &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseTransportHeader,\n Offset: 2, // Offset for a transport protocol header\n Len: 2, // 2 bytes for port\n })\n re = append(re, &expr.Lookup{\n SourceRegister: 1,\n Invert: false,\n SetID: set.ID,\n SetName: set.Name,\n })\n\n ports := []uint16{12000, 12001, 12345, 12346}\n setElements := make([]nftables.SetElement, len(ports))\n for i := 0; i < len(ports); i++ {\n setElements[i].Key = binaryutil.BigEndian.PutUint16(ports[i])\n }\n\n if err := c.AddSet(&set, setElements); err != nil {\n t.Fatal(err)\n }\n\n c.AddRule(&nftables.Rule{\n Table: tbl,\n Chain: ch,\n Exprs: re,\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestMasq(t *testing.T) {\n tests := []struct {\n name string\n chain *nftables.Chain\n want [][]byte\n masqExprs []expr.Any\n }{\n {\n name: \"Masquerada\",\n chain: &nftables.Chain{\n Name: \"base-chain\",\n },\n want: [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain ip filter base-chain\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x03\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\"),\n // nft add rule ip filter base-chain ip protocol tcp masquerade\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x02\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\x78\\x00\\x04\\x80\\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\\x01\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x09\\x08\\x00\\x04\\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\\x14\\x00\\x01\\x80\\x09\\x00\\x01\\x00\\x6d\\x61\\x73\\x71\\x00\\x00\\x00\\x00\\x04\\x00\\x02\\x80\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n },\n masqExprs: []expr.Any{\n &expr.Masq{},\n },\n },\n {\n name: \"Masquerada with flags\",\n chain: &nftables.Chain{\n Name: \"base-chain\",\n },\n want: [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain ip filter base-chain\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x03\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\"),\n // nft add rule ip filter base-chain ip protocol tcp masquerade random,fully-random,persistent\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x02\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\x80\\x00\\x04\\x80\\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\\x01\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x09\\x08\\x00\\x04\\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\\x1c\\x00\\x01\\x80\\x09\\x00\\x01\\x00\\x6d\\x61\\x73\\x71\\x00\\x00\\x00\\x00\\x0c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x1c\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n },\n masqExprs: []expr.Any{\n &expr.Masq{Random: true, FullyRandom: true, Persistent: true, ToPorts: false},\n },\n },\n {\n name: \"Masquerada with 1 port\",\n chain: &nftables.Chain{\n Name: \"base-chain\",\n },\n want: [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain ip filter base-chain\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x03\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\"),\n // nft add rule ip filter base-chain ip protocol tcp masquerade to :1024\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x02\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\xac\\x00\\x04\\x80\\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\\x01\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x09\\x08\\x00\\x04\\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\\x2c\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x69\\x6d\\x6d\\x65\\x64\\x69\\x61\\x74\\x65\\x00\\x00\\x00\\x18\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x0c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x04\\x00\\x00\\x00\\x1c\\x00\\x01\\x80\\x09\\x00\\x01\\x00\\x6d\\x61\\x73\\x71\\x00\\x00\\x00\\x00\\x0c\\x00\\x02\\x80\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x01\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n },\n masqExprs: []expr.Any{\n &expr.Immediate{Register: 1, Data: binaryutil.BigEndian.PutUint32(uint32(1024) << 16)},\n &expr.Masq{ToPorts: true, RegProtoMin: 1},\n },\n },\n {\n name: \"Masquerada with port range\",\n chain: &nftables.Chain{\n Name: \"base-chain\",\n },\n want: [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain ip filter base-chain\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x03\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\"),\n // nft add rule ip filter base-chain ip protocol tcp masquerade to :1024-2044\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x02\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\xe0\\x00\\x04\\x80\\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\\x01\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x09\\x08\\x00\\x04\\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\\x2c\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x69\\x6d\\x6d\\x65\\x64\\x69\\x61\\x74\\x65\\x00\\x00\\x00\\x18\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x0c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x04\\x00\\x00\\x00\\x2c\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x69\\x6d\\x6d\\x65\\x64\\x69\\x61\\x74\\x65\\x00\\x00\\x00\\x18\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x02\\x0c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x07\\xfc\\x00\\x00\\x24\\x00\\x01\\x80\\x09\\x00\\x01\\x00\\x6d\\x61\\x73\\x71\\x00\\x00\\x00\\x00\\x14\\x00\\x02\\x80\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x02\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n },\n masqExprs: []expr.Any{\n &expr.Immediate{Register: 1, Data: binaryutil.BigEndian.PutUint32(uint32(1024) << 16)},\n &expr.Immediate{Register: 2, Data: binaryutil.BigEndian.PutUint32(uint32(2044) << 16)},\n &expr.Masq{ToPorts: true, RegProtoMin: 1, RegProtoMax: 2},\n },\n },\n }\n\n for _, tt := range tests {\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(tt.want[idx]) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n got := b\n if !bytes.Equal(got, tt.want[idx]) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(tt.want[idx])))\n }\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n tt.chain.Table = filter\n chain := c.AddChain(tt.chain)\n exprs := []expr.Any{\n // [ payload load 1b @ network header + 9 => reg 1 ]\n &expr.Payload{\n DestRegister: 1,\n Base: expr.PayloadBaseNetworkHeader,\n Offset: 9,\n Len: 1,\n },\n // [ cmp eq reg 1 0x00000006 ]\n &expr.Cmp{\n Op: expr.CmpOpEq,\n Register: 1,\n Data: []byte{unix.IPPROTO_TCP},\n },\n }\n exprs = append(exprs, tt.masqExprs...)\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: chain,\n Exprs: exprs,\n })\n if err := c.Flush(); err != nil {\n t.Fatalf(\"Test \\\"%s\\\" failed with error: %+v\", tt.name, err)\n }\n }\n}\n\nfunc TestReject(t *testing.T) {\n tests := []struct {\n name string\n chain *nftables.Chain\n want [][]byte\n rejectExprs []expr.Any\n }{\n {\n name: \"Reject\",\n chain: &nftables.Chain{\n Name: \"base-chain\",\n },\n want: [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain ip filter base-chain\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x03\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\"),\n // nft add rule ip filter base-chain reject\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x02\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\x28\\x00\\x04\\x80\\x24\\x00\\x01\\x80\\x0b\\x00\\x01\\x00\\x72\\x65\\x6a\\x65\\x63\\x74\\x00\\x00\\x14\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x05\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n },\n rejectExprs: []expr.Any{\n &expr.Reject{},\n },\n },\n {\n name: \"Reject with tcp reset\",\n chain: &nftables.Chain{\n Name: \"base-chain\",\n },\n want: [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain ip filter base-chain\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x03\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\"),\n // nft add rule ip filter base-chain reject with tcp reset\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x02\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\x28\\x00\\x04\\x80\\x24\\x00\\x01\\x80\\x0b\\x00\\x01\\x00\\x72\\x65\\x6a\\x65\\x63\\x74\\x00\\x00\\x14\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x05\\x00\\x02\\x00\\x01\\x00\\x00\\x00\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n },\n rejectExprs: []expr.Any{\n &expr.Reject{Type: unix.NFT_REJECT_TCP_RST, Code: unix.NFT_REJECT_TCP_RST},\n },\n },\n {\n name: \"Reject with icmp type host-unreachable\",\n chain: &nftables.Chain{\n Name: \"base-chain\",\n },\n want: [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain ip filter base-chain\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x03\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\"),\n // nft add rule ip filter base-chain reject with icmp type host-unreachable\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x02\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\x28\\x00\\x04\\x80\\x24\\x00\\x01\\x80\\x0b\\x00\\x01\\x00\\x72\\x65\\x6a\\x65\\x63\\x74\\x00\\x00\\x14\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x05\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n },\n rejectExprs: []expr.Any{\n &expr.Reject{Type: unix.NFT_REJECT_ICMP_UNREACH, Code: unix.NFT_REJECT_ICMP_UNREACH},\n },\n },\n }\n\n for _, tt := range tests {\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(tt.want[idx]) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n got := b\n if !bytes.Equal(got, tt.want[idx]) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(tt.want[idx])))\n }\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n tt.chain.Table = filter\n chain := c.AddChain(tt.chain)\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: chain,\n Exprs: tt.rejectExprs,\n })\n if err := c.Flush(); err != nil {\n t.Fatalf(\"Test \\\"%s\\\" failed with error: %+v\", tt.name, err)\n }\n }\n}\n\nfunc TestFib(t *testing.T) {\n tests := []struct {\n name string\n chain *nftables.Chain\n want [][]byte\n fibExprs []expr.Any\n }{\n {\n name: \"fib saddr type local\",\n chain: &nftables.Chain{\n Name: \"base-chain\",\n },\n want: [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain ip filter base-chain\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x03\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\"),\n // nft add rule ip filter base-chain fib saddr type local\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x02\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\x2c\\x00\\x04\\x80\\x28\\x00\\x01\\x80\\x08\\x00\\x01\\x00\\x66\\x69\\x62\\x00\\x1c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x03\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n },\n fibExprs: []expr.Any{\n &expr.Fib{\n Register: 1,\n FlagSADDR: true,\n ResultADDRTYPE: true,\n },\n },\n },\n {\n name: \"fib daddr type broadcast\",\n chain: &nftables.Chain{\n Name: \"base-chain\",\n },\n want: [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain ip filter base-chain\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x03\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\"),\n // nft add rule ip filter base-chain fib daddr type broadcast\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x02\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\x2c\\x00\\x04\\x80\\x28\\x00\\x01\\x80\\x08\\x00\\x01\\x00\\x66\\x69\\x62\\x00\\x1c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x02\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x03\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n },\n fibExprs: []expr.Any{\n &expr.Fib{\n Register: 1,\n FlagDADDR: true,\n ResultADDRTYPE: true,\n },\n },\n },\n {\n name: \"fib saddr . iif oif missing\",\n chain: &nftables.Chain{\n Name: \"base-chain\",\n },\n want: [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain ip filter base-chain\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x03\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\"),\n // nft add rule ip filter base-chain fib saddr . iif oif missing\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x02\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\x2c\\x00\\x04\\x80\\x28\\x00\\x01\\x80\\x08\\x00\\x01\\x00\\x66\\x69\\x62\\x00\\x1c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x09\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x01\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n },\n fibExprs: []expr.Any{\n &expr.Fib{\n Register: 1,\n FlagSADDR: true,\n FlagIIF: true,\n ResultOIF: true,\n },\n },\n },\n }\n\n for _, tt := range tests {\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(tt.want[idx]) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n got := b\n if !bytes.Equal(got, tt.want[idx]) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(tt.want[idx])))\n }\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n tt.chain.Table = filter\n chain := c.AddChain(tt.chain)\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: chain,\n Exprs: tt.fibExprs,\n })\n if err := c.Flush(); err != nil {\n t.Fatalf(\"Test \\\"%s\\\" failed with error: %+v\", tt.name, err)\n }\n }\n}\n\nfunc TestNumgen(t *testing.T) {\n tests := []struct {\n name string\n chain *nftables.Chain\n want [][]byte\n numgenExprs []expr.Any\n }{\n {\n name: \"numgen random\",\n chain: &nftables.Chain{\n Name: \"base-chain\",\n },\n want: [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain ip filter base-chain\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x03\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\"),\n // nft add rule ip filter base-chain numgen random mod 1 offset 0 vmap { 0 : drop }\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x02\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\x38\\x00\\x04\\x80\\x34\\x00\\x01\\x80\\x0b\\x00\\x01\\x00\\x6e\\x75\\x6d\\x67\\x65\\x6e\\x00\\x00\\x24\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x04\\x00\\x00\\x00\\x00\\x00\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n },\n numgenExprs: []expr.Any{\n &expr.Numgen{\n Register: 1,\n Type: unix.NFT_NG_RANDOM,\n Modulus: 0x1,\n Offset: 0,\n },\n },\n },\n {\n name: \"numgen incremental\",\n chain: &nftables.Chain{\n Name: \"base-chain\",\n },\n want: [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain ip filter base-chain\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x03\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\"),\n // nft add rule ip filter base-chain numgen inc mod 1 offset 0 vmap { 0 : drop }\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x02\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\x38\\x00\\x04\\x80\\x34\\x00\\x01\\x80\\x0b\\x00\\x01\\x00\\x6e\\x75\\x6d\\x67\\x65\\x6e\\x00\\x00\\x24\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x00\\x08\\x00\\x04\\x00\\x00\\x00\\x00\\x00\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n },\n numgenExprs: []expr.Any{\n &expr.Numgen{\n Register: 1,\n Type: unix.NFT_NG_INCREMENTAL,\n Modulus: 0x1,\n Offset: 0,\n },\n },\n },\n }\n\n for _, tt := range tests {\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(tt.want[idx]) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n got := b\n if !bytes.Equal(got, tt.want[idx]) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(tt.want[idx])))\n }\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n tt.chain.Table = filter\n chain := c.AddChain(tt.chain)\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: chain,\n Exprs: tt.numgenExprs,\n })\n if err := c.Flush(); err != nil {\n t.Fatalf(\"Test \\\"%s\\\" failed with error: %+v\", tt.name, err)\n }\n }\n}\n\nfunc TestMap(t *testing.T) {\n tests := []struct {\n name string\n chain *nftables.Chain\n want [][]byte\n set nftables.Set\n element []nftables.SetElement\n }{\n {\n name: \"map inet_service: inet_service 1 element\",\n chain: &nftables.Chain{\n Name: \"base-chain\",\n },\n want: [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain ip filter base-chain\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x03\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\"),\n // nft add map ip filter test-map { type inet_service: inet_service\\; elements={ 22: 1024 } \\; }\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0d\\x00\\x02\\x00\\x74\\x65\\x73\\x74\\x2d\\x6d\\x61\\x70\\x00\\x00\\x00\\x00\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x08\\x08\\x00\\x04\\x00\\x00\\x00\\x00\\x0d\\x08\\x00\\x05\\x00\\x00\\x00\\x00\\x02\\x08\\x00\\x0a\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x06\\x00\\x00\\x00\\x00\\x0d\\x08\\x00\\x07\\x00\\x00\\x00\\x00\\x02\"),\n []byte(\"\\x02\\x00\\x00\\x00\\x0d\\x00\\x02\\x00\\x74\\x65\\x73\\x74\\x2d\\x6d\\x61\\x70\\x00\\x00\\x00\\x00\\x08\\x00\\x04\\x00\\x00\\x00\\x00\\x01\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x20\\x00\\x03\\x80\\x1c\\x00\\x01\\x80\\x0c\\x00\\x01\\x80\\x06\\x00\\x01\\x00\\x00\\x16\\x00\\x00\\x0c\\x00\\x02\\x80\\x06\\x00\\x01\\x00\\x04\\x00\\x00\\x00\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n },\n set: nftables.Set{\n Name: \"test-map\",\n ID: uint32(1),\n KeyType: nftables.TypeInetService,\n DataType: nftables.TypeInetService,\n IsMap: true,\n },\n element: []nftables.SetElement{\n {\n Key: binaryutil.BigEndian.PutUint16(uint16(22)),\n Val: binaryutil.BigEndian.PutUint16(uint16(1024)),\n },\n },\n },\n }\n\n for _, tt := range tests {\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(tt.want[idx]) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n got := b\n if !bytes.Equal(got, tt.want[idx]) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(tt.want[idx])))\n }\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n tt.chain.Table = filter\n c.AddChain(tt.chain)\n tt.set.Table = filter\n c.AddSet(&tt.set, tt.element)\n if err := c.Flush(); err != nil {\n t.Fatalf(\"Test \\\"%s\\\" failed with error: %+v\", tt.name, err)\n }\n }\n}\n\nfunc TestVmap(t *testing.T) {\n tests := []struct {\n name string\n chain *nftables.Chain\n want [][]byte\n set nftables.Set\n element []nftables.SetElement\n }{\n {\n name: \"map inet_service: drop verdict\",\n chain: &nftables.Chain{\n Name: \"base-chain\",\n },\n want: [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain ip filter base-chain\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x03\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\"),\n // nft add map ip filter test-vmap { type inet_service: verdict\\; elements={ 22: drop } \\; }\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0e\\x00\\x02\\x00\\x74\\x65\\x73\\x74\\x2d\\x76\\x6d\\x61\\x70\\x00\\x00\\x00\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x08\\x08\\x00\\x04\\x00\\x00\\x00\\x00\\x0d\\x08\\x00\\x05\\x00\\x00\\x00\\x00\\x02\\x08\\x00\\x0a\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x06\\x00\\xff\\xff\\xff\\x00\\x08\\x00\\x07\\x00\\x00\\x00\\x00\\x00\"),\n []byte(\"\\x02\\x00\\x00\\x00\\x0e\\x00\\x02\\x00\\x74\\x65\\x73\\x74\\x2d\\x76\\x6d\\x61\\x70\\x00\\x00\\x00\\x08\\x00\\x04\\x00\\x00\\x00\\x00\\x01\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x24\\x00\\x03\\x80\\x20\\x00\\x01\\x80\\x0c\\x00\\x01\\x80\\x06\\x00\\x01\\x00\\x00\\x16\\x00\\x00\\x10\\x00\\x02\\x80\\x0c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n },\n set: nftables.Set{\n Name: \"test-vmap\",\n ID: uint32(1),\n KeyType: nftables.TypeInetService,\n DataType: nftables.TypeVerdict,\n IsMap: true,\n },\n element: []nftables.SetElement{\n {\n Key: binaryutil.BigEndian.PutUint16(uint16(22)),\n VerdictData: &expr.Verdict{\n Kind: expr.VerdictDrop,\n },\n },\n },\n }, {\n name: \"map inet_service: jump to chain verdict\",\n chain: &nftables.Chain{\n Name: \"base-chain\",\n },\n want: [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain ip filter base-chain\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x03\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\"),\n // nft add map ip filter test-vmap { type inet_service: verdict\\; elements={ 22: jump fake-chain } \\; }\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0e\\x00\\x02\\x00\\x74\\x65\\x73\\x74\\x2d\\x76\\x6d\\x61\\x70\\x00\\x00\\x00\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x08\\x08\\x00\\x04\\x00\\x00\\x00\\x00\\x0d\\x08\\x00\\x05\\x00\\x00\\x00\\x00\\x02\\x08\\x00\\x0a\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x06\\x00\\xff\\xff\\xff\\x00\\x08\\x00\\x07\\x00\\x00\\x00\\x00\\x00\"),\n []byte(\"\\x02\\x00\\x00\\x00\\x0e\\x00\\x02\\x00\\x74\\x65\\x73\\x74\\x2d\\x76\\x6d\\x61\\x70\\x00\\x00\\x00\\x08\\x00\\x04\\x00\\x00\\x00\\x00\\x01\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x34\\x00\\x03\\x80\\x30\\x00\\x01\\x80\\x0c\\x00\\x01\\x80\\x06\\x00\\x01\\x00\\x00\\x16\\x00\\x00\\x20\\x00\\x02\\x80\\x1c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\xff\\xff\\xff\\xfd\\x0f\\x00\\x02\\x00\\x66\\x61\\x6b\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n },\n set: nftables.Set{\n Name: \"test-vmap\",\n ID: uint32(1),\n KeyType: nftables.TypeInetService,\n DataType: nftables.TypeVerdict,\n IsMap: true,\n },\n element: []nftables.SetElement{\n {\n Key: binaryutil.BigEndian.PutUint16(uint16(22)),\n VerdictData: &expr.Verdict{\n Kind: unix.NFT_JUMP,\n Chain: \"fake-chain\",\n },\n },\n },\n },\n }\n\n for _, tt := range tests {\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(tt.want[idx]) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n got := b\n if !bytes.Equal(got, tt.want[idx]) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(tt.want[idx])))\n }\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n tt.chain.Table = filter\n c.AddChain(tt.chain)\n tt.set.Table = filter\n c.AddSet(&tt.set, tt.element)\n if err := c.Flush(); err != nil {\n t.Fatalf(\"Test \\\"%s\\\" failed with error: %+v\", tt.name, err)\n }\n }\n}\n\nfunc TestJHash(t *testing.T) {\n // The want byte sequences come from stracing nft(8), e.g.:\n // strace -f -v -x -s 2048 -eraw=sendto nft add rule filter prerouting mark set jhash ip saddr mod 2\n //\n // The nft(8) command sequence was taken from:\n // https://wiki.nftables.org/wiki-nftables/index.php/Quick_reference-nftables_in_10_minutes#Tcp\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft flush ruleset\n []byte(\"\\x00\\x00\\x00\\x00\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain ip filter base-chain { type filter hook prerouting priority 0 \\; }\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x03\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\x14\\x00\\x04\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x0b\\x00\\x07\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\"),\n // nft add rule filter base_chain mark set jhash ip saddr mod 2 seed 0xfeedcafe offset 1\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x02\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\xa8\\x00\\x04\\x80\\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\\x02\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x0c\\x08\\x00\\x04\\x00\\x00\\x00\\x00\\x04\\x4c\\x00\\x01\\x80\\x09\\x00\\x01\\x00\\x68\\x61\\x73\\x68\\x00\\x00\\x00\\x00\\x3c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x02\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x04\\x08\\x00\\x04\\x00\\x00\\x00\\x00\\x02\\x08\\x00\\x05\\x00\\xfe\\xed\\xca\\xfe\\x08\\x00\\x06\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x07\\x00\\x00\\x00\\x00\\x00\\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\\x03\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x01\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n forward := c.AddChain(&nftables.Chain{\n Name: \"base-chain\",\n Table: filter,\n Type: nftables.ChainTypeFilter,\n Hooknum: nftables.ChainHookPrerouting,\n Priority: nftables.ChainPriorityFilter,\n })\n\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: forward,\n Exprs: []expr.Any{\n // [ payload load 4b @ network header + 12 => reg 2 ]\n &expr.Payload{\n DestRegister: 2,\n Base: expr.PayloadBaseNetworkHeader,\n Offset: 12,\n Len: 4,\n },\n // [ hash reg 1 = jhash(reg 2, 4, 0xfeedcafe) % mod 2 offset 1 ]\n &expr.Hash{\n SourceRegister: 2,\n DestRegister: 1,\n Length: 4,\n Modulus: 2,\n Seed: 4276996862,\n Offset: 1,\n Type: expr.HashTypeJenkins,\n },\n // [ meta set mark with reg 1 ]\n &expr.Meta{\n Key: expr.MetaKeyMARK,\n SourceRegister: true,\n Register: 1,\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestDup(t *testing.T) {\n\n // The want byte sequences come from stracing nft(8), e.g.:\n // strace -f -v -x -s 2048 -eraw=sendto nft add rule filter prerouting mark set jhash ip saddr mod 2\n //\n // The nft(8) command sequence was taken from:\n // https://wiki.nftables.org/wiki-nftables/index.php/Quick_reference-nftables_in_10_minutes#Tcp\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n\n // nft flush ruleset\n []byte(\"\\x00\\x00\\x00\\x00\"),\n\n // nft add table ip mangle\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x6d\\x61\\x6e\\x67\\x6c\\x65\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n\n // nft add chain ip mangle base-chain { type filter hook prerouting priority 0 \\; }\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x6d\\x61\\x6e\\x67\\x6c\\x65\\x00\\x00\\x0f\\x00\\x03\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\x14\\x00\\x04\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x0b\\x00\\x07\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\"),\n\n // nft add rule mangle base-chain dup to 127.0.0.50 device lo\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x6d\\x61\\x6e\\x67\\x6c\\x65\\x00\\x00\\x0f\\x00\\x02\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\x7c\\x00\\x04\\x80\\x2c\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x69\\x6d\\x6d\\x65\\x64\\x69\\x61\\x74\\x65\\x00\\x00\\x00\\x18\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x0c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x7f\\x00\\x00\\x32\\x2c\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x69\\x6d\\x6d\\x65\\x64\\x69\\x61\\x74\\x65\\x00\\x00\\x00\\x18\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x02\\x0c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x01\\x00\\x00\\x00\\x20\\x00\\x01\\x80\\x08\\x00\\x01\\x00\\x64\\x75\\x70\\x00\\x14\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x02\"),\n\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.FlushRuleset()\n\n mangle := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"mangle\",\n })\n\n prerouting := c.AddChain(&nftables.Chain{\n Name: \"base-chain\",\n Table: mangle,\n Type: nftables.ChainTypeFilter,\n Hooknum: nftables.ChainHookPrerouting,\n Priority: nftables.ChainPriorityFilter,\n })\n\n lo, err := net.InterfaceByName(\"lo\")\n\n if err != nil {\n t.Fatal(err)\n }\n\n c.AddRule(&nftables.Rule{\n Table: mangle,\n Chain: prerouting,\n Exprs: []expr.Any{\n // [ immediate reg 1 0x3200007f ]\n &expr.Immediate{\n Register: 1,\n Data: net.ParseIP(\"127.0.0.50\").To4(),\n },\n // [ immediate reg 2 0x00000001 ]\n &expr.Immediate{\n Register: 2,\n Data: binaryutil.NativeEndian.PutUint32(uint32(lo.Index)),\n },\n // [ dup sreg_addr 1 sreg_dev 2 ]\n &expr.Dup{\n RegAddr: 1,\n RegDev: 2,\n IsRegDevSet: true,\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestDupWoDev(t *testing.T) {\n\n // The want byte sequences come from stracing nft(8), e.g.:\n // strace -f -v -x -s 2048 -eraw=sendto nft add rule filter prerouting mark set jhash ip saddr mod 2\n //\n // The nft(8) command sequence was taken from:\n // https://wiki.nftables.org/wiki-nftables/index.php/Quick_reference-nftables_in_10_minutes#Tcp\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n\n // nft flush ruleset\n []byte(\"\\x00\\x00\\x00\\x00\"),\n\n // nft add table ip mangle\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x6d\\x61\\x6e\\x67\\x6c\\x65\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n\n // nft add chain ip mangle base-chain { type filter hook prerouting priority 0 \\; }\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x6d\\x61\\x6e\\x67\\x6c\\x65\\x00\\x00\\x0f\\x00\\x03\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\x14\\x00\\x04\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x0b\\x00\\x07\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\"),\n\n // nft add rule mangle base-chain dup to 127.0.0.50\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x6d\\x61\\x6e\\x67\\x6c\\x65\\x00\\x00\\x0f\\x00\\x02\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\x48\\x00\\x04\\x80\\x2c\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x69\\x6d\\x6d\\x65\\x64\\x69\\x61\\x74\\x65\\x00\\x00\\x00\\x18\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x0c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x7f\\x00\\x00\\x32\\x18\\x00\\x01\\x80\\x08\\x00\\x01\\x00\\x64\\x75\\x70\\x00\\x0c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\"),\n\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.FlushRuleset()\n\n mangle := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"mangle\",\n })\n\n prerouting := c.AddChain(&nftables.Chain{\n Name: \"base-chain\",\n Table: mangle,\n Type: nftables.ChainTypeFilter,\n Hooknum: nftables.ChainHookPrerouting,\n Priority: nftables.ChainPriorityFilter,\n })\n\n c.AddRule(&nftables.Rule{\n Table: mangle,\n Chain: prerouting,\n Exprs: []expr.Any{\n // [ immediate reg 1 0x3200007f ]\n &expr.Immediate{\n Register: 1,\n Data: net.ParseIP(\"127.0.0.50\").To4(),\n },\n // [ dup sreg_addr 1 sreg_dev 2 ]\n &expr.Dup{\n RegAddr: 1,\n IsRegDevSet: false,\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestNotrack(t *testing.T) {\n // The want byte sequences come from stracing nft(8), e.g.:\n // strace -f -v -x -s 2048 -eraw=sendto nft add rule filter prerouting mark set jhash ip saddr mod 2\n //\n // The nft(8) command sequence was taken from:\n // https://wiki.nftables.org/wiki-nftables/index.php/Quick_reference-nftables_in_10_minutes#Tcp\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft flush ruleset\n []byte(\"\\x00\\x00\\x00\\x00\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain ip filter base-chain { type filter hook prerouting priority 0 \\; }\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x03\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\x14\\x00\\x04\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x0b\\x00\\x07\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\"),\n // nft add rule filter base_chain notrack\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x02\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\x14\\x00\\x04\\x80\\x10\\x00\\x01\\x80\\x0c\\x00\\x01\\x00\\x6e\\x6f\\x74\\x72\\x61\\x63\\x6b\\x00\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n nftest.MatchRulesetBytes(t,\n func(c *nftables.Conn) {\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n prerouting := c.AddChain(&nftables.Chain{\n Name: \"base-chain\",\n Table: filter,\n Type: nftables.ChainTypeFilter,\n Hooknum: nftables.ChainHookPrerouting,\n Priority: nftables.ChainPriorityFilter,\n })\n\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: prerouting,\n Exprs: []expr.Any{\n // [ notrack ]\n &expr.Notrack{},\n },\n })\n },\n want)\n}\n\nfunc TestQuota(t *testing.T) {\n\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft flush ruleset\n []byte(\"\\x00\\x00\\x00\\x00\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain ip filter regular-chain\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x12\\x00\\x03\\x00\\x72\\x65\\x67\\x75\\x6c\\x61\\x72\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\x00\"),\n // nft add rule ip filter regular-chain quota over 6 bytes\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x12\\x00\\x02\\x00\\x72\\x65\\x67\\x75\\x6c\\x61\\x72\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\x00\\x38\\x00\\x04\\x80\\x34\\x00\\x01\\x80\\x0a\\x00\\x01\\x00\\x71\\x75\\x6f\\x74\\x61\\x00\\x00\\x00\\x24\\x00\\x02\\x80\\x0c\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x06\\x0c\\x00\\x04\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x01\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want[idx]) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n got := b\n if !bytes.Equal(got, want[idx]) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want[idx])))\n }\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n output := c.AddChain(&nftables.Chain{\n Name: \"regular-chain\",\n Table: filter,\n })\n\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: output,\n Exprs: []expr.Any{\n // [ quota bytes 6 consumed 0 flags 1 ]\n &expr.Quota{\n Bytes: 6,\n Consumed: 0,\n Over: true,\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestStatelessNAT(t *testing.T) {\n // The want byte sequences come from stracing nft(8), e.g.:\n // strace -f -v -x -s 2048 -eraw=sendto nft add rule filter prerouting mark set jhash ip saddr mod 2\n //\n // The nft(8) command sequence was taken from:\n // https://wiki.nftables.org/wiki-nftables/index.php/Quick_reference-nftables_in_10_minutes#Tcp\n want := [][]byte{\n // batch begin\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n // nft flush ruleset\n []byte(\"\\x00\\x00\\x00\\x00\"),\n // nft add table ip filter\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\"),\n // nft add chain ip filter base-chain { type filter hook prerouting priority 0 \\; }\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x03\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\x14\\x00\\x04\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x0b\\x00\\x07\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\"),\n // nft add rule ip filter base-chain ip daddr set 192.168.1.1 notrack\n []byte(\"\\x02\\x00\\x00\\x00\\x0b\\x00\\x01\\x00\\x66\\x69\\x6c\\x74\\x65\\x72\\x00\\x00\\x0f\\x00\\x02\\x00\\x62\\x61\\x73\\x65\\x2d\\x63\\x68\\x61\\x69\\x6e\\x00\\x00\\x8c\\x00\\x04\\x80\\x2c\\x00\\x01\\x80\\x0e\\x00\\x01\\x00\\x69\\x6d\\x6d\\x65\\x64\\x69\\x61\\x74\\x65\\x00\\x00\\x00\\x18\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\x00\\x00\\x00\\x01\\x0c\\x00\\x02\\x80\\x08\\x00\\x01\\x00\\xc0\\xa8\\x01\\x01\\x4c\\x00\\x01\\x80\\x0c\\x00\\x01\\x00\\x70\\x61\\x79\\x6c\\x6f\\x61\\x64\\x00\\x3c\\x00\\x02\\x80\\x08\\x00\\x05\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x02\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x03\\x00\\x00\\x00\\x00\\x10\\x08\\x00\\x04\\x00\\x00\\x00\\x00\\x04\\x08\\x00\\x06\\x00\\x00\\x00\\x00\\x01\\x08\\x00\\x07\\x00\\x00\\x00\\x00\\x0a\\x08\\x00\\x08\\x00\\x00\\x00\\x00\\x01\\x10\\x00\\x01\\x80\\x0c\\x00\\x01\\x00\\x6e\\x6f\\x74\\x72\\x61\\x63\\x6b\\x00\"),\n // batch end\n []byte(\"\\x00\\x00\\x00\\x0a\"),\n }\n\n c, err := nftables.New(nftables.WithTestDial(\n func(req []netlink.Message) ([]netlink.Message, error) {\n for idx, msg := range req {\n b, err := msg.MarshalBinary()\n if err != nil {\n t.Fatal(err)\n }\n if len(b) < 16 {\n continue\n }\n b = b[16:]\n if len(want) == 0 {\n t.Errorf(\"no want entry for message %d: %x\", idx, b)\n continue\n }\n if got, want := b, want[0]; !bytes.Equal(got, want) {\n t.Errorf(\"message %d: %s\", idx, linediff(nfdump(got), nfdump(want)))\n }\n want = want[1:]\n }\n return req, nil\n }))\n if err != nil {\n t.Fatal(err)\n }\n\n c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n forward := c.AddChain(&nftables.Chain{\n Name: \"base-chain\",\n Table: filter,\n Type: nftables.ChainTypeFilter,\n Hooknum: nftables.ChainHookPrerouting,\n Priority: nftables.ChainPriorityFilter,\n })\n\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: forward,\n Exprs: []expr.Any{\n &expr.Immediate{\n Register: 1,\n Data: net.ParseIP(\"192.168.1.1\").To4(),\n },\n // [ payload write reg 1 => 4b @ network header + 16 csum_type 1 csum_off 10 csum_flags 0x1 ]\n &expr.Payload{\n OperationType: expr.PayloadWrite,\n SourceRegister: 1,\n Base: expr.PayloadBaseNetworkHeader,\n Offset: 16,\n Len: 4,\n CsumType: expr.CsumTypeInet,\n CsumOffset: 10,\n CsumFlags: unix.NFT_PAYLOAD_L4CSUM_PSEUDOHDR,\n },\n // [ notrack ]\n &expr.Notrack{},\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Fatal(err)\n }\n}\n\nfunc TestGetRulesObjref(t *testing.T) {\n // Create a new network namespace to test these operations,\n // and tear down the namespace at test completion.\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n // Clear all rules at the beginning + end of the test.\n c.FlushRuleset()\n defer c.FlushRuleset()\n\n table := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n chain := c.AddChain(&nftables.Chain{\n Name: \"forward\",\n Table: table,\n Type: nftables.ChainTypeFilter,\n Hooknum: nftables.ChainHookForward,\n Priority: nftables.ChainPriorityFilter,\n })\n\n counterName := \"fwded1\"\n c.AddObj(&nftables.CounterObj{\n Table: table,\n Name: counterName,\n Bytes: 1,\n Packets: 1,\n })\n\n counterRule := c.AddRule(&nftables.Rule{\n Table: table,\n Chain: chain,\n Exprs: []expr.Any{\n &expr.Objref{\n Type: 1,\n Name: counterName,\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Errorf(\"c.Flush() failed: %v\", err)\n }\n\n rules, err := c.GetRules(table, chain)\n if err != nil {\n t.Fatal(err)\n }\n\n if got, want := len(rules), 1; got != want {\n t.Fatalf(\"unexpected number of rules: got %d, want %d\", got, want)\n }\n if got, want := len(rules[0].Exprs), 1; got != want {\n t.Fatalf(\"unexpected number of exprs: got %d, want %d\", got, want)\n }\n objref, objrefOk := rules[0].Exprs[0].(*expr.Objref)\n if !objrefOk {\n t.Fatalf(\"Exprs[0] is type %T, want *expr.Objref\", rules[0].Exprs[0])\n }\n if want := counterRule.Exprs[0]; !reflect.DeepEqual(objref, want) {\n t.Errorf(\"objref expr = %+v, wanted %+v\", objref, want)\n }\n}\n\nfunc TestGetRulesQueue(t *testing.T) {\n // Create a new network namespace to test these operations,\n // and tear down the namespace at test completion.\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n // Clear all rules at the beginning + end of the test.\n c.FlushRuleset()\n defer c.FlushRuleset()\n\n table := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n chain := c.AddChain(&nftables.Chain{\n Name: \"forward\",\n Table: table,\n Type: nftables.ChainTypeFilter,\n Hooknum: nftables.ChainHookForward,\n Priority: nftables.ChainPriorityFilter,\n })\n\n queueRule := c.AddRule(&nftables.Rule{\n Table: table,\n Chain: chain,\n Exprs: []expr.Any{\n &expr.Queue{\n Num: 1000,\n Flag: expr.QueueFlagBypass,\n },\n },\n })\n\n if err := c.Flush(); err != nil {\n t.Errorf(\"c.Flush() failed: %v\", err)\n }\n\n rules, err := c.GetRules(table, chain)\n if err != nil {\n t.Fatal(err)\n }\n\n if got, want := len(rules), 1; got != want {\n t.Fatalf(\"unexpected number of rules: got %d, want %d\", got, want)\n }\n if got, want := len(rules[0].Exprs), 1; got != want {\n t.Fatalf(\"unexpected number of exprs: got %d, want %d\", got, want)\n }\n queueExpr, ok := rules[0].Exprs[0].(*expr.Queue)\n if !ok {\n t.Fatalf(\"Exprs[0] is type %T, want *expr.Queue\", rules[0].Exprs[0])\n }\n if want := queueRule.Exprs[0]; !reflect.DeepEqual(queueExpr, want) {\n t.Errorf(\"queue expr = %+v, wanted %+v\", queueExpr, want)\n }\n}\n\nfunc TestNftablesCompat(t *testing.T) {\n // Create a new network namespace to test these operations,\n // and tear down the namespace at test completion.\n c, newNS := openSystemNFTConn(t)\n defer cleanupSystemNFTConn(t, newNS)\n // Clear all rules at the beginning + end of the test.\n c.FlushRuleset()\n defer c.FlushRuleset()\n\n filter := c.AddTable(&nftables.Table{\n Family: nftables.TableFamilyIPv4,\n Name: \"filter\",\n })\n\n input := c.AddChain(&nftables.Chain{\n Name: \"input\",\n Table: filter,\n Type: nftables.ChainTypeFilter,\n Hooknum: nftables.ChainHookInput,\n Priority: nftables.ChainPriorityFilter,\n })\n\n // -tcp --dport 0:65534 --sport 0:65534\n tcpMatch := &expr.Match{\n Name: \"tcp\",\n Info: &xt.Tcp{\n SrcPorts: [2]uint16{0, 65534},\n DstPorts: [2]uint16{0, 65534},\n },\n }\n\n // -udp --dport 0:65534 --sport 0:65534\n udpMatch := &expr.Match{\n Name: \"udp\",\n Info: &xt.Udp{\n SrcPorts: [2]uint16{0, 65534},\n DstPorts: [2]uint16{0, 65534},\n },\n }\n\n // - j TCPMSS --set-mss 1460\n mess := xt.Unknown([]byte{1460 & 0xff, (1460 >> 8) & 0xff})\n tcpMessTarget := &expr.Target{\n Name: \"TCPMSS\",\n Info: &mess,\n }\n\n // -m state --state ESTABLISHED\n ctMatch := &expr.Match{\n Name: \"conntrack\",\n Rev: 1,\n Info: &xt.ConntrackMtinfo1{\n ConntrackMtinfoBase: xt.ConntrackMtinfoBase{\n MatchFlags: 0x2001,\n },\n StateMask: 0x02,\n },\n }\n\n // -p tcp --dport --dport 0:65534 --sport 0:65534 -m state --state ESTABLISHED -j TCPMSS --set-mss 1460\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: input,\n Exprs: []expr.Any{\n tcpMatch,\n ctMatch,\n tcpMessTarget,\n },\n })\n if err := c.Flush(); err != nil {\n t.Fatalf(\"add rule fail %#v\", err)\n }\n\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: input,\n Exprs: []expr.Any{\n udpMatch,\n &expr.Verdict{\n Kind: expr.VerdictAccept,\n },\n },\n })\n if err := c.Flush(); err != nil {\n t.Fatalf(\"add rule %#v fail\", err)\n }\n\n // -m state --state ESTABLISHED -j ACCEPT\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: input,\n Exprs: []expr.Any{\n ctMatch,\n &expr.Verdict{\n Kind: expr.VerdictAccept,\n },\n },\n })\n if err := c.Flush(); err != nil {\n t.Fatalf(\"add rule %#v fail\", err)\n }\n\n // -p udp --dport --dport 0:65534 --sport 0:65534 -m state --state ESTABLISHED -j ACCEPT\n c.AddRule(&nftables.Rule{\n Table: filter,\n Chain: input,\n Exprs: []expr.Any{\n tcpMatch,\n udpMatch,\n ctMatch,\n &expr.Verdict{\n Kind: expr.VerdictAccept,\n },\n },\n })\n if err := c.Flush(); err == nil {\n t.Fatalf(\"compat policy should conflict and err should not be err\")\n }\n}\n")))
[client-notification] Sat Dec 10 13:25:06 2022:
(:jsonrpc "2.0" :method "workspace/didChangeConfiguration" :params
(:settings #s(hash-table size 1 test eql rehash-size 1.5 rehash-threshold 0.8125 data
())))
[server-notification] Sat Dec 10 13:25:06 2022:
(:jsonrpc "2.0" :method "window/logMessage" :params
(:type 3 :message "2022/12/10 13:25:06 go env for /home/michael/go/src/github.com/google/nftables\n(root /home/michael/go/src/github.com/google/nftables)\n(go version go version go1.19.3 linux/amd64)\n(valid build configuration = true)\n(build flags: [])\nGO111MODULE=\nGOSUMDB=sum.golang.org\nGONOPROXY=\nGOFLAGS=\nGOINSECURE=\nGOMOD=/home/michael/go/src/github.com/google/nftables/go.mod\nGOWORK=\nGOCACHE=/home/michael/.cache/go-build\nGOROOT=/home/michael/sdk/go1.19.3\nGOMODCACHE=/home/michael/go/pkg/mod\nGOPATH=/home/michael/go\nGONOSUMDB=\nGOPRIVATE=\nGOPROXY=https://proxy.golang.org,direct\n\n"))
[server-notification] Sat Dec 10 13:25:06 2022:
(:jsonrpc "2.0" :method "window/logMessage" :params
(:type 3 :message "2022/12/10 13:25:06 go/packages.Load #1\n snapshot=0\n directory=/home/michael/go/src/github.com/google/nftables\n query=[builtin github.com/google/nftables/...]\n packages=20\n"))
[server-notification] Sat Dec 10 13:25:06 2022:
(:jsonrpc "2.0" :method "window/logMessage" :params
(:type 3 :message "2022/12/10 13:25:06 go/packages.Load #1: updating metadata for 85 packages\n"))
[server-notification] Sat Dec 10 13:25:06 2022:
(:jsonrpc "2.0" :method "window/showMessage" :params
(:type 3 :message "Finished loading packages."))
[server-request] (id:2) Sat Dec 10 13:25:06 2022:
(:jsonrpc "2.0" :method "client/registerCapability" :params
(:registrations
[(:id "workspace/didChangeWatchedFiles-0" :method "workspace/didChangeWatchedFiles" :registerOptions
(:watchers
[(:globPattern "{/home/michael/go/src/github.com/google/nftables/alignedbuff,/home/michael/go/src/github.com/google/nftables/binaryutil,/home/michael/go/src/github.com/google/nftables/expr,/home/michael/go/src/github.com/google/nftables/internal,/home/michael/go/src/github.com/google/nftables/internal/nftest,/home/michael/go/src/github.com/google/nftables/internal/parseexprfunc,/home/michael/go/src/github.com/google/nftables/repro,/home/michael/go/src/github.com/google/nftables/xt}" :kind 7)
(:globPattern "**/*.{go,mod,sum,work}" :kind 7)]))])
:id 2)
[client-reply] (id:2) Sat Dec 10 13:25:06 2022:
(:jsonrpc "2.0" :id 2 :result nil)
[server-request] (id:3) Sat Dec 10 13:25:06 2022:
(:jsonrpc "2.0" :method "workspace/configuration" :params
(:items
[(:section "gopls")])
:id 3)
[client-reply] (id:3) Sat Dec 10 13:25:06 2022:
(:jsonrpc "2.0" :id 3 :result
[nil])
[server-request] (id:4) Sat Dec 10 13:25:06 2022:
(:jsonrpc "2.0" :method "workspace/configuration" :params
(:items
[(:scopeUri "file:///home/michael/go/src/github.com/google/nftables" :section "gopls")])
:id 4)
[client-reply] (id:4) Sat Dec 10 13:25:06 2022:
(:jsonrpc "2.0" :id 4 :result
[nil])
[server-notification] Sat Dec 10 13:25:06 2022:
(:jsonrpc "2.0" :method "textDocument/publishDiagnostics" :params
(:uri "file:///home/michael/go/src/github.com/google/nftables/nftables_test.go" :diagnostics
[(:range
(:start
(:line 1672 :character 2)
:end
(:line 1672 :character 8))
:severity 2 :source "simplifycompositelit" :message "redundant type from array, slice, or map composite literal" :tags
[1])
(:range
(:start
(:line 1679 :character 2)
:end
(:line 1679 :character 19))
:severity 2 :source "simplifycompositelit" :message "redundant type from array, slice, or map composite literal" :tags
[1])
(:range
(:start
(:line 1679 :character 20)
:end
(:line 1679 :character 35))
:severity 2 :source "simplifycompositelit" :message "redundant type from array, slice, or map composite literal" :tags
[1])
(:range
(:start
(:line 1680 :character 2)
:end
(:line 1680 :character 19))
:severity 2 :source "simplifycompositelit" :message "redundant type from array, slice, or map composite literal" :tags
[1])
(:range
(:start
(:line 1680 :character 20)
:end
(:line 1680 :character 35))
:severity 2 :source "simplifycompositelit" :message "redundant type from array, slice, or map composite literal" :tags
[1])
(:range
(:start
(:line 1681 :character 2)
:end
(:line 1681 :character 19))
:severity 2 :source "simplifycompositelit" :message "redundant type from array, slice, or map composite literal" :tags
[1])
(:range
(:start
(:line 1681 :character 20)
:end
(:line 1681 :character 35))
:severity 2 :source "simplifycompositelit" :message "redundant type from array, slice, or map composite literal" :tags
[1])]))
[server-notification] Sat Dec 10 13:25:06 2022:
(:jsonrpc "2.0" :method "textDocument/publishDiagnostics" :params
(:uri "file:///home/michael/go/src/github.com/google/nftables/get_rules_test.go" :diagnostics
[(:range
(:start
(:line 16 :character 2)
:end
(:line 16 :character 8))
:severity 2 :source "simplifycompositelit" :message "redundant type from array, slice, or map composite literal" :tags
[1])
(:range
(:start
(:line 23 :character 2)
:end
(:line 23 :character 19))
:severity 2 :source "simplifycompositelit" :message "redundant type from array, slice, or map composite literal" :tags
[1])
(:range
(:start
(:line 23 :character 20)
:end
(:line 23 :character 35))
:severity 2 :source "simplifycompositelit" :message "redundant type from array, slice, or map composite literal" :tags
[1])
(:range
(:start
(:line 24 :character 2)
:end
(:line 24 :character 19))
:severity 2 :source "simplifycompositelit" :message "redundant type from array, slice, or map composite literal" :tags
[1])
(:range
(:start
(:line 24 :character 20)
:end
(:line 24 :character 35))
:severity 2 :source "simplifycompositelit" :message "redundant type from array, slice, or map composite literal" :tags
[1])]))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment