diff --git a/SOURCES/0048-tests-py-Move-tcpopt.t-to-any-directory.patch b/SOURCES/0048-tests-py-Move-tcpopt.t-to-any-directory.patch new file mode 100644 index 0000000..f366a09 --- /dev/null +++ b/SOURCES/0048-tests-py-Move-tcpopt.t-to-any-directory.patch @@ -0,0 +1,2507 @@ +From c925727c50aa0c916105deaca95cb2f7292ea906 Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Mon, 12 Jul 2021 17:44:08 +0200 +Subject: [PATCH] tests/py: Move tcpopt.t to any/ directory + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1979334 +Upstream Status: nftables commit d566fecdfcc37 + +commit d566fecdfcc37b721729d26a90af01fc87e09c89 +Author: Phil Sutter +Date: Tue Mar 10 12:56:18 2020 +0100 + + tests/py: Move tcpopt.t to any/ directory + + Merge tcpopt.t files in ip, ip6 and inet into a common one, they were + just marignally different. + + Signed-off-by: Phil Sutter +--- + tests/py/{inet => any}/tcpopt.t | 3 + + tests/py/{inet => any}/tcpopt.t.json | 70 ++- + tests/py/{inet => any}/tcpopt.t.json.output | 0 + tests/py/any/tcpopt.t.payload | 603 ++++++++++++++++++++ + tests/py/inet/tcpopt.t.payload | 200 ------- + tests/py/ip/tcpopt.t | 38 -- + tests/py/ip/tcpopt.t.json | 416 -------------- + tests/py/ip/tcpopt.t.json.output | 16 - + tests/py/ip/tcpopt.t.payload | 181 ------ + tests/py/ip6/tcpopt.t | 37 -- + tests/py/ip6/tcpopt.t.json | 416 -------------- + tests/py/ip6/tcpopt.t.json.output | 16 - + tests/py/ip6/tcpopt.t.payload | 181 ------ + 13 files changed, 649 insertions(+), 1528 deletions(-) + rename tests/py/{inet => any}/tcpopt.t (94%) + rename tests/py/{inet => any}/tcpopt.t.json (88%) + rename tests/py/{inet => any}/tcpopt.t.json.output (100%) + create mode 100644 tests/py/any/tcpopt.t.payload + delete mode 100644 tests/py/inet/tcpopt.t.payload + delete mode 100644 tests/py/ip/tcpopt.t + delete mode 100644 tests/py/ip/tcpopt.t.json + delete mode 100644 tests/py/ip/tcpopt.t.json.output + delete mode 100644 tests/py/ip/tcpopt.t.payload + delete mode 100644 tests/py/ip6/tcpopt.t + delete mode 100644 tests/py/ip6/tcpopt.t.json + delete mode 100644 tests/py/ip6/tcpopt.t.json.output + delete mode 100644 tests/py/ip6/tcpopt.t.payload + +diff --git a/tests/py/inet/tcpopt.t b/tests/py/any/tcpopt.t +similarity index 94% +rename from tests/py/inet/tcpopt.t +rename to tests/py/any/tcpopt.t +index b457691..08b1dcb 100644 +--- a/tests/py/inet/tcpopt.t ++++ b/tests/py/any/tcpopt.t +@@ -1,5 +1,7 @@ + :input;type filter hook input priority 0 + ++*ip;test-ip4;input ++*ip6;test-ip6;input + *inet;test-inet;input + + tcp option eol kind 1;ok +@@ -19,6 +21,7 @@ tcp option sack0 left 1;ok;tcp option sack left 1 + tcp option sack1 left 1;ok + tcp option sack2 left 1;ok + tcp option sack3 left 1;ok ++tcp option sack right 1;ok + tcp option sack0 right 1;ok;tcp option sack right 1 + tcp option sack1 right 1;ok + tcp option sack2 right 1;ok +diff --git a/tests/py/inet/tcpopt.t.json b/tests/py/any/tcpopt.t.json +similarity index 88% +rename from tests/py/inet/tcpopt.t.json +rename to tests/py/any/tcpopt.t.json +index 45e9c29..48eb339 100644 +--- a/tests/py/inet/tcpopt.t.json ++++ b/tests/py/any/tcpopt.t.json +@@ -8,7 +8,7 @@ + "name": "eol" + } + }, +- "op": "==", ++ "op": "==", + "right": 1 + } + } +@@ -24,7 +24,7 @@ + "name": "noop" + } + }, +- "op": "==", ++ "op": "==", + "right": 1 + } + } +@@ -40,7 +40,7 @@ + "name": "maxseg" + } + }, +- "op": "==", ++ "op": "==", + "right": 1 + } + } +@@ -56,7 +56,7 @@ + "name": "maxseg" + } + }, +- "op": "==", ++ "op": "==", + "right": 1 + } + } +@@ -72,7 +72,7 @@ + "name": "maxseg" + } + }, +- "op": "==", ++ "op": "==", + "right": 1 + } + } +@@ -88,7 +88,7 @@ + "name": "window" + } + }, +- "op": "==", ++ "op": "==", + "right": 1 + } + } +@@ -104,7 +104,7 @@ + "name": "window" + } + }, +- "op": "==", ++ "op": "==", + "right": 1 + } + } +@@ -120,7 +120,7 @@ + "name": "window" + } + }, +- "op": "==", ++ "op": "==", + "right": 1 + } + } +@@ -136,7 +136,7 @@ + "name": "sack-permitted" + } + }, +- "op": "==", ++ "op": "==", + "right": 1 + } + } +@@ -152,7 +152,7 @@ + "name": "sack-permitted" + } + }, +- "op": "==", ++ "op": "==", + "right": 1 + } + } +@@ -168,7 +168,7 @@ + "name": "sack" + } + }, +- "op": "==", ++ "op": "==", + "right": 1 + } + } +@@ -184,7 +184,7 @@ + "name": "sack" + } + }, +- "op": "==", ++ "op": "==", + "right": 1 + } + } +@@ -200,7 +200,7 @@ + "name": "sack" + } + }, +- "op": "==", ++ "op": "==", + "right": 1 + } + } +@@ -216,7 +216,7 @@ + "name": "sack0" + } + }, +- "op": "==", ++ "op": "==", + "right": 1 + } + } +@@ -232,7 +232,7 @@ + "name": "sack1" + } + }, +- "op": "==", ++ "op": "==", + "right": 1 + } + } +@@ -248,7 +248,7 @@ + "name": "sack2" + } + }, +- "op": "==", ++ "op": "==", + "right": 1 + } + } +@@ -264,7 +264,23 @@ + "name": "sack3" + } + }, +- "op": "==", ++ "op": "==", ++ "right": 1 ++ } ++ } ++] ++ ++# tcp option sack right 1 ++[ ++ { ++ "match": { ++ "left": { ++ "tcp option": { ++ "field": "right", ++ "name": "sack" ++ } ++ }, ++ "op": "==", + "right": 1 + } + } +@@ -280,7 +296,7 @@ + "name": "sack0" + } + }, +- "op": "==", ++ "op": "==", + "right": 1 + } + } +@@ -296,7 +312,7 @@ + "name": "sack1" + } + }, +- "op": "==", ++ "op": "==", + "right": 1 + } + } +@@ -312,7 +328,7 @@ + "name": "sack2" + } + }, +- "op": "==", ++ "op": "==", + "right": 1 + } + } +@@ -328,7 +344,7 @@ + "name": "sack3" + } + }, +- "op": "==", ++ "op": "==", + "right": 1 + } + } +@@ -344,7 +360,7 @@ + "name": "timestamp" + } + }, +- "op": "==", ++ "op": "==", + "right": 1 + } + } +@@ -360,7 +376,7 @@ + "name": "timestamp" + } + }, +- "op": "==", ++ "op": "==", + "right": 1 + } + } +@@ -376,7 +392,7 @@ + "name": "timestamp" + } + }, +- "op": "==", ++ "op": "==", + "right": 1 + } + } +@@ -392,7 +408,7 @@ + "name": "timestamp" + } + }, +- "op": "==", ++ "op": "==", + "right": 1 + } + } +@@ -407,7 +423,7 @@ + "name": "window" + } + }, +- "op": "==", ++ "op": "==", + "right": true + } + } +@@ -422,7 +438,7 @@ + "name": "window" + } + }, +- "op": "==", ++ "op": "==", + "right": false + } + } +diff --git a/tests/py/inet/tcpopt.t.json.output b/tests/py/any/tcpopt.t.json.output +similarity index 100% +rename from tests/py/inet/tcpopt.t.json.output +rename to tests/py/any/tcpopt.t.json.output +diff --git a/tests/py/any/tcpopt.t.payload b/tests/py/any/tcpopt.t.payload +new file mode 100644 +index 0000000..63751cf +--- /dev/null ++++ b/tests/py/any/tcpopt.t.payload +@@ -0,0 +1,603 @@ ++# tcp option eol kind 1 ++ip ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 1b @ 0 + 0 => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# tcp option eol kind 1 ++ip6 ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 1b @ 0 + 0 => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# tcp option eol kind 1 ++inet ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 1b @ 0 + 0 => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# tcp option noop kind 1 ++ip ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 1b @ 1 + 0 => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# tcp option noop kind 1 ++ip6 ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 1b @ 1 + 0 => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# tcp option noop kind 1 ++inet ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 1b @ 1 + 0 => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# tcp option maxseg kind 1 ++ip ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 1b @ 2 + 0 => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# tcp option maxseg kind 1 ++ip6 ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 1b @ 2 + 0 => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# tcp option maxseg kind 1 ++inet ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 1b @ 2 + 0 => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# tcp option maxseg length 1 ++ip ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 1b @ 2 + 1 => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# tcp option maxseg length 1 ++ip6 ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 1b @ 2 + 1 => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# tcp option maxseg length 1 ++inet ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 1b @ 2 + 1 => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# tcp option maxseg size 1 ++ip ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 2b @ 2 + 2 => reg 1 ] ++ [ cmp eq reg 1 0x00000100 ] ++ ++# tcp option maxseg size 1 ++ip6 ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 2b @ 2 + 2 => reg 1 ] ++ [ cmp eq reg 1 0x00000100 ] ++ ++# tcp option maxseg size 1 ++inet ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 2b @ 2 + 2 => reg 1 ] ++ [ cmp eq reg 1 0x00000100 ] ++ ++# tcp option window kind 1 ++ip ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 1b @ 3 + 0 => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# tcp option window kind 1 ++ip6 ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 1b @ 3 + 0 => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# tcp option window kind 1 ++inet ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 1b @ 3 + 0 => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# tcp option window length 1 ++ip ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 1b @ 3 + 1 => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# tcp option window length 1 ++ip6 ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 1b @ 3 + 1 => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# tcp option window length 1 ++inet ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 1b @ 3 + 1 => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# tcp option window count 1 ++ip ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 1b @ 3 + 2 => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# tcp option window count 1 ++ip6 ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 1b @ 3 + 2 => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# tcp option window count 1 ++inet ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 1b @ 3 + 2 => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# tcp option sack-permitted kind 1 ++ip ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 1b @ 4 + 0 => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# tcp option sack-permitted kind 1 ++ip6 ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 1b @ 4 + 0 => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# tcp option sack-permitted kind 1 ++inet ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 1b @ 4 + 0 => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# tcp option sack-permitted length 1 ++ip ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 1b @ 4 + 1 => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# tcp option sack-permitted length 1 ++ip6 ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 1b @ 4 + 1 => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# tcp option sack-permitted length 1 ++inet ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 1b @ 4 + 1 => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# tcp option sack kind 1 ++ip ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 1b @ 5 + 0 => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# tcp option sack kind 1 ++ip6 ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 1b @ 5 + 0 => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# tcp option sack kind 1 ++inet ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 1b @ 5 + 0 => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# tcp option sack length 1 ++ip ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 1b @ 5 + 1 => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# tcp option sack length 1 ++ip6 ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 1b @ 5 + 1 => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# tcp option sack length 1 ++inet ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 1b @ 5 + 1 => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# tcp option sack left 1 ++ip ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 4b @ 5 + 2 => reg 1 ] ++ [ cmp eq reg 1 0x01000000 ] ++ ++# tcp option sack left 1 ++ip6 ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 4b @ 5 + 2 => reg 1 ] ++ [ cmp eq reg 1 0x01000000 ] ++ ++# tcp option sack left 1 ++inet ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 4b @ 5 + 2 => reg 1 ] ++ [ cmp eq reg 1 0x01000000 ] ++ ++# tcp option sack0 left 1 ++ip ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 4b @ 5 + 2 => reg 1 ] ++ [ cmp eq reg 1 0x01000000 ] ++ ++# tcp option sack0 left 1 ++ip6 ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 4b @ 5 + 2 => reg 1 ] ++ [ cmp eq reg 1 0x01000000 ] ++ ++# tcp option sack0 left 1 ++inet ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 4b @ 5 + 2 => reg 1 ] ++ [ cmp eq reg 1 0x01000000 ] ++ ++# tcp option sack1 left 1 ++ip ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 4b @ 5 + 10 => reg 1 ] ++ [ cmp eq reg 1 0x01000000 ] ++ ++# tcp option sack1 left 1 ++ip6 ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 4b @ 5 + 10 => reg 1 ] ++ [ cmp eq reg 1 0x01000000 ] ++ ++# tcp option sack1 left 1 ++inet ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 4b @ 5 + 10 => reg 1 ] ++ [ cmp eq reg 1 0x01000000 ] ++ ++# tcp option sack2 left 1 ++ip ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 4b @ 5 + 18 => reg 1 ] ++ [ cmp eq reg 1 0x01000000 ] ++ ++# tcp option sack2 left 1 ++ip6 ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 4b @ 5 + 18 => reg 1 ] ++ [ cmp eq reg 1 0x01000000 ] ++ ++# tcp option sack2 left 1 ++inet ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 4b @ 5 + 18 => reg 1 ] ++ [ cmp eq reg 1 0x01000000 ] ++ ++# tcp option sack3 left 1 ++ip ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 4b @ 5 + 26 => reg 1 ] ++ [ cmp eq reg 1 0x01000000 ] ++ ++# tcp option sack3 left 1 ++ip6 ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 4b @ 5 + 26 => reg 1 ] ++ [ cmp eq reg 1 0x01000000 ] ++ ++# tcp option sack3 left 1 ++inet ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 4b @ 5 + 26 => reg 1 ] ++ [ cmp eq reg 1 0x01000000 ] ++ ++# tcp option sack right 1 ++ip ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 4b @ 5 + 6 => reg 1 ] ++ [ cmp eq reg 1 0x01000000 ] ++ ++# tcp option sack right 1 ++ip6 ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 4b @ 5 + 6 => reg 1 ] ++ [ cmp eq reg 1 0x01000000 ] ++ ++# tcp option sack right 1 ++inet ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 4b @ 5 + 6 => reg 1 ] ++ [ cmp eq reg 1 0x01000000 ] ++ ++# tcp option sack0 right 1 ++ip ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 4b @ 5 + 6 => reg 1 ] ++ [ cmp eq reg 1 0x01000000 ] ++ ++# tcp option sack0 right 1 ++ip6 ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 4b @ 5 + 6 => reg 1 ] ++ [ cmp eq reg 1 0x01000000 ] ++ ++# tcp option sack0 right 1 ++inet ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 4b @ 5 + 6 => reg 1 ] ++ [ cmp eq reg 1 0x01000000 ] ++ ++# tcp option sack1 right 1 ++ip ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 4b @ 5 + 14 => reg 1 ] ++ [ cmp eq reg 1 0x01000000 ] ++ ++# tcp option sack1 right 1 ++ip6 ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 4b @ 5 + 14 => reg 1 ] ++ [ cmp eq reg 1 0x01000000 ] ++ ++# tcp option sack1 right 1 ++inet ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 4b @ 5 + 14 => reg 1 ] ++ [ cmp eq reg 1 0x01000000 ] ++ ++# tcp option sack2 right 1 ++ip ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 4b @ 5 + 22 => reg 1 ] ++ [ cmp eq reg 1 0x01000000 ] ++ ++# tcp option sack2 right 1 ++ip6 ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 4b @ 5 + 22 => reg 1 ] ++ [ cmp eq reg 1 0x01000000 ] ++ ++# tcp option sack2 right 1 ++inet ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 4b @ 5 + 22 => reg 1 ] ++ [ cmp eq reg 1 0x01000000 ] ++ ++# tcp option sack3 right 1 ++ip ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 4b @ 5 + 30 => reg 1 ] ++ [ cmp eq reg 1 0x01000000 ] ++ ++# tcp option sack3 right 1 ++ip6 ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 4b @ 5 + 30 => reg 1 ] ++ [ cmp eq reg 1 0x01000000 ] ++ ++# tcp option sack3 right 1 ++inet ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 4b @ 5 + 30 => reg 1 ] ++ [ cmp eq reg 1 0x01000000 ] ++ ++# tcp option timestamp kind 1 ++ip ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 1b @ 8 + 0 => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# tcp option timestamp kind 1 ++ip6 ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 1b @ 8 + 0 => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# tcp option timestamp kind 1 ++inet ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 1b @ 8 + 0 => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# tcp option timestamp length 1 ++ip ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 1b @ 8 + 1 => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# tcp option timestamp length 1 ++ip6 ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 1b @ 8 + 1 => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# tcp option timestamp length 1 ++inet ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 1b @ 8 + 1 => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# tcp option timestamp tsval 1 ++ip ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 4b @ 8 + 2 => reg 1 ] ++ [ cmp eq reg 1 0x01000000 ] ++ ++# tcp option timestamp tsval 1 ++ip6 ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 4b @ 8 + 2 => reg 1 ] ++ [ cmp eq reg 1 0x01000000 ] ++ ++# tcp option timestamp tsval 1 ++inet ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 4b @ 8 + 2 => reg 1 ] ++ [ cmp eq reg 1 0x01000000 ] ++ ++# tcp option timestamp tsecr 1 ++ip ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 4b @ 8 + 6 => reg 1 ] ++ [ cmp eq reg 1 0x01000000 ] ++ ++# tcp option timestamp tsecr 1 ++ip6 ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 4b @ 8 + 6 => reg 1 ] ++ [ cmp eq reg 1 0x01000000 ] ++ ++# tcp option timestamp tsecr 1 ++inet ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 4b @ 8 + 6 => reg 1 ] ++ [ cmp eq reg 1 0x01000000 ] ++ ++# tcp option window exists ++ip ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 1b @ 3 + 0 present => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# tcp option window exists ++ip6 ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 1b @ 3 + 0 present => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# tcp option window exists ++inet ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 1b @ 3 + 0 present => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# tcp option window missing ++ip ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 1b @ 3 + 0 present => reg 1 ] ++ [ cmp eq reg 1 0x00000000 ] ++ ++# tcp option window missing ++ip6 ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 1b @ 3 + 0 present => reg 1 ] ++ [ cmp eq reg 1 0x00000000 ] ++ ++# tcp option window missing ++inet ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 1b @ 3 + 0 present => reg 1 ] ++ [ cmp eq reg 1 0x00000000 ] ++ ++# tcp option maxseg size set 1360 ++ip ++ [ immediate reg 1 0x00005005 ] ++ [ exthdr write tcpopt reg 1 => 2b @ 2 + 2 ] ++ ++# tcp option maxseg size set 1360 ++ip6 ++ [ immediate reg 1 0x00005005 ] ++ [ exthdr write tcpopt reg 1 => 2b @ 2 + 2 ] ++ ++# tcp option maxseg size set 1360 ++inet ++ [ immediate reg 1 0x00005005 ] ++ [ exthdr write tcpopt reg 1 => 2b @ 2 + 2 ] ++ +diff --git a/tests/py/inet/tcpopt.t.payload b/tests/py/inet/tcpopt.t.payload +deleted file mode 100644 +index 7e254ed..0000000 +--- a/tests/py/inet/tcpopt.t.payload ++++ /dev/null +@@ -1,200 +0,0 @@ +-# tcp option eol kind 1 +-inet test-inet input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 1b @ 0 + 0 => reg 1 ] +- [ cmp eq reg 1 0x00000001 ] +- +-# tcp option noop kind 1 +-inet test-inet input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 1b @ 1 + 0 => reg 1 ] +- [ cmp eq reg 1 0x00000001 ] +- +-# tcp option maxseg kind 1 +-inet test-inet input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 1b @ 2 + 0 => reg 1 ] +- [ cmp eq reg 1 0x00000001 ] +- +-# tcp option maxseg length 1 +-inet test-inet input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 1b @ 2 + 1 => reg 1 ] +- [ cmp eq reg 1 0x00000001 ] +- +-# tcp option maxseg size 1 +-inet test-inet input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 2b @ 2 + 2 => reg 1 ] +- [ cmp eq reg 1 0x00000100 ] +- +-# tcp option window kind 1 +-inet test-inet input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 1b @ 3 + 0 => reg 1 ] +- [ cmp eq reg 1 0x00000001 ] +- +-# tcp option window length 1 +-inet test-inet input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 1b @ 3 + 1 => reg 1 ] +- [ cmp eq reg 1 0x00000001 ] +- +-# tcp option window count 1 +-inet test-inet input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 1b @ 3 + 2 => reg 1 ] +- [ cmp eq reg 1 0x00000001 ] +- +-# tcp option sack-permitted kind 1 +-inet test-inet input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 1b @ 4 + 0 => reg 1 ] +- [ cmp eq reg 1 0x00000001 ] +- +-# tcp option sack-permitted length 1 +-inet test-inet input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 1b @ 4 + 1 => reg 1 ] +- [ cmp eq reg 1 0x00000001 ] +- +-# tcp option sack kind 1 +-inet test-inet input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 1b @ 5 + 0 => reg 1 ] +- [ cmp eq reg 1 0x00000001 ] +- +-# tcp option sack length 1 +-inet test-inet input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 1b @ 5 + 1 => reg 1 ] +- [ cmp eq reg 1 0x00000001 ] +- +-# tcp option sack left 1 +-inet test-inet input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 4b @ 5 + 2 => reg 1 ] +- [ cmp eq reg 1 0x01000000 ] +- +-# tcp option sack0 left 1 +-inet test-inet input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 4b @ 5 + 2 => reg 1 ] +- [ cmp eq reg 1 0x01000000 ] +- +-# tcp option sack1 left 1 +-inet test-inet input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 4b @ 5 + 10 => reg 1 ] +- [ cmp eq reg 1 0x01000000 ] +- +-# tcp option sack2 left 1 +-inet test-inet input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 4b @ 5 + 18 => reg 1 ] +- [ cmp eq reg 1 0x01000000 ] +- +-# tcp option sack3 left 1 +-inet test-inet input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 4b @ 5 + 26 => reg 1 ] +- [ cmp eq reg 1 0x01000000 ] +- +-# tcp option sack right 1 +-inet test-inet input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 4b @ 5 + 6 => reg 1 ] +- [ cmp eq reg 1 0x01000000 ] +- +-# tcp option sack0 right 1 +-inet test-inet input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 4b @ 5 + 6 => reg 1 ] +- [ cmp eq reg 1 0x01000000 ] +- +-# tcp option sack1 right 1 +-inet test-inet input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 4b @ 5 + 14 => reg 1 ] +- [ cmp eq reg 1 0x01000000 ] +- +-# tcp option sack2 right 1 +-inet test-inet input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 4b @ 5 + 22 => reg 1 ] +- [ cmp eq reg 1 0x01000000 ] +- +-# tcp option sack3 right 1 +-inet test-inet input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 4b @ 5 + 30 => reg 1 ] +- [ cmp eq reg 1 0x01000000 ] +- +-# tcp option timestamp kind 1 +-inet test-inet input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 1b @ 8 + 0 => reg 1 ] +- [ cmp eq reg 1 0x00000001 ] +- +-# tcp option timestamp length 1 +-inet test-inet input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 1b @ 8 + 1 => reg 1 ] +- [ cmp eq reg 1 0x00000001 ] +- +-# tcp option timestamp tsval 1 +-inet test-inet input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 4b @ 8 + 2 => reg 1 ] +- [ cmp eq reg 1 0x01000000 ] +- +-# tcp option timestamp tsecr 1 +-inet test-inet input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 4b @ 8 + 6 => reg 1 ] +- [ cmp eq reg 1 0x01000000 ] +- +-# tcp option window exists +-inet test-inet input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 1b @ 3 + 0 present => reg 1 ] +- [ cmp eq reg 1 0x00000001 ] +- +-# tcp option window missing +-inet test-inet input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 1b @ 3 + 0 present => reg 1 ] +- [ cmp eq reg 1 0x00000000 ] +- +-# tcp option maxseg size set 1360 +-inet test-inet input +- [ immediate reg 1 0x00005005 ] +- [ exthdr write tcpopt reg 1 => 2b @ 2 + 2 ] +diff --git a/tests/py/ip/tcpopt.t b/tests/py/ip/tcpopt.t +deleted file mode 100644 +index 7ee50a8..0000000 +--- a/tests/py/ip/tcpopt.t ++++ /dev/null +@@ -1,38 +0,0 @@ +-:input;type filter hook input priority 0 +- +-*ip;test-ip;input +- +-tcp option eol kind 1;ok +-tcp option noop kind 1;ok +-tcp option maxseg kind 1;ok +-tcp option maxseg length 1;ok +-tcp option maxseg size 1;ok +-tcp option window kind 1;ok +-tcp option window length 1;ok +-tcp option window count 1;ok +-tcp option sack-permitted kind 1;ok +-tcp option sack-permitted length 1;ok +-tcp option sack kind 1;ok +-tcp option sack length 1;ok +-tcp option sack left 1;ok +-tcp option sack0 left 1;ok;tcp option sack left 1 +-tcp option sack1 left 1;ok +-tcp option sack2 left 1;ok +-tcp option sack3 left 1;ok +-tcp option sack right 1;ok +-tcp option sack0 right 1;ok;tcp option sack right 1 +-tcp option sack1 right 1;ok +-tcp option sack2 right 1;ok +-tcp option sack3 right 1;ok +-tcp option timestamp kind 1;ok +-tcp option timestamp length 1;ok +-tcp option timestamp tsval 1;ok +-tcp option timestamp tsecr 1;ok +- +-tcp option foobar;fail +-tcp option foo bar;fail +-tcp option eol left;fail +-tcp option eol left 1;fail +-tcp option eol left 1;fail +-tcp option sack window;fail +-tcp option sack window 1;fail +diff --git a/tests/py/ip/tcpopt.t.json b/tests/py/ip/tcpopt.t.json +deleted file mode 100644 +index d573dd1..0000000 +--- a/tests/py/ip/tcpopt.t.json ++++ /dev/null +@@ -1,416 +0,0 @@ +-# tcp option eol kind 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "kind", +- "name": "eol" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option noop kind 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "kind", +- "name": "noop" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option maxseg kind 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "kind", +- "name": "maxseg" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option maxseg length 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "length", +- "name": "maxseg" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option maxseg size 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "size", +- "name": "maxseg" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option window kind 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "kind", +- "name": "window" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option window length 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "length", +- "name": "window" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option window count 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "count", +- "name": "window" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option sack-permitted kind 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "kind", +- "name": "sack-permitted" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option sack-permitted length 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "length", +- "name": "sack-permitted" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option sack kind 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "kind", +- "name": "sack" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option sack length 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "length", +- "name": "sack" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option sack left 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "left", +- "name": "sack" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option sack0 left 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "left", +- "name": "sack" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option sack1 left 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "left", +- "name": "sack1" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option sack2 left 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "left", +- "name": "sack2" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option sack3 left 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "left", +- "name": "sack3" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option sack right 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "right", +- "name": "sack" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option sack0 right 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "right", +- "name": "sack0" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option sack1 right 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "right", +- "name": "sack1" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option sack2 right 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "right", +- "name": "sack2" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option sack3 right 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "right", +- "name": "sack3" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option timestamp kind 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "kind", +- "name": "timestamp" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option timestamp length 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "length", +- "name": "timestamp" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option timestamp tsval 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "tsval", +- "name": "timestamp" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option timestamp tsecr 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "tsecr", +- "name": "timestamp" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +diff --git a/tests/py/ip/tcpopt.t.json.output b/tests/py/ip/tcpopt.t.json.output +deleted file mode 100644 +index 81dd8ad..0000000 +--- a/tests/py/ip/tcpopt.t.json.output ++++ /dev/null +@@ -1,16 +0,0 @@ +-# tcp option sack0 right 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "right", +- "name": "sack" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +diff --git a/tests/py/ip/tcpopt.t.payload b/tests/py/ip/tcpopt.t.payload +deleted file mode 100644 +index b2e5bdb..0000000 +--- a/tests/py/ip/tcpopt.t.payload ++++ /dev/null +@@ -1,181 +0,0 @@ +-# tcp option eol kind 1 +-ip test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 1b @ 0 + 0 => reg 1 ] +- [ cmp eq reg 1 0x00000001 ] +- +-# tcp option noop kind 1 +-ip test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 1b @ 1 + 0 => reg 1 ] +- [ cmp eq reg 1 0x00000001 ] +- +-# tcp option maxseg kind 1 +-ip test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 1b @ 2 + 0 => reg 1 ] +- [ cmp eq reg 1 0x00000001 ] +- +-# tcp option maxseg length 1 +-ip test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 1b @ 2 + 1 => reg 1 ] +- [ cmp eq reg 1 0x00000001 ] +- +-# tcp option maxseg size 1 +-ip test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 2b @ 2 + 2 => reg 1 ] +- [ cmp eq reg 1 0x00000100 ] +- +-# tcp option window kind 1 +-ip test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 1b @ 3 + 0 => reg 1 ] +- [ cmp eq reg 1 0x00000001 ] +- +-# tcp option window length 1 +-ip test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 1b @ 3 + 1 => reg 1 ] +- [ cmp eq reg 1 0x00000001 ] +- +-# tcp option window count 1 +-ip test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 1b @ 3 + 2 => reg 1 ] +- [ cmp eq reg 1 0x00000001 ] +- +-# tcp option sack-permitted kind 1 +-ip test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 1b @ 4 + 0 => reg 1 ] +- [ cmp eq reg 1 0x00000001 ] +- +-# tcp option sack-permitted length 1 +-ip test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 1b @ 4 + 1 => reg 1 ] +- [ cmp eq reg 1 0x00000001 ] +- +-# tcp option sack kind 1 +-ip test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 1b @ 5 + 0 => reg 1 ] +- [ cmp eq reg 1 0x00000001 ] +- +-# tcp option sack length 1 +-ip test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 1b @ 5 + 1 => reg 1 ] +- [ cmp eq reg 1 0x00000001 ] +- +-# tcp option sack left 1 +-ip test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 4b @ 5 + 2 => reg 1 ] +- [ cmp eq reg 1 0x01000000 ] +- +-# tcp option sack0 left 1 +-ip test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 4b @ 5 + 2 => reg 1 ] +- [ cmp eq reg 1 0x01000000 ] +- +-# tcp option sack1 left 1 +-ip test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 4b @ 5 + 10 => reg 1 ] +- [ cmp eq reg 1 0x01000000 ] +- +-# tcp option sack2 left 1 +-ip test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 4b @ 5 + 18 => reg 1 ] +- [ cmp eq reg 1 0x01000000 ] +- +-# tcp option sack3 left 1 +-ip test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 4b @ 5 + 26 => reg 1 ] +- [ cmp eq reg 1 0x01000000 ] +- +-# tcp option sack right 1 +-ip test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 4b @ 5 + 6 => reg 1 ] +- [ cmp eq reg 1 0x01000000 ] +- +-# tcp option sack0 right 1 +-ip test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 4b @ 5 + 6 => reg 1 ] +- [ cmp eq reg 1 0x01000000 ] +- +-# tcp option sack1 right 1 +-ip test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 4b @ 5 + 14 => reg 1 ] +- [ cmp eq reg 1 0x01000000 ] +- +-# tcp option sack2 right 1 +-ip test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 4b @ 5 + 22 => reg 1 ] +- [ cmp eq reg 1 0x01000000 ] +- +-# tcp option sack3 right 1 +-ip test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 4b @ 5 + 30 => reg 1 ] +- [ cmp eq reg 1 0x01000000 ] +- +-# tcp option timestamp kind 1 +-ip test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 1b @ 8 + 0 => reg 1 ] +- [ cmp eq reg 1 0x00000001 ] +- +-# tcp option timestamp length 1 +-ip test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 1b @ 8 + 1 => reg 1 ] +- [ cmp eq reg 1 0x00000001 ] +- +-# tcp option timestamp tsval 1 +-ip test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 4b @ 8 + 2 => reg 1 ] +- [ cmp eq reg 1 0x01000000 ] +- +-# tcp option timestamp tsecr 1 +-ip test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 4b @ 8 + 6 => reg 1 ] +- [ cmp eq reg 1 0x01000000 ] +diff --git a/tests/py/ip6/tcpopt.t b/tests/py/ip6/tcpopt.t +deleted file mode 100644 +index 497f69f..0000000 +--- a/tests/py/ip6/tcpopt.t ++++ /dev/null +@@ -1,37 +0,0 @@ +-:input;type filter hook input priority 0 +-*ip6;test-ip6;input +- +-tcp option eol kind 1;ok +-tcp option noop kind 1;ok +-tcp option maxseg kind 1;ok +-tcp option maxseg length 1;ok +-tcp option maxseg size 1;ok +-tcp option window kind 1;ok +-tcp option window length 1;ok +-tcp option window count 1;ok +-tcp option sack-permitted kind 1;ok +-tcp option sack-permitted length 1;ok +-tcp option sack kind 1;ok +-tcp option sack length 1;ok +-tcp option sack left 1;ok +-tcp option sack0 left 1;ok;tcp option sack left 1 +-tcp option sack1 left 1;ok +-tcp option sack2 left 1;ok +-tcp option sack3 left 1;ok +-tcp option sack right 1;ok +-tcp option sack0 right 1;ok;tcp option sack right 1 +-tcp option sack1 right 1;ok +-tcp option sack2 right 1;ok +-tcp option sack3 right 1;ok +-tcp option timestamp kind 1;ok +-tcp option timestamp length 1;ok +-tcp option timestamp tsval 1;ok +-tcp option timestamp tsecr 1;ok +- +-tcp option foobar;fail +-tcp option foo bar;fail +-tcp option eol left;fail +-tcp option eol left 1;fail +-tcp option eol left 1;fail +-tcp option sack window;fail +-tcp option sack window 1;fail +diff --git a/tests/py/ip6/tcpopt.t.json b/tests/py/ip6/tcpopt.t.json +deleted file mode 100644 +index d573dd1..0000000 +--- a/tests/py/ip6/tcpopt.t.json ++++ /dev/null +@@ -1,416 +0,0 @@ +-# tcp option eol kind 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "kind", +- "name": "eol" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option noop kind 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "kind", +- "name": "noop" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option maxseg kind 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "kind", +- "name": "maxseg" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option maxseg length 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "length", +- "name": "maxseg" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option maxseg size 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "size", +- "name": "maxseg" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option window kind 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "kind", +- "name": "window" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option window length 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "length", +- "name": "window" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option window count 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "count", +- "name": "window" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option sack-permitted kind 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "kind", +- "name": "sack-permitted" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option sack-permitted length 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "length", +- "name": "sack-permitted" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option sack kind 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "kind", +- "name": "sack" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option sack length 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "length", +- "name": "sack" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option sack left 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "left", +- "name": "sack" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option sack0 left 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "left", +- "name": "sack" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option sack1 left 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "left", +- "name": "sack1" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option sack2 left 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "left", +- "name": "sack2" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option sack3 left 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "left", +- "name": "sack3" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option sack right 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "right", +- "name": "sack" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option sack0 right 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "right", +- "name": "sack0" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option sack1 right 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "right", +- "name": "sack1" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option sack2 right 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "right", +- "name": "sack2" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option sack3 right 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "right", +- "name": "sack3" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option timestamp kind 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "kind", +- "name": "timestamp" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option timestamp length 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "length", +- "name": "timestamp" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option timestamp tsval 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "tsval", +- "name": "timestamp" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +-# tcp option timestamp tsecr 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "tsecr", +- "name": "timestamp" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +diff --git a/tests/py/ip6/tcpopt.t.json.output b/tests/py/ip6/tcpopt.t.json.output +deleted file mode 100644 +index 81dd8ad..0000000 +--- a/tests/py/ip6/tcpopt.t.json.output ++++ /dev/null +@@ -1,16 +0,0 @@ +-# tcp option sack0 right 1 +-[ +- { +- "match": { +- "left": { +- "tcp option": { +- "field": "right", +- "name": "sack" +- } +- }, +- "op": "==", +- "right": 1 +- } +- } +-] +- +diff --git a/tests/py/ip6/tcpopt.t.payload b/tests/py/ip6/tcpopt.t.payload +deleted file mode 100644 +index 4b18919..0000000 +--- a/tests/py/ip6/tcpopt.t.payload ++++ /dev/null +@@ -1,181 +0,0 @@ +-# tcp option eol kind 1 +-ip6 test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 1b @ 0 + 0 => reg 1 ] +- [ cmp eq reg 1 0x00000001 ] +- +-# tcp option noop kind 1 +-ip6 test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 1b @ 1 + 0 => reg 1 ] +- [ cmp eq reg 1 0x00000001 ] +- +-# tcp option maxseg kind 1 +-ip6 test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 1b @ 2 + 0 => reg 1 ] +- [ cmp eq reg 1 0x00000001 ] +- +-# tcp option maxseg length 1 +-ip6 test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 1b @ 2 + 1 => reg 1 ] +- [ cmp eq reg 1 0x00000001 ] +- +-# tcp option maxseg size 1 +-ip6 test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 2b @ 2 + 2 => reg 1 ] +- [ cmp eq reg 1 0x00000100 ] +- +-# tcp option window kind 1 +-ip6 test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 1b @ 3 + 0 => reg 1 ] +- [ cmp eq reg 1 0x00000001 ] +- +-# tcp option window length 1 +-ip6 test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 1b @ 3 + 1 => reg 1 ] +- [ cmp eq reg 1 0x00000001 ] +- +-# tcp option window count 1 +-ip6 test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 1b @ 3 + 2 => reg 1 ] +- [ cmp eq reg 1 0x00000001 ] +- +-# tcp option sack-permitted kind 1 +-ip6 test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 1b @ 4 + 0 => reg 1 ] +- [ cmp eq reg 1 0x00000001 ] +- +-# tcp option sack-permitted length 1 +-ip6 test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 1b @ 4 + 1 => reg 1 ] +- [ cmp eq reg 1 0x00000001 ] +- +-# tcp option sack kind 1 +-ip6 test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 1b @ 5 + 0 => reg 1 ] +- [ cmp eq reg 1 0x00000001 ] +- +-# tcp option sack length 1 +-ip6 test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 1b @ 5 + 1 => reg 1 ] +- [ cmp eq reg 1 0x00000001 ] +- +-# tcp option sack left 1 +-ip6 test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 4b @ 5 + 2 => reg 1 ] +- [ cmp eq reg 1 0x01000000 ] +- +-# tcp option sack0 left 1 +-ip6 test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 4b @ 5 + 2 => reg 1 ] +- [ cmp eq reg 1 0x01000000 ] +- +-# tcp option sack1 left 1 +-ip6 test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 4b @ 5 + 10 => reg 1 ] +- [ cmp eq reg 1 0x01000000 ] +- +-# tcp option sack2 left 1 +-ip6 test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 4b @ 5 + 18 => reg 1 ] +- [ cmp eq reg 1 0x01000000 ] +- +-# tcp option sack3 left 1 +-ip6 test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 4b @ 5 + 26 => reg 1 ] +- [ cmp eq reg 1 0x01000000 ] +- +-# tcp option sack right 1 +-ip6 test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 4b @ 5 + 6 => reg 1 ] +- [ cmp eq reg 1 0x01000000 ] +- +-# tcp option sack0 right 1 +-ip6 test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 4b @ 5 + 6 => reg 1 ] +- [ cmp eq reg 1 0x01000000 ] +- +-# tcp option sack1 right 1 +-ip6 test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 4b @ 5 + 14 => reg 1 ] +- [ cmp eq reg 1 0x01000000 ] +- +-# tcp option sack2 right 1 +-ip6 test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 4b @ 5 + 22 => reg 1 ] +- [ cmp eq reg 1 0x01000000 ] +- +-# tcp option sack3 right 1 +-ip6 test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 4b @ 5 + 30 => reg 1 ] +- [ cmp eq reg 1 0x01000000 ] +- +-# tcp option timestamp kind 1 +-ip6 test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 1b @ 8 + 0 => reg 1 ] +- [ cmp eq reg 1 0x00000001 ] +- +-# tcp option timestamp length 1 +-ip6 test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 1b @ 8 + 1 => reg 1 ] +- [ cmp eq reg 1 0x00000001 ] +- +-# tcp option timestamp tsval 1 +-ip6 test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 4b @ 8 + 2 => reg 1 ] +- [ cmp eq reg 1 0x01000000 ] +- +-# tcp option timestamp tsecr 1 +-ip6 test-ip input +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 4b @ 8 + 6 => reg 1 ] +- [ cmp eq reg 1 0x01000000 ] +-- +2.31.1 + diff --git a/SOURCES/0049-parser-merge-sack-perm-sack-permitted-and-maxseg-mss.patch b/SOURCES/0049-parser-merge-sack-perm-sack-permitted-and-maxseg-mss.patch new file mode 100644 index 0000000..6c23314 --- /dev/null +++ b/SOURCES/0049-parser-merge-sack-perm-sack-permitted-and-maxseg-mss.patch @@ -0,0 +1,294 @@ +From f87960ecc2ed04c803b27bb6a9c42ecd0ba0bc96 Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Mon, 12 Jul 2021 17:44:08 +0200 +Subject: [PATCH] parser: merge sack-perm/sack-permitted and maxseg/mss + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1979334 +Upstream Status: nftables commit 2a9aea6f2dfb6 + +commit 2a9aea6f2dfb6ee61528809af98860e06b38762b +Author: Florian Westphal +Date: Mon Nov 2 00:27:04 2020 +0100 + + parser: merge sack-perm/sack-permitted and maxseg/mss + + One was added by the tcp option parsing ocde, the other by synproxy. + + So we have: + synproxy ... sack-perm + synproxy ... mss + + and + + tcp option maxseg + tcp option sack-permitted + + This kills the extra tokens on the scanner/parser side, + so sack-perm and sack-permitted can both be used. + + Likewise, 'synproxy maxseg' and 'tcp option mss size 42' will work too. + On the output side, the shorter form is now preferred, i.e. sack-perm + and mss. + + Signed-off-by: Florian Westphal +--- + doc/payload-expression.txt | 8 ++++---- + src/parser_bison.y | 12 +++++------- + src/scanner.l | 8 ++++---- + src/tcpopt.c | 2 +- + tests/py/any/tcpopt.t | 4 ++-- + tests/py/any/tcpopt.t.json | 8 ++++---- + tests/py/any/tcpopt.t.payload | 12 ++++++------ + 7 files changed, 26 insertions(+), 28 deletions(-) + +diff --git a/doc/payload-expression.txt b/doc/payload-expression.txt +index dba42fd..3d7057c 100644 +--- a/doc/payload-expression.txt ++++ b/doc/payload-expression.txt +@@ -525,13 +525,13 @@ nftables currently supports matching (finding) a given ipv6 extension header, TC + *dst* {*nexthdr* | *hdrlength*} + *mh* {*nexthdr* | *hdrlength* | *checksum* | *type*} + *srh* {*flags* | *tag* | *sid* | *seg-left*} +-*tcp option* {*eol* | *noop* | *maxseg* | *window* | *sack-permitted* | *sack* | *sack0* | *sack1* | *sack2* | *sack3* | *timestamp*} 'tcp_option_field' ++*tcp option* {*eol* | *noop* | *maxseg* | *window* | *sack-perm* | *sack* | *sack0* | *sack1* | *sack2* | *sack3* | *timestamp*} 'tcp_option_field' + *ip option* { lsrr | ra | rr | ssrr } 'ip_option_field' + + The following syntaxes are valid only in a relational expression with boolean type on right-hand side for checking header existence only: + [verse] + *exthdr* {*hbh* | *frag* | *rt* | *dst* | *mh*} +-*tcp option* {*eol* | *noop* | *maxseg* | *window* | *sack-permitted* | *sack* | *sack0* | *sack1* | *sack2* | *sack3* | *timestamp*} ++*tcp option* {*eol* | *noop* | *maxseg* | *window* | *sack-perm* | *sack* | *sack0* | *sack1* | *sack2* | *sack3* | *timestamp*} + *ip option* { lsrr | ra | rr | ssrr } + + .IPv6 extension headers +@@ -568,7 +568,7 @@ kind, length, size + |window| + TCP Window Scaling | + kind, length, count +-|sack-permitted| ++|sack-perm | + TCP SACK permitted | + kind, length + |sack| +@@ -611,7 +611,7 @@ type, length, ptr, addr + + .finding TCP options + -------------------- +-filter input tcp option sack-permitted kind 1 counter ++filter input tcp option sack-perm kind 1 counter + -------------------- + + .matching IPv6 exthdr +diff --git a/src/parser_bison.y b/src/parser_bison.y +index 4cca31b..56d26e3 100644 +--- a/src/parser_bison.y ++++ b/src/parser_bison.y +@@ -221,7 +221,6 @@ int nft_lex(void *, void *, void *); + %token SYNPROXY "synproxy" + %token MSS "mss" + %token WSCALE "wscale" +-%token SACKPERM "sack-perm" + + %token HOOK "hook" + %token DEVICE "device" +@@ -385,14 +384,13 @@ int nft_lex(void *, void *, void *); + %token OPTION "option" + %token ECHO "echo" + %token EOL "eol" +-%token MAXSEG "maxseg" + %token NOOP "noop" + %token SACK "sack" + %token SACK0 "sack0" + %token SACK1 "sack1" + %token SACK2 "sack2" + %token SACK3 "sack3" +-%token SACK_PERMITTED "sack-permitted" ++%token SACK_PERM "sack-permitted" + %token TIMESTAMP "timestamp" + %token KIND "kind" + %token COUNT "count" +@@ -2889,7 +2887,7 @@ synproxy_arg : MSS NUM + { + $0->synproxy.flags |= NF_SYNPROXY_OPT_TIMESTAMP; + } +- | SACKPERM ++ | SACK_PERM + { + $0->synproxy.flags |= NF_SYNPROXY_OPT_SACK_PERM; + } +@@ -2944,7 +2942,7 @@ synproxy_ts : /* empty */ { $$ = 0; } + ; + + synproxy_sack : /* empty */ { $$ = 0; } +- | SACKPERM ++ | SACK_PERM + { + $$ = NF_SYNPROXY_OPT_SACK_PERM; + } +@@ -4736,9 +4734,9 @@ tcp_hdr_field : SPORT { $$ = TCPHDR_SPORT; } + + tcp_hdr_option_type : EOL { $$ = TCPOPTHDR_EOL; } + | NOOP { $$ = TCPOPTHDR_NOOP; } +- | MAXSEG { $$ = TCPOPTHDR_MAXSEG; } ++ | MSS { $$ = TCPOPTHDR_MAXSEG; } + | WINDOW { $$ = TCPOPTHDR_WINDOW; } +- | SACK_PERMITTED { $$ = TCPOPTHDR_SACK_PERMITTED; } ++ | SACK_PERM { $$ = TCPOPTHDR_SACK_PERMITTED; } + | SACK { $$ = TCPOPTHDR_SACK0; } + | SACK0 { $$ = TCPOPTHDR_SACK0; } + | SACK1 { $$ = TCPOPTHDR_SACK1; } +diff --git a/src/scanner.l b/src/scanner.l +index 7daf5c1..a369802 100644 +--- a/src/scanner.l ++++ b/src/scanner.l +@@ -419,14 +419,16 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr}) + + "echo" { return ECHO; } + "eol" { return EOL; } +-"maxseg" { return MAXSEG; } ++"maxseg" { return MSS; } ++"mss" { return MSS; } + "noop" { return NOOP; } + "sack" { return SACK; } + "sack0" { return SACK0; } + "sack1" { return SACK1; } + "sack2" { return SACK2; } + "sack3" { return SACK3; } +-"sack-permitted" { return SACK_PERMITTED; } ++"sack-permitted" { return SACK_PERM; } ++"sack-perm" { return SACK_PERM; } + "timestamp" { return TIMESTAMP; } + "time" { return TIME; } + +@@ -562,9 +564,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr}) + "osf" { return OSF; } + + "synproxy" { return SYNPROXY; } +-"mss" { return MSS; } + "wscale" { return WSCALE; } +-"sack-perm" { return SACKPERM; } + + "notrack" { return NOTRACK; } + +diff --git a/src/tcpopt.c b/src/tcpopt.c +index ec305d9..6dbaa9e 100644 +--- a/src/tcpopt.c ++++ b/src/tcpopt.c +@@ -55,7 +55,7 @@ static const struct exthdr_desc tcpopt_window = { + }; + + static const struct exthdr_desc tcpopt_sack_permitted = { +- .name = "sack-permitted", ++ .name = "sack-perm", + .type = TCPOPT_SACK_PERMITTED, + .templates = { + [TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8), +diff --git a/tests/py/any/tcpopt.t b/tests/py/any/tcpopt.t +index 08b1dcb..5f21d49 100644 +--- a/tests/py/any/tcpopt.t ++++ b/tests/py/any/tcpopt.t +@@ -12,8 +12,8 @@ tcp option maxseg size 1;ok + tcp option window kind 1;ok + tcp option window length 1;ok + tcp option window count 1;ok +-tcp option sack-permitted kind 1;ok +-tcp option sack-permitted length 1;ok ++tcp option sack-perm kind 1;ok ++tcp option sack-perm length 1;ok + tcp option sack kind 1;ok + tcp option sack length 1;ok + tcp option sack left 1;ok +diff --git a/tests/py/any/tcpopt.t.json b/tests/py/any/tcpopt.t.json +index 48eb339..2c6236a 100644 +--- a/tests/py/any/tcpopt.t.json ++++ b/tests/py/any/tcpopt.t.json +@@ -126,14 +126,14 @@ + } + ] + +-# tcp option sack-permitted kind 1 ++# tcp option sack-perm kind 1 + [ + { + "match": { + "left": { + "tcp option": { + "field": "kind", +- "name": "sack-permitted" ++ "name": "sack-perm" + } + }, + "op": "==", +@@ -142,14 +142,14 @@ + } + ] + +-# tcp option sack-permitted length 1 ++# tcp option sack-perm length 1 + [ + { + "match": { + "left": { + "tcp option": { + "field": "length", +- "name": "sack-permitted" ++ "name": "sack-perm" + } + }, + "op": "==", +diff --git a/tests/py/any/tcpopt.t.payload b/tests/py/any/tcpopt.t.payload +index 63751cf..f63076a 100644 +--- a/tests/py/any/tcpopt.t.payload ++++ b/tests/py/any/tcpopt.t.payload +@@ -166,42 +166,42 @@ inet + [ exthdr load tcpopt 1b @ 3 + 2 => reg 1 ] + [ cmp eq reg 1 0x00000001 ] + +-# tcp option sack-permitted kind 1 ++# tcp option sack-perm kind 1 + ip + [ meta load l4proto => reg 1 ] + [ cmp eq reg 1 0x00000006 ] + [ exthdr load tcpopt 1b @ 4 + 0 => reg 1 ] + [ cmp eq reg 1 0x00000001 ] + +-# tcp option sack-permitted kind 1 ++# tcp option sack-perm kind 1 + ip6 + [ meta load l4proto => reg 1 ] + [ cmp eq reg 1 0x00000006 ] + [ exthdr load tcpopt 1b @ 4 + 0 => reg 1 ] + [ cmp eq reg 1 0x00000001 ] + +-# tcp option sack-permitted kind 1 ++# tcp option sack-perm kind 1 + inet + [ meta load l4proto => reg 1 ] + [ cmp eq reg 1 0x00000006 ] + [ exthdr load tcpopt 1b @ 4 + 0 => reg 1 ] + [ cmp eq reg 1 0x00000001 ] + +-# tcp option sack-permitted length 1 ++# tcp option sack-perm length 1 + ip + [ meta load l4proto => reg 1 ] + [ cmp eq reg 1 0x00000006 ] + [ exthdr load tcpopt 1b @ 4 + 1 => reg 1 ] + [ cmp eq reg 1 0x00000001 ] + +-# tcp option sack-permitted length 1 ++# tcp option sack-perm length 1 + ip6 + [ meta load l4proto => reg 1 ] + [ cmp eq reg 1 0x00000006 ] + [ exthdr load tcpopt 1b @ 4 + 1 => reg 1 ] + [ cmp eq reg 1 0x00000001 ] + +-# tcp option sack-permitted length 1 ++# tcp option sack-perm length 1 + inet + [ meta load l4proto => reg 1 ] + [ cmp eq reg 1 0x00000006 ] +-- +2.31.1 + diff --git a/SOURCES/0050-tcpopts-clean-up-parser-tcpopt.c-plumbing.patch b/SOURCES/0050-tcpopts-clean-up-parser-tcpopt.c-plumbing.patch new file mode 100644 index 0000000..5598b1a --- /dev/null +++ b/SOURCES/0050-tcpopts-clean-up-parser-tcpopt.c-plumbing.patch @@ -0,0 +1,387 @@ +From 0aa694acf7c233f9426e48d0644b29ddec4fb16d Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Mon, 12 Jul 2021 17:44:08 +0200 +Subject: [PATCH] tcpopts: clean up parser -> tcpopt.c plumbing + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1979334 +Upstream Status: nftables commit 41158e0388ac5 + +commit 41158e0388ac56380fc0ee301f0d43f95ec43fab +Author: Florian Westphal +Date: Mon Nov 2 14:53:26 2020 +0100 + + tcpopts: clean up parser -> tcpopt.c plumbing + + tcpopt template mapping is asymmetric: + one mapping is to match dumped netlink exthdr expression to the original + tcp option template. + + This struct is indexed by the raw, on-write kind/type number. + + The other mapping maps parsed options to the tcp option template. + Remove the latter. The parser is changed to translate the textual + option name, e.g. "maxseg" to the on-wire number. + + This avoids the second mapping, it will also allow to more easily + support raw option matching in a followup patch. + + Signed-off-by: Florian Westphal +--- + doc/payload-expression.txt | 4 +- + include/tcpopt.h | 35 ++++++++------- + src/parser_bison.y | 26 +++++------ + src/parser_json.c | 10 ++--- + src/scanner.l | 3 +- + src/tcpopt.c | 92 +++++++++++++++----------------------- + 6 files changed, 75 insertions(+), 95 deletions(-) + +diff --git a/doc/payload-expression.txt b/doc/payload-expression.txt +index 3d7057c..27145c3 100644 +--- a/doc/payload-expression.txt ++++ b/doc/payload-expression.txt +@@ -525,13 +525,13 @@ nftables currently supports matching (finding) a given ipv6 extension header, TC + *dst* {*nexthdr* | *hdrlength*} + *mh* {*nexthdr* | *hdrlength* | *checksum* | *type*} + *srh* {*flags* | *tag* | *sid* | *seg-left*} +-*tcp option* {*eol* | *noop* | *maxseg* | *window* | *sack-perm* | *sack* | *sack0* | *sack1* | *sack2* | *sack3* | *timestamp*} 'tcp_option_field' ++*tcp option* {*eol* | *nop* | *maxseg* | *window* | *sack-perm* | *sack* | *sack0* | *sack1* | *sack2* | *sack3* | *timestamp*} 'tcp_option_field' + *ip option* { lsrr | ra | rr | ssrr } 'ip_option_field' + + The following syntaxes are valid only in a relational expression with boolean type on right-hand side for checking header existence only: + [verse] + *exthdr* {*hbh* | *frag* | *rt* | *dst* | *mh*} +-*tcp option* {*eol* | *noop* | *maxseg* | *window* | *sack-perm* | *sack* | *sack0* | *sack1* | *sack2* | *sack3* | *timestamp*} ++*tcp option* {*eol* | *nop* | *maxseg* | *window* | *sack-perm* | *sack* | *sack0* | *sack1* | *sack2* | *sack3* | *timestamp*} + *ip option* { lsrr | ra | rr | ssrr } + + .IPv6 extension headers +diff --git a/include/tcpopt.h b/include/tcpopt.h +index ffdbcb0..7f3fbb8 100644 +--- a/include/tcpopt.h ++++ b/include/tcpopt.h +@@ -6,7 +6,7 @@ + #include + + extern struct expr *tcpopt_expr_alloc(const struct location *loc, +- uint8_t type, uint8_t field); ++ unsigned int kind, unsigned int field); + + extern void tcpopt_init_raw(struct expr *expr, uint8_t type, + unsigned int offset, unsigned int len, +@@ -15,21 +15,22 @@ extern void tcpopt_init_raw(struct expr *expr, uint8_t type, + extern bool tcpopt_find_template(struct expr *expr, const struct expr *mask, + unsigned int *shift); + +-enum tcpopt_hdr_types { +- TCPOPTHDR_INVALID, +- TCPOPTHDR_EOL, +- TCPOPTHDR_NOOP, +- TCPOPTHDR_MAXSEG, +- TCPOPTHDR_WINDOW, +- TCPOPTHDR_SACK_PERMITTED, +- TCPOPTHDR_SACK0, +- TCPOPTHDR_SACK1, +- TCPOPTHDR_SACK2, +- TCPOPTHDR_SACK3, +- TCPOPTHDR_TIMESTAMP, +- TCPOPTHDR_ECHO, +- TCPOPTHDR_ECHO_REPLY, +- __TCPOPTHDR_MAX ++/* TCP option numbers used on wire */ ++enum tcpopt_kind { ++ TCPOPT_KIND_EOL = 0, ++ TCPOPT_KIND_NOP = 1, ++ TCPOPT_KIND_MAXSEG = 2, ++ TCPOPT_KIND_WINDOW = 3, ++ TCPOPT_KIND_SACK_PERMITTED = 4, ++ TCPOPT_KIND_SACK = 5, ++ TCPOPT_KIND_TIMESTAMP = 8, ++ TCPOPT_KIND_ECHO = 8, ++ __TCPOPT_KIND_MAX, ++ ++ /* extra oob info, internal to nft */ ++ TCPOPT_KIND_SACK1 = 256, ++ TCPOPT_KIND_SACK2 = 257, ++ TCPOPT_KIND_SACK3 = 258, + }; + + enum tcpopt_hdr_fields { +@@ -44,6 +45,6 @@ enum tcpopt_hdr_fields { + TCPOPTHDR_FIELD_TSECR, + }; + +-extern const struct exthdr_desc *tcpopthdr_protocols[__TCPOPTHDR_MAX]; ++extern const struct exthdr_desc *tcpopt_protocols[__TCPOPT_KIND_MAX]; + + #endif /* NFTABLES_TCPOPT_H */ +diff --git a/src/parser_bison.y b/src/parser_bison.y +index 56d26e3..8f77766 100644 +--- a/src/parser_bison.y ++++ b/src/parser_bison.y +@@ -384,7 +384,7 @@ int nft_lex(void *, void *, void *); + %token OPTION "option" + %token ECHO "echo" + %token EOL "eol" +-%token NOOP "noop" ++%token NOP "nop" + %token SACK "sack" + %token SACK0 "sack0" + %token SACK1 "sack1" +@@ -4732,18 +4732,18 @@ tcp_hdr_field : SPORT { $$ = TCPHDR_SPORT; } + | URGPTR { $$ = TCPHDR_URGPTR; } + ; + +-tcp_hdr_option_type : EOL { $$ = TCPOPTHDR_EOL; } +- | NOOP { $$ = TCPOPTHDR_NOOP; } +- | MSS { $$ = TCPOPTHDR_MAXSEG; } +- | WINDOW { $$ = TCPOPTHDR_WINDOW; } +- | SACK_PERM { $$ = TCPOPTHDR_SACK_PERMITTED; } +- | SACK { $$ = TCPOPTHDR_SACK0; } +- | SACK0 { $$ = TCPOPTHDR_SACK0; } +- | SACK1 { $$ = TCPOPTHDR_SACK1; } +- | SACK2 { $$ = TCPOPTHDR_SACK2; } +- | SACK3 { $$ = TCPOPTHDR_SACK3; } +- | ECHO { $$ = TCPOPTHDR_ECHO; } +- | TIMESTAMP { $$ = TCPOPTHDR_TIMESTAMP; } ++tcp_hdr_option_type : EOL { $$ = TCPOPT_KIND_EOL; } ++ | NOP { $$ = TCPOPT_KIND_NOP; } ++ | MSS { $$ = TCPOPT_KIND_MAXSEG; } ++ | WINDOW { $$ = TCPOPT_KIND_WINDOW; } ++ | SACK_PERM { $$ = TCPOPT_KIND_SACK_PERMITTED; } ++ | SACK { $$ = TCPOPT_KIND_SACK; } ++ | SACK0 { $$ = TCPOPT_KIND_SACK; } ++ | SACK1 { $$ = TCPOPT_KIND_SACK1; } ++ | SACK2 { $$ = TCPOPT_KIND_SACK2; } ++ | SACK3 { $$ = TCPOPT_KIND_SACK3; } ++ | ECHO { $$ = TCPOPT_KIND_ECHO; } ++ | TIMESTAMP { $$ = TCPOPT_KIND_TIMESTAMP; } + ; + + tcp_hdr_option_field : KIND { $$ = TCPOPTHDR_FIELD_KIND; } +diff --git a/src/parser_json.c b/src/parser_json.c +index 662bb4b..44b58a0 100644 +--- a/src/parser_json.c ++++ b/src/parser_json.c +@@ -456,9 +456,9 @@ static int json_parse_tcp_option_type(const char *name, int *val) + { + unsigned int i; + +- for (i = 0; i < array_size(tcpopthdr_protocols); i++) { +- if (tcpopthdr_protocols[i] && +- !strcmp(tcpopthdr_protocols[i]->name, name)) { ++ for (i = 0; i < array_size(tcpopt_protocols); i++) { ++ if (tcpopt_protocols[i] && ++ !strcmp(tcpopt_protocols[i]->name, name)) { + if (val) + *val = i; + return 0; +@@ -467,7 +467,7 @@ static int json_parse_tcp_option_type(const char *name, int *val) + /* special case for sack0 - sack3 */ + if (sscanf(name, "sack%u", &i) == 1 && i < 4) { + if (val) +- *val = TCPOPTHDR_SACK0 + i; ++ *val = TCPOPT_KIND_SACK + i; + return 0; + } + return 1; +@@ -476,7 +476,7 @@ static int json_parse_tcp_option_type(const char *name, int *val) + static int json_parse_tcp_option_field(int type, const char *name, int *val) + { + unsigned int i; +- const struct exthdr_desc *desc = tcpopthdr_protocols[type]; ++ const struct exthdr_desc *desc = tcpopt_protocols[type]; + + for (i = 0; i < array_size(desc->templates); i++) { + if (desc->templates[i].token && +diff --git a/src/scanner.l b/src/scanner.l +index a369802..20b1b2d 100644 +--- a/src/scanner.l ++++ b/src/scanner.l +@@ -421,7 +421,8 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr}) + "eol" { return EOL; } + "maxseg" { return MSS; } + "mss" { return MSS; } +-"noop" { return NOOP; } ++"nop" { return NOP; } ++"noop" { return NOP; } + "sack" { return SACK; } + "sack0" { return SACK0; } + "sack1" { return SACK1; } +diff --git a/src/tcpopt.c b/src/tcpopt.c +index 6dbaa9e..8d5bdec 100644 +--- a/src/tcpopt.c ++++ b/src/tcpopt.c +@@ -20,7 +20,7 @@ static const struct proto_hdr_template tcpopt_unknown_template = + __offset, __len) + static const struct exthdr_desc tcpopt_eol = { + .name = "eol", +- .type = TCPOPT_EOL, ++ .type = TCPOPT_KIND_EOL, + .templates = { + [TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8), + }, +@@ -28,7 +28,7 @@ static const struct exthdr_desc tcpopt_eol = { + + static const struct exthdr_desc tcpopt_nop = { + .name = "noop", +- .type = TCPOPT_NOP, ++ .type = TCPOPT_KIND_NOP, + .templates = { + [TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8), + }, +@@ -36,7 +36,7 @@ static const struct exthdr_desc tcpopt_nop = { + + static const struct exthdr_desc tcptopt_maxseg = { + .name = "maxseg", +- .type = TCPOPT_MAXSEG, ++ .type = TCPOPT_KIND_MAXSEG, + .templates = { + [TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8), + [TCPOPTHDR_FIELD_LENGTH] = PHT("length", 8, 8), +@@ -46,7 +46,7 @@ static const struct exthdr_desc tcptopt_maxseg = { + + static const struct exthdr_desc tcpopt_window = { + .name = "window", +- .type = TCPOPT_WINDOW, ++ .type = TCPOPT_KIND_WINDOW, + .templates = { + [TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8), + [TCPOPTHDR_FIELD_LENGTH] = PHT("length", 8, 8), +@@ -56,7 +56,7 @@ static const struct exthdr_desc tcpopt_window = { + + static const struct exthdr_desc tcpopt_sack_permitted = { + .name = "sack-perm", +- .type = TCPOPT_SACK_PERMITTED, ++ .type = TCPOPT_KIND_SACK_PERMITTED, + .templates = { + [TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8), + [TCPOPTHDR_FIELD_LENGTH] = PHT("length", 8, 8), +@@ -65,7 +65,7 @@ static const struct exthdr_desc tcpopt_sack_permitted = { + + static const struct exthdr_desc tcpopt_sack = { + .name = "sack", +- .type = TCPOPT_SACK, ++ .type = TCPOPT_KIND_SACK, + .templates = { + [TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8), + [TCPOPTHDR_FIELD_LENGTH] = PHT("length", 8, 8), +@@ -76,7 +76,7 @@ static const struct exthdr_desc tcpopt_sack = { + + static const struct exthdr_desc tcpopt_timestamp = { + .name = "timestamp", +- .type = TCPOPT_TIMESTAMP, ++ .type = TCPOPT_KIND_TIMESTAMP, + .templates = { + [TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8), + [TCPOPTHDR_FIELD_LENGTH] = PHT("length", 8, 8), +@@ -86,19 +86,14 @@ static const struct exthdr_desc tcpopt_timestamp = { + }; + #undef PHT + +-#define TCPOPT_OBSOLETE ((struct exthdr_desc *)NULL) +-#define TCPOPT_ECHO 6 +-#define TCPOPT_ECHO_REPLY 7 +-static const struct exthdr_desc *tcpopt_protocols[] = { +- [TCPOPT_EOL] = &tcpopt_eol, +- [TCPOPT_NOP] = &tcpopt_nop, +- [TCPOPT_MAXSEG] = &tcptopt_maxseg, +- [TCPOPT_WINDOW] = &tcpopt_window, +- [TCPOPT_SACK_PERMITTED] = &tcpopt_sack_permitted, +- [TCPOPT_SACK] = &tcpopt_sack, +- [TCPOPT_ECHO] = TCPOPT_OBSOLETE, +- [TCPOPT_ECHO_REPLY] = TCPOPT_OBSOLETE, +- [TCPOPT_TIMESTAMP] = &tcpopt_timestamp, ++const struct exthdr_desc *tcpopt_protocols[] = { ++ [TCPOPT_KIND_EOL] = &tcpopt_eol, ++ [TCPOPT_KIND_NOP] = &tcpopt_nop, ++ [TCPOPT_KIND_MAXSEG] = &tcptopt_maxseg, ++ [TCPOPT_KIND_WINDOW] = &tcpopt_window, ++ [TCPOPT_KIND_SACK_PERMITTED] = &tcpopt_sack_permitted, ++ [TCPOPT_KIND_SACK] = &tcpopt_sack, ++ [TCPOPT_KIND_TIMESTAMP] = &tcpopt_timestamp, + }; + + static unsigned int calc_offset(const struct exthdr_desc *desc, +@@ -136,51 +131,34 @@ static unsigned int calc_offset_reverse(const struct exthdr_desc *desc, + } + } + +-const struct exthdr_desc *tcpopthdr_protocols[__TCPOPTHDR_MAX] = { +- [TCPOPTHDR_EOL] = &tcpopt_eol, +- [TCPOPTHDR_NOOP] = &tcpopt_nop, +- [TCPOPTHDR_MAXSEG] = &tcptopt_maxseg, +- [TCPOPTHDR_WINDOW] = &tcpopt_window, +- [TCPOPTHDR_SACK_PERMITTED] = &tcpopt_sack_permitted, +- [TCPOPTHDR_SACK0] = &tcpopt_sack, +- [TCPOPTHDR_SACK1] = &tcpopt_sack, +- [TCPOPTHDR_SACK2] = &tcpopt_sack, +- [TCPOPTHDR_SACK3] = &tcpopt_sack, +- [TCPOPTHDR_ECHO] = TCPOPT_OBSOLETE, +- [TCPOPTHDR_ECHO_REPLY] = TCPOPT_OBSOLETE, +- [TCPOPTHDR_TIMESTAMP] = &tcpopt_timestamp, +-}; +- +-static uint8_t tcpopt_optnum[] = { +- [TCPOPTHDR_SACK0] = 0, +- [TCPOPTHDR_SACK1] = 1, +- [TCPOPTHDR_SACK2] = 2, +- [TCPOPTHDR_SACK3] = 3, +-}; +- +-static uint8_t tcpopt_find_optnum(uint8_t optnum) +-{ +- if (optnum > TCPOPTHDR_SACK3) +- return 0; +- +- return tcpopt_optnum[optnum]; +-} +- +-struct expr *tcpopt_expr_alloc(const struct location *loc, uint8_t type, +- uint8_t field) ++struct expr *tcpopt_expr_alloc(const struct location *loc, ++ unsigned int kind, ++ unsigned int field) + { + const struct proto_hdr_template *tmpl; + const struct exthdr_desc *desc; ++ uint8_t optnum = 0; + struct expr *expr; +- uint8_t optnum; + +- desc = tcpopthdr_protocols[type]; ++ switch (kind) { ++ case TCPOPT_KIND_SACK1: ++ kind = TCPOPT_KIND_SACK; ++ optnum = 1; ++ break; ++ case TCPOPT_KIND_SACK2: ++ kind = TCPOPT_KIND_SACK; ++ optnum = 2; ++ break; ++ case TCPOPT_KIND_SACK3: ++ kind = TCPOPT_KIND_SACK; ++ optnum = 3; ++ } ++ ++ desc = tcpopt_protocols[kind]; + tmpl = &desc->templates[field]; + if (!tmpl) + return NULL; + +- optnum = tcpopt_find_optnum(type); +- + expr = expr_alloc(loc, EXPR_EXTHDR, tmpl->dtype, + BYTEORDER_BIG_ENDIAN, tmpl->len); + expr->exthdr.desc = desc; +@@ -206,7 +184,7 @@ void tcpopt_init_raw(struct expr *expr, uint8_t type, unsigned int offset, + assert(type < array_size(tcpopt_protocols)); + expr->exthdr.desc = tcpopt_protocols[type]; + expr->exthdr.flags = flags; +- assert(expr->exthdr.desc != TCPOPT_OBSOLETE); ++ assert(expr->exthdr.desc != NULL); + + for (i = 0; i < array_size(expr->exthdr.desc->templates); ++i) { + tmpl = &expr->exthdr.desc->templates[i]; +-- +2.31.1 + diff --git a/SOURCES/0051-tcpopt-rename-noop-to-nop.patch b/SOURCES/0051-tcpopt-rename-noop-to-nop.patch new file mode 100644 index 0000000..8ca855a --- /dev/null +++ b/SOURCES/0051-tcpopt-rename-noop-to-nop.patch @@ -0,0 +1,118 @@ +From f4476f9428a79c5d6d8fe284f0da91c2d4177e66 Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Mon, 12 Jul 2021 17:44:08 +0200 +Subject: [PATCH] tcpopt: rename noop to nop + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1979334 +Upstream Status: nftables commit 8f591eba561ac + +commit 8f591eba561aceeef605283c693b659a708d1cd3 +Author: Florian Westphal +Date: Mon Nov 2 14:58:41 2020 +0100 + + tcpopt: rename noop to nop + + 'nop' is the tcp padding "option". "noop" is retained for compatibility + on parser side. + + Signed-off-by: Florian Westphal +--- + doc/payload-expression.txt | 4 ++-- + src/tcpopt.c | 2 +- + tests/py/any/tcpopt.t | 2 +- + tests/py/any/tcpopt.t.json | 4 ++-- + tests/py/any/tcpopt.t.payload | 16 +--------------- + 5 files changed, 7 insertions(+), 21 deletions(-) + +diff --git a/doc/payload-expression.txt b/doc/payload-expression.txt +index 27145c3..3a07321 100644 +--- a/doc/payload-expression.txt ++++ b/doc/payload-expression.txt +@@ -559,8 +559,8 @@ Segment Routing Header + |eol| + End if option list| + kind +-|noop| +-1 Byte TCP No-op options | ++|nop| ++1 Byte TCP Nop padding option | + kind + |maxseg| + TCP Maximum Segment Size| +diff --git a/src/tcpopt.c b/src/tcpopt.c +index 8d5bdec..17cb580 100644 +--- a/src/tcpopt.c ++++ b/src/tcpopt.c +@@ -27,7 +27,7 @@ static const struct exthdr_desc tcpopt_eol = { + }; + + static const struct exthdr_desc tcpopt_nop = { +- .name = "noop", ++ .name = "nop", + .type = TCPOPT_KIND_NOP, + .templates = { + [TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8), +diff --git a/tests/py/any/tcpopt.t b/tests/py/any/tcpopt.t +index 5f21d49..1d42de8 100644 +--- a/tests/py/any/tcpopt.t ++++ b/tests/py/any/tcpopt.t +@@ -5,7 +5,7 @@ + *inet;test-inet;input + + tcp option eol kind 1;ok +-tcp option noop kind 1;ok ++tcp option nop kind 1;ok + tcp option maxseg kind 1;ok + tcp option maxseg length 1;ok + tcp option maxseg size 1;ok +diff --git a/tests/py/any/tcpopt.t.json b/tests/py/any/tcpopt.t.json +index 2c6236a..b15e36e 100644 +--- a/tests/py/any/tcpopt.t.json ++++ b/tests/py/any/tcpopt.t.json +@@ -14,14 +14,14 @@ + } + ] + +-# tcp option noop kind 1 ++# tcp option nop kind 1 + [ + { + "match": { + "left": { + "tcp option": { + "field": "kind", +- "name": "noop" ++ "name": "nop" + } + }, + "op": "==", +diff --git a/tests/py/any/tcpopt.t.payload b/tests/py/any/tcpopt.t.payload +index f63076a..9c480c8 100644 +--- a/tests/py/any/tcpopt.t.payload ++++ b/tests/py/any/tcpopt.t.payload +@@ -19,21 +19,7 @@ inet + [ exthdr load tcpopt 1b @ 0 + 0 => reg 1 ] + [ cmp eq reg 1 0x00000001 ] + +-# tcp option noop kind 1 +-ip +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 1b @ 1 + 0 => reg 1 ] +- [ cmp eq reg 1 0x00000001 ] +- +-# tcp option noop kind 1 +-ip6 +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 1b @ 1 + 0 => reg 1 ] +- [ cmp eq reg 1 0x00000001 ] +- +-# tcp option noop kind 1 ++# tcp option nop kind 1 + inet + [ meta load l4proto => reg 1 ] + [ cmp eq reg 1 0x00000006 ] +-- +2.31.1 + diff --git a/SOURCES/0052-tcpopt-split-tcpopt_hdr_fields-into-per-option-enum.patch b/SOURCES/0052-tcpopt-split-tcpopt_hdr_fields-into-per-option-enum.patch new file mode 100644 index 0000000..22dd1c1 --- /dev/null +++ b/SOURCES/0052-tcpopt-split-tcpopt_hdr_fields-into-per-option-enum.patch @@ -0,0 +1,538 @@ +From 9697436145bf374093dc61e3ad857f7122de08ee Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Mon, 12 Jul 2021 17:44:08 +0200 +Subject: [PATCH] tcpopt: split tcpopt_hdr_fields into per-option enum + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1979334 +Upstream Status: nftables commit 2e1f821d713aa + +commit 2e1f821d713aa44717b38901ee80cac8e2aa0335 +Author: Florian Westphal +Date: Mon Nov 2 15:22:40 2020 +0100 + + tcpopt: split tcpopt_hdr_fields into per-option enum + + Currently we're limited to ten template fields in exthdr_desc struct. + Using a single enum for all tpc option fields thus won't work + indefinitely (TCPOPTHDR_FIELD_TSECR is 9) when new option templates get + added. + + Fortunately we can just use one enum per tcp option to avoid this. + As a side effect this also allows to simplify the sack offset + calculations. Rather than computing that on-the-fly, just add extra + fields to the SACK template. + + expr->exthdr.offset now holds the 'raw' value, filled in from the option + template. This would ease implementation of 'raw option matching' + using offset and length to load from the option. + + Signed-off-by: Florian Westphal +--- + include/tcpopt.h | 46 +++++++++++---- + src/evaluate.c | 16 ++--- + src/exthdr.c | 1 + + src/ipopt.c | 2 +- + src/netlink_delinearize.c | 2 +- + src/netlink_linearize.c | 4 +- + src/parser_bison.y | 18 +++--- + src/parser_json.c | 36 ++++++++++-- + src/tcpopt.c | 119 ++++++++++++++++---------------------- + 9 files changed, 139 insertions(+), 105 deletions(-) + +diff --git a/include/tcpopt.h b/include/tcpopt.h +index 7f3fbb8..667c8a7 100644 +--- a/include/tcpopt.h ++++ b/include/tcpopt.h +@@ -33,16 +33,42 @@ enum tcpopt_kind { + TCPOPT_KIND_SACK3 = 258, + }; + +-enum tcpopt_hdr_fields { +- TCPOPTHDR_FIELD_INVALID, +- TCPOPTHDR_FIELD_KIND, +- TCPOPTHDR_FIELD_LENGTH, +- TCPOPTHDR_FIELD_SIZE, +- TCPOPTHDR_FIELD_COUNT, +- TCPOPTHDR_FIELD_LEFT, +- TCPOPTHDR_FIELD_RIGHT, +- TCPOPTHDR_FIELD_TSVAL, +- TCPOPTHDR_FIELD_TSECR, ++/* Internal identifiers */ ++enum tcpopt_common { ++ TCPOPT_COMMON_KIND, ++ TCPOPT_COMMON_LENGTH, ++}; ++ ++enum tcpopt_maxseg { ++ TCPOPT_MAXSEG_KIND, ++ TCPOPT_MAXSEG_LENGTH, ++ TCPOPT_MAXSEG_SIZE, ++}; ++ ++enum tcpopt_timestamp { ++ TCPOPT_TS_KIND, ++ TCPOPT_TS_LENGTH, ++ TCPOPT_TS_TSVAL, ++ TCPOPT_TS_TSECR, ++}; ++ ++enum tcpopt_windowscale { ++ TCPOPT_WINDOW_KIND, ++ TCPOPT_WINDOW_LENGTH, ++ TCPOPT_WINDOW_COUNT, ++}; ++ ++enum tcpopt_hdr_field_sack { ++ TCPOPT_SACK_KIND, ++ TCPOPT_SACK_LENGTH, ++ TCPOPT_SACK_LEFT, ++ TCPOPT_SACK_RIGHT, ++ TCPOPT_SACK_LEFT1, ++ TCPOPT_SACK_RIGHT1, ++ TCPOPT_SACK_LEFT2, ++ TCPOPT_SACK_RIGHT2, ++ TCPOPT_SACK_LEFT3, ++ TCPOPT_SACK_RIGHT3, + }; + + extern const struct exthdr_desc *tcpopt_protocols[__TCPOPT_KIND_MAX]; +diff --git a/src/evaluate.c b/src/evaluate.c +index 0181750..99a66c2 100644 +--- a/src/evaluate.c ++++ b/src/evaluate.c +@@ -474,7 +474,7 @@ static void expr_evaluate_bits(struct eval_ctx *ctx, struct expr **exprp) + &extra_len); + break; + case EXPR_EXTHDR: +- shift = expr_offset_shift(expr, expr->exthdr.tmpl->offset, ++ shift = expr_offset_shift(expr, expr->exthdr.offset, + &extra_len); + break; + default: +@@ -526,18 +526,16 @@ static int __expr_evaluate_exthdr(struct eval_ctx *ctx, struct expr **exprp) + if (expr_evaluate_primary(ctx, exprp) < 0) + return -1; + +- if (expr->exthdr.tmpl->offset % BITS_PER_BYTE != 0 || ++ if (expr->exthdr.offset % BITS_PER_BYTE != 0 || + expr->len % BITS_PER_BYTE != 0) + expr_evaluate_bits(ctx, exprp); + + switch (expr->exthdr.op) { + case NFT_EXTHDR_OP_TCPOPT: { + static const unsigned int max_tcpoptlen = (15 * 4 - 20) * BITS_PER_BYTE; +- unsigned int totlen = 0; ++ unsigned int totlen; + +- totlen += expr->exthdr.tmpl->offset; +- totlen += expr->exthdr.tmpl->len; +- totlen += expr->exthdr.offset; ++ totlen = expr->exthdr.tmpl->len + expr->exthdr.offset; + + if (totlen > max_tcpoptlen) + return expr_error(ctx->msgs, expr, +@@ -547,11 +545,9 @@ static int __expr_evaluate_exthdr(struct eval_ctx *ctx, struct expr **exprp) + } + case NFT_EXTHDR_OP_IPV4: { + static const unsigned int max_ipoptlen = 40 * BITS_PER_BYTE; +- unsigned int totlen = 0; ++ unsigned int totlen; + +- totlen += expr->exthdr.tmpl->offset; +- totlen += expr->exthdr.tmpl->len; +- totlen += expr->exthdr.offset; ++ totlen = expr->exthdr.offset + expr->exthdr.tmpl->len; + + if (totlen > max_ipoptlen) + return expr_error(ctx->msgs, expr, +diff --git a/src/exthdr.c b/src/exthdr.c +index e1ec6f3..c28213f 100644 +--- a/src/exthdr.c ++++ b/src/exthdr.c +@@ -99,6 +99,7 @@ struct expr *exthdr_expr_alloc(const struct location *loc, + BYTEORDER_BIG_ENDIAN, tmpl->len); + expr->exthdr.desc = desc; + expr->exthdr.tmpl = tmpl; ++ expr->exthdr.offset = tmpl->offset; + return expr; + } + +diff --git a/src/ipopt.c b/src/ipopt.c +index b3d0279..7ecb8b9 100644 +--- a/src/ipopt.c ++++ b/src/ipopt.c +@@ -102,7 +102,7 @@ struct expr *ipopt_expr_alloc(const struct location *loc, uint8_t type, + expr->exthdr.desc = desc; + expr->exthdr.tmpl = tmpl; + expr->exthdr.op = NFT_EXTHDR_OP_IPV4; +- expr->exthdr.offset = calc_offset(desc, tmpl, ptr); ++ expr->exthdr.offset = tmpl->offset + calc_offset(desc, tmpl, ptr); + + return expr; + } +diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c +index 157a473..790336a 100644 +--- a/src/netlink_delinearize.c ++++ b/src/netlink_delinearize.c +@@ -727,8 +727,8 @@ static void netlink_parse_numgen(struct netlink_parse_ctx *ctx, + const struct location *loc, + const struct nftnl_expr *nle) + { +- enum nft_registers dreg; + uint32_t type, until, offset; ++ enum nft_registers dreg; + struct expr *expr; + + type = nftnl_expr_get_u32(nle, NFTNL_EXPR_NG_TYPE); +diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c +index 25be634..9d1a064 100644 +--- a/src/netlink_linearize.c ++++ b/src/netlink_linearize.c +@@ -168,7 +168,7 @@ static void netlink_gen_exthdr(struct netlink_linearize_ctx *ctx, + const struct expr *expr, + enum nft_registers dreg) + { +- unsigned int offset = expr->exthdr.tmpl->offset + expr->exthdr.offset; ++ unsigned int offset = expr->exthdr.offset; + struct nftnl_expr *nle; + + nle = alloc_nft_expr("exthdr"); +@@ -896,7 +896,7 @@ static void netlink_gen_exthdr_stmt(struct netlink_linearize_ctx *ctx, + + expr = stmt->exthdr.expr; + +- offset = expr->exthdr.tmpl->offset + expr->exthdr.offset; ++ offset = expr->exthdr.offset; + + nle = alloc_nft_expr("exthdr"); + netlink_put_register(nle, NFTNL_EXPR_EXTHDR_SREG, sreg); +diff --git a/src/parser_bison.y b/src/parser_bison.y +index 8f77766..114b289 100644 +--- a/src/parser_bison.y ++++ b/src/parser_bison.y +@@ -4715,7 +4715,7 @@ tcp_hdr_expr : TCP tcp_hdr_field + } + | TCP OPTION tcp_hdr_option_type + { +- $$ = tcpopt_expr_alloc(&@$, $3, TCPOPTHDR_FIELD_KIND); ++ $$ = tcpopt_expr_alloc(&@$, $3, TCPOPT_COMMON_KIND); + $$->exthdr.flags = NFT_EXTHDR_F_PRESENT; + } + ; +@@ -4746,14 +4746,14 @@ tcp_hdr_option_type : EOL { $$ = TCPOPT_KIND_EOL; } + | TIMESTAMP { $$ = TCPOPT_KIND_TIMESTAMP; } + ; + +-tcp_hdr_option_field : KIND { $$ = TCPOPTHDR_FIELD_KIND; } +- | LENGTH { $$ = TCPOPTHDR_FIELD_LENGTH; } +- | SIZE { $$ = TCPOPTHDR_FIELD_SIZE; } +- | COUNT { $$ = TCPOPTHDR_FIELD_COUNT; } +- | LEFT { $$ = TCPOPTHDR_FIELD_LEFT; } +- | RIGHT { $$ = TCPOPTHDR_FIELD_RIGHT; } +- | TSVAL { $$ = TCPOPTHDR_FIELD_TSVAL; } +- | TSECR { $$ = TCPOPTHDR_FIELD_TSECR; } ++tcp_hdr_option_field : KIND { $$ = TCPOPT_COMMON_KIND; } ++ | LENGTH { $$ = TCPOPT_COMMON_LENGTH; } ++ | SIZE { $$ = TCPOPT_MAXSEG_SIZE; } ++ | COUNT { $$ = TCPOPT_WINDOW_COUNT; } ++ | LEFT { $$ = TCPOPT_SACK_LEFT; } ++ | RIGHT { $$ = TCPOPT_SACK_RIGHT; } ++ | TSVAL { $$ = TCPOPT_TS_TSVAL; } ++ | TSECR { $$ = TCPOPT_TS_TSECR; } + ; + + dccp_hdr_expr : DCCP dccp_hdr_field +diff --git a/src/parser_json.c b/src/parser_json.c +index 44b58a0..ab2375f 100644 +--- a/src/parser_json.c ++++ b/src/parser_json.c +@@ -466,8 +466,10 @@ static int json_parse_tcp_option_type(const char *name, int *val) + } + /* special case for sack0 - sack3 */ + if (sscanf(name, "sack%u", &i) == 1 && i < 4) { +- if (val) +- *val = TCPOPT_KIND_SACK + i; ++ if (val && i == 0) ++ *val = TCPOPT_KIND_SACK; ++ else if (val && i > 0) ++ *val = TCPOPT_KIND_SACK1 + i - 1; + return 0; + } + return 1; +@@ -475,12 +477,38 @@ static int json_parse_tcp_option_type(const char *name, int *val) + + static int json_parse_tcp_option_field(int type, const char *name, int *val) + { ++ const struct exthdr_desc *desc; ++ unsigned int block = 0; + unsigned int i; +- const struct exthdr_desc *desc = tcpopt_protocols[type]; ++ ++ switch (type) { ++ case TCPOPT_KIND_SACK1: ++ type = TCPOPT_KIND_SACK; ++ block = 1; ++ break; ++ case TCPOPT_KIND_SACK2: ++ type = TCPOPT_KIND_SACK; ++ block = 2; ++ break; ++ case TCPOPT_KIND_SACK3: ++ type = TCPOPT_KIND_SACK; ++ block = 3; ++ break; ++ } ++ ++ if (type < 0 || type >= (int)array_size(tcpopt_protocols)) ++ return 1; ++ ++ desc = tcpopt_protocols[type]; + + for (i = 0; i < array_size(desc->templates); i++) { + if (desc->templates[i].token && + !strcmp(desc->templates[i].token, name)) { ++ if (block) { ++ block--; ++ continue; ++ } ++ + if (val) + *val = i; + return 0; +@@ -585,7 +613,7 @@ static struct expr *json_parse_tcp_option_expr(struct json_ctx *ctx, + + if (json_unpack(root, "{s:s}", "field", &field)) { + expr = tcpopt_expr_alloc(int_loc, descval, +- TCPOPTHDR_FIELD_KIND); ++ TCPOPT_COMMON_KIND); + expr->exthdr.flags = NFT_EXTHDR_F_PRESENT; + + return expr; +diff --git a/src/tcpopt.c b/src/tcpopt.c +index 17cb580..d1dd13b 100644 +--- a/src/tcpopt.c ++++ b/src/tcpopt.c +@@ -22,7 +22,7 @@ static const struct exthdr_desc tcpopt_eol = { + .name = "eol", + .type = TCPOPT_KIND_EOL, + .templates = { +- [TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8), ++ [TCPOPT_COMMON_KIND] = PHT("kind", 0, 8), + }, + }; + +@@ -30,7 +30,7 @@ static const struct exthdr_desc tcpopt_nop = { + .name = "nop", + .type = TCPOPT_KIND_NOP, + .templates = { +- [TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8), ++ [TCPOPT_COMMON_KIND] = PHT("kind", 0, 8), + }, + }; + +@@ -38,9 +38,9 @@ static const struct exthdr_desc tcptopt_maxseg = { + .name = "maxseg", + .type = TCPOPT_KIND_MAXSEG, + .templates = { +- [TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8), +- [TCPOPTHDR_FIELD_LENGTH] = PHT("length", 8, 8), +- [TCPOPTHDR_FIELD_SIZE] = PHT("size", 16, 16), ++ [TCPOPT_MAXSEG_KIND] = PHT("kind", 0, 8), ++ [TCPOPT_MAXSEG_LENGTH] = PHT("length", 8, 8), ++ [TCPOPT_MAXSEG_SIZE] = PHT("size", 16, 16), + }, + }; + +@@ -48,9 +48,9 @@ static const struct exthdr_desc tcpopt_window = { + .name = "window", + .type = TCPOPT_KIND_WINDOW, + .templates = { +- [TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8), +- [TCPOPTHDR_FIELD_LENGTH] = PHT("length", 8, 8), +- [TCPOPTHDR_FIELD_COUNT] = PHT("count", 16, 8), ++ [TCPOPT_WINDOW_KIND] = PHT("kind", 0, 8), ++ [TCPOPT_WINDOW_LENGTH] = PHT("length", 8, 8), ++ [TCPOPT_WINDOW_COUNT] = PHT("count", 16, 8), + }, + }; + +@@ -58,8 +58,8 @@ static const struct exthdr_desc tcpopt_sack_permitted = { + .name = "sack-perm", + .type = TCPOPT_KIND_SACK_PERMITTED, + .templates = { +- [TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8), +- [TCPOPTHDR_FIELD_LENGTH] = PHT("length", 8, 8), ++ [TCPOPT_COMMON_KIND] = PHT("kind", 0, 8), ++ [TCPOPT_COMMON_LENGTH] = PHT("length", 8, 8), + }, + }; + +@@ -67,10 +67,16 @@ static const struct exthdr_desc tcpopt_sack = { + .name = "sack", + .type = TCPOPT_KIND_SACK, + .templates = { +- [TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8), +- [TCPOPTHDR_FIELD_LENGTH] = PHT("length", 8, 8), +- [TCPOPTHDR_FIELD_LEFT] = PHT("left", 16, 32), +- [TCPOPTHDR_FIELD_RIGHT] = PHT("right", 48, 32), ++ [TCPOPT_SACK_KIND] = PHT("kind", 0, 8), ++ [TCPOPT_SACK_LENGTH] = PHT("length", 8, 8), ++ [TCPOPT_SACK_LEFT] = PHT("left", 16, 32), ++ [TCPOPT_SACK_RIGHT] = PHT("right", 48, 32), ++ [TCPOPT_SACK_LEFT1] = PHT("left", 80, 32), ++ [TCPOPT_SACK_RIGHT1] = PHT("right", 112, 32), ++ [TCPOPT_SACK_LEFT2] = PHT("left", 144, 32), ++ [TCPOPT_SACK_RIGHT2] = PHT("right", 176, 32), ++ [TCPOPT_SACK_LEFT3] = PHT("left", 208, 32), ++ [TCPOPT_SACK_RIGHT3] = PHT("right", 240, 32), + }, + }; + +@@ -78,12 +84,13 @@ static const struct exthdr_desc tcpopt_timestamp = { + .name = "timestamp", + .type = TCPOPT_KIND_TIMESTAMP, + .templates = { +- [TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8), +- [TCPOPTHDR_FIELD_LENGTH] = PHT("length", 8, 8), +- [TCPOPTHDR_FIELD_TSVAL] = PHT("tsval", 16, 32), +- [TCPOPTHDR_FIELD_TSECR] = PHT("tsecr", 48, 32), ++ [TCPOPT_TS_KIND] = PHT("kind", 0, 8), ++ [TCPOPT_TS_LENGTH] = PHT("length", 8, 8), ++ [TCPOPT_TS_TSVAL] = PHT("tsval", 16, 32), ++ [TCPOPT_TS_TSECR] = PHT("tsecr", 48, 32), + }, + }; ++ + #undef PHT + + const struct exthdr_desc *tcpopt_protocols[] = { +@@ -96,65 +103,43 @@ const struct exthdr_desc *tcpopt_protocols[] = { + [TCPOPT_KIND_TIMESTAMP] = &tcpopt_timestamp, + }; + +-static unsigned int calc_offset(const struct exthdr_desc *desc, +- const struct proto_hdr_template *tmpl, +- unsigned int num) +-{ +- if (!desc || tmpl == &tcpopt_unknown_template) +- return 0; +- +- switch (desc->type) { +- case TCPOPT_SACK: +- /* Make sure, offset calculations only apply to left and right +- * fields +- */ +- return (tmpl->offset < 16) ? 0 : num * 64; +- default: +- return 0; +- } +-} +- +- +-static unsigned int calc_offset_reverse(const struct exthdr_desc *desc, +- const struct proto_hdr_template *tmpl, +- unsigned int offset) +-{ +- if (!desc || tmpl == &tcpopt_unknown_template) +- return offset; +- +- switch (desc->type) { +- case TCPOPT_SACK: +- /* We can safely ignore the first left/right field */ +- return offset < 80 ? offset : (offset % 64); +- default: +- return offset; +- } +-} +- + struct expr *tcpopt_expr_alloc(const struct location *loc, + unsigned int kind, + unsigned int field) + { + const struct proto_hdr_template *tmpl; +- const struct exthdr_desc *desc; +- uint8_t optnum = 0; ++ const struct exthdr_desc *desc = NULL; + struct expr *expr; + + switch (kind) { + case TCPOPT_KIND_SACK1: + kind = TCPOPT_KIND_SACK; +- optnum = 1; ++ if (field == TCPOPT_SACK_LEFT) ++ field = TCPOPT_SACK_LEFT1; ++ else if (field == TCPOPT_SACK_RIGHT) ++ field = TCPOPT_SACK_RIGHT1; + break; + case TCPOPT_KIND_SACK2: + kind = TCPOPT_KIND_SACK; +- optnum = 2; ++ if (field == TCPOPT_SACK_LEFT) ++ field = TCPOPT_SACK_LEFT2; ++ else if (field == TCPOPT_SACK_RIGHT) ++ field = TCPOPT_SACK_RIGHT2; + break; + case TCPOPT_KIND_SACK3: + kind = TCPOPT_KIND_SACK; +- optnum = 3; ++ if (field == TCPOPT_SACK_LEFT) ++ field = TCPOPT_SACK_LEFT3; ++ else if (field == TCPOPT_SACK_RIGHT) ++ field = TCPOPT_SACK_RIGHT3; ++ break; + } + +- desc = tcpopt_protocols[kind]; ++ if (kind < array_size(tcpopt_protocols)) ++ desc = tcpopt_protocols[kind]; ++ ++ if (!desc) ++ return NULL; + tmpl = &desc->templates[field]; + if (!tmpl) + return NULL; +@@ -164,34 +149,32 @@ struct expr *tcpopt_expr_alloc(const struct location *loc, + expr->exthdr.desc = desc; + expr->exthdr.tmpl = tmpl; + expr->exthdr.op = NFT_EXTHDR_OP_TCPOPT; +- expr->exthdr.offset = calc_offset(desc, tmpl, optnum); ++ expr->exthdr.offset = tmpl->offset; + + return expr; + } + +-void tcpopt_init_raw(struct expr *expr, uint8_t type, unsigned int offset, ++void tcpopt_init_raw(struct expr *expr, uint8_t type, unsigned int off, + unsigned int len, uint32_t flags) + { + const struct proto_hdr_template *tmpl; +- unsigned int i, off; ++ unsigned int i; + + assert(expr->etype == EXPR_EXTHDR); + + expr->len = len; + expr->exthdr.flags = flags; +- expr->exthdr.offset = offset; ++ expr->exthdr.offset = off; ++ ++ if (type >= array_size(tcpopt_protocols)) ++ return; + +- assert(type < array_size(tcpopt_protocols)); + expr->exthdr.desc = tcpopt_protocols[type]; + expr->exthdr.flags = flags; + assert(expr->exthdr.desc != NULL); + + for (i = 0; i < array_size(expr->exthdr.desc->templates); ++i) { + tmpl = &expr->exthdr.desc->templates[i]; +- /* We have to reverse calculate the offset for the sack options +- * at this point +- */ +- off = calc_offset_reverse(expr->exthdr.desc, tmpl, offset); + if (tmpl->offset != off || tmpl->len != len) + continue; + +-- +2.31.1 + diff --git a/SOURCES/0053-tcpopt-allow-to-check-for-presence-of-any-tcp-option.patch b/SOURCES/0053-tcpopt-allow-to-check-for-presence-of-any-tcp-option.patch new file mode 100644 index 0000000..6c7f7ed --- /dev/null +++ b/SOURCES/0053-tcpopt-allow-to-check-for-presence-of-any-tcp-option.patch @@ -0,0 +1,336 @@ +From 8a4b6cbf58e965d67b0337ba1736bd3691a49890 Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Mon, 12 Jul 2021 17:44:08 +0200 +Subject: [PATCH] tcpopt: allow to check for presence of any tcp option + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1979334 +Upstream Status: nftables commit 24d8da3083422 + +commit 24d8da3083422da8336eeed2ee23b2ccf598ba5a +Author: Florian Westphal +Date: Wed Oct 21 23:54:17 2020 +0200 + + tcpopt: allow to check for presence of any tcp option + + nft currently doesn't allow to check for presence of arbitrary tcp options. + Only known options where nft provides a template can be tested for. + + This allows to test for presence of raw protocol values as well. + + Example: + + tcp option 42 exists + + Signed-off-by: Florian Westphal +--- + include/expression.h | 3 +- + src/exthdr.c | 12 ++++++++ + src/ipopt.c | 1 + + src/netlink_linearize.c | 2 +- + src/parser_bison.y | 7 +++++ + src/tcpopt.c | 42 +++++++++++++++++++++++---- + tests/py/any/tcpopt.t | 2 ++ + tests/py/any/tcpopt.t.payload | 53 +++-------------------------------- + 8 files changed, 65 insertions(+), 57 deletions(-) + +diff --git a/include/expression.h b/include/expression.h +index 2e41aa0..b50183d 100644 +--- a/include/expression.h ++++ b/include/expression.h +@@ -299,7 +299,8 @@ struct expr { + /* EXPR_EXTHDR */ + const struct exthdr_desc *desc; + const struct proto_hdr_template *tmpl; +- unsigned int offset; ++ uint16_t offset; ++ uint8_t raw_type; + enum nft_exthdr_op op; + unsigned int flags; + } exthdr; +diff --git a/src/exthdr.c b/src/exthdr.c +index c28213f..68d5aa5 100644 +--- a/src/exthdr.c ++++ b/src/exthdr.c +@@ -32,6 +32,13 @@ static void exthdr_expr_print(const struct expr *expr, struct output_ctx *octx) + */ + unsigned int offset = expr->exthdr.offset / 64; + ++ if (expr->exthdr.desc == NULL && ++ expr->exthdr.offset == 0 && ++ expr->exthdr.flags & NFT_EXTHDR_F_PRESENT) { ++ nft_print(octx, "tcp option %d", expr->exthdr.raw_type); ++ return; ++ } ++ + nft_print(octx, "tcp option %s", expr->exthdr.desc->name); + if (expr->exthdr.flags & NFT_EXTHDR_F_PRESENT) + return; +@@ -59,6 +66,7 @@ static bool exthdr_expr_cmp(const struct expr *e1, const struct expr *e2) + return e1->exthdr.desc == e2->exthdr.desc && + e1->exthdr.tmpl == e2->exthdr.tmpl && + e1->exthdr.op == e2->exthdr.op && ++ e1->exthdr.raw_type == e2->exthdr.raw_type && + e1->exthdr.flags == e2->exthdr.flags; + } + +@@ -69,6 +77,7 @@ static void exthdr_expr_clone(struct expr *new, const struct expr *expr) + new->exthdr.offset = expr->exthdr.offset; + new->exthdr.op = expr->exthdr.op; + new->exthdr.flags = expr->exthdr.flags; ++ new->exthdr.raw_type = expr->exthdr.raw_type; + } + + const struct expr_ops exthdr_expr_ops = { +@@ -98,6 +107,7 @@ struct expr *exthdr_expr_alloc(const struct location *loc, + expr = expr_alloc(loc, EXPR_EXTHDR, tmpl->dtype, + BYTEORDER_BIG_ENDIAN, tmpl->len); + expr->exthdr.desc = desc; ++ expr->exthdr.raw_type = desc ? desc->type : 0; + expr->exthdr.tmpl = tmpl; + expr->exthdr.offset = tmpl->offset; + return expr; +@@ -176,6 +186,8 @@ void exthdr_init_raw(struct expr *expr, uint8_t type, + unsigned int i; + + assert(expr->etype == EXPR_EXTHDR); ++ expr->exthdr.raw_type = type; ++ + if (op == NFT_EXTHDR_OP_TCPOPT) + return tcpopt_init_raw(expr, type, offset, len, flags); + if (op == NFT_EXTHDR_OP_IPV4) +diff --git a/src/ipopt.c b/src/ipopt.c +index 7ecb8b9..5f9f908 100644 +--- a/src/ipopt.c ++++ b/src/ipopt.c +@@ -103,6 +103,7 @@ struct expr *ipopt_expr_alloc(const struct location *loc, uint8_t type, + expr->exthdr.tmpl = tmpl; + expr->exthdr.op = NFT_EXTHDR_OP_IPV4; + expr->exthdr.offset = tmpl->offset + calc_offset(desc, tmpl, ptr); ++ expr->exthdr.raw_type = desc->type; + + return expr; + } +diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c +index 9d1a064..28b0e6a 100644 +--- a/src/netlink_linearize.c ++++ b/src/netlink_linearize.c +@@ -174,7 +174,7 @@ static void netlink_gen_exthdr(struct netlink_linearize_ctx *ctx, + nle = alloc_nft_expr("exthdr"); + netlink_put_register(nle, NFTNL_EXPR_EXTHDR_DREG, dreg); + nftnl_expr_set_u8(nle, NFTNL_EXPR_EXTHDR_TYPE, +- expr->exthdr.desc->type); ++ expr->exthdr.raw_type); + nftnl_expr_set_u32(nle, NFTNL_EXPR_EXTHDR_OFFSET, offset / BITS_PER_BYTE); + nftnl_expr_set_u32(nle, NFTNL_EXPR_EXTHDR_LEN, + div_round_up(expr->len, BITS_PER_BYTE)); +diff --git a/src/parser_bison.y b/src/parser_bison.y +index 114b289..4ea9364 100644 +--- a/src/parser_bison.y ++++ b/src/parser_bison.y +@@ -4744,6 +4744,13 @@ tcp_hdr_option_type : EOL { $$ = TCPOPT_KIND_EOL; } + | SACK3 { $$ = TCPOPT_KIND_SACK3; } + | ECHO { $$ = TCPOPT_KIND_ECHO; } + | TIMESTAMP { $$ = TCPOPT_KIND_TIMESTAMP; } ++ | NUM { ++ if ($1 > 255) { ++ erec_queue(error(&@1, "value too large"), state->msgs); ++ YYERROR; ++ } ++ $$ = $1; ++ } + ; + + tcp_hdr_option_field : KIND { $$ = TCPOPT_COMMON_KIND; } +diff --git a/src/tcpopt.c b/src/tcpopt.c +index d1dd13b..1cf97a5 100644 +--- a/src/tcpopt.c ++++ b/src/tcpopt.c +@@ -103,6 +103,19 @@ const struct exthdr_desc *tcpopt_protocols[] = { + [TCPOPT_KIND_TIMESTAMP] = &tcpopt_timestamp, + }; + ++/** ++ * tcpopt_expr_alloc - allocate tcp option extension expression ++ * ++ * @loc: location from parser ++ * @kind: raw tcp option value to find in packet ++ * @field: highlevel field to find in the option if @kind is present in packet ++ * ++ * Allocate a new tcp option expression. ++ * @kind is the raw option value to find in the packet. ++ * Exception: SACK may use extra OOB data that is mangled here. ++ * ++ * @field is the optional field to extract from the @type option. ++ */ + struct expr *tcpopt_expr_alloc(const struct location *loc, + unsigned int kind, + unsigned int field) +@@ -138,8 +151,22 @@ struct expr *tcpopt_expr_alloc(const struct location *loc, + if (kind < array_size(tcpopt_protocols)) + desc = tcpopt_protocols[kind]; + +- if (!desc) +- return NULL; ++ if (!desc) { ++ if (field != TCPOPT_COMMON_KIND || kind > 255) ++ return NULL; ++ ++ expr = expr_alloc(loc, EXPR_EXTHDR, &integer_type, ++ BYTEORDER_BIG_ENDIAN, 8); ++ ++ desc = tcpopt_protocols[TCPOPT_NOP]; ++ tmpl = &desc->templates[field]; ++ expr->exthdr.desc = desc; ++ expr->exthdr.tmpl = tmpl; ++ expr->exthdr.op = NFT_EXTHDR_OP_TCPOPT; ++ expr->exthdr.raw_type = kind; ++ return expr; ++ } ++ + tmpl = &desc->templates[field]; + if (!tmpl) + return NULL; +@@ -149,6 +176,7 @@ struct expr *tcpopt_expr_alloc(const struct location *loc, + expr->exthdr.desc = desc; + expr->exthdr.tmpl = tmpl; + expr->exthdr.op = NFT_EXTHDR_OP_TCPOPT; ++ expr->exthdr.raw_type = desc->type; + expr->exthdr.offset = tmpl->offset; + + return expr; +@@ -165,6 +193,10 @@ void tcpopt_init_raw(struct expr *expr, uint8_t type, unsigned int off, + expr->len = len; + expr->exthdr.flags = flags; + expr->exthdr.offset = off; ++ expr->exthdr.op = NFT_EXTHDR_OP_TCPOPT; ++ ++ if (flags & NFT_EXTHDR_F_PRESENT) ++ datatype_set(expr, &boolean_type); + + if (type >= array_size(tcpopt_protocols)) + return; +@@ -178,12 +210,10 @@ void tcpopt_init_raw(struct expr *expr, uint8_t type, unsigned int off, + if (tmpl->offset != off || tmpl->len != len) + continue; + +- if (flags & NFT_EXTHDR_F_PRESENT) +- datatype_set(expr, &boolean_type); +- else ++ if ((flags & NFT_EXTHDR_F_PRESENT) == 0) + datatype_set(expr, tmpl->dtype); ++ + expr->exthdr.tmpl = tmpl; +- expr->exthdr.op = NFT_EXTHDR_OP_TCPOPT; + break; + } + } +diff --git a/tests/py/any/tcpopt.t b/tests/py/any/tcpopt.t +index 1d42de8..7b17014 100644 +--- a/tests/py/any/tcpopt.t ++++ b/tests/py/any/tcpopt.t +@@ -30,6 +30,7 @@ tcp option timestamp kind 1;ok + tcp option timestamp length 1;ok + tcp option timestamp tsval 1;ok + tcp option timestamp tsecr 1;ok ++tcp option 255 missing;ok + + tcp option foobar;fail + tcp option foo bar;fail +@@ -38,6 +39,7 @@ tcp option eol left 1;fail + tcp option eol left 1;fail + tcp option sack window;fail + tcp option sack window 1;fail ++tcp option 256 exists;fail + + tcp option window exists;ok + tcp option window missing;ok +diff --git a/tests/py/any/tcpopt.t.payload b/tests/py/any/tcpopt.t.payload +index 9c480c8..34f8e26 100644 +--- a/tests/py/any/tcpopt.t.payload ++++ b/tests/py/any/tcpopt.t.payload +@@ -509,20 +509,6 @@ inet + [ exthdr load tcpopt 4b @ 8 + 2 => reg 1 ] + [ cmp eq reg 1 0x01000000 ] + +-# tcp option timestamp tsecr 1 +-ip +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 4b @ 8 + 6 => reg 1 ] +- [ cmp eq reg 1 0x01000000 ] +- +-# tcp option timestamp tsecr 1 +-ip6 +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 4b @ 8 + 6 => reg 1 ] +- [ cmp eq reg 1 0x01000000 ] +- + # tcp option timestamp tsecr 1 + inet + [ meta load l4proto => reg 1 ] +@@ -530,19 +516,12 @@ inet + [ exthdr load tcpopt 4b @ 8 + 6 => reg 1 ] + [ cmp eq reg 1 0x01000000 ] + +-# tcp option window exists +-ip +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 1b @ 3 + 0 present => reg 1 ] +- [ cmp eq reg 1 0x00000001 ] +- +-# tcp option window exists +-ip6 ++# tcp option 255 missing ++inet + [ meta load l4proto => reg 1 ] + [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 1b @ 3 + 0 present => reg 1 ] +- [ cmp eq reg 1 0x00000001 ] ++ [ exthdr load tcpopt 1b @ 255 + 0 present => reg 1 ] ++ [ cmp eq reg 1 0x00000000 ] + + # tcp option window exists + inet +@@ -551,20 +530,6 @@ inet + [ exthdr load tcpopt 1b @ 3 + 0 present => reg 1 ] + [ cmp eq reg 1 0x00000001 ] + +-# tcp option window missing +-ip +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 1b @ 3 + 0 present => reg 1 ] +- [ cmp eq reg 1 0x00000000 ] +- +-# tcp option window missing +-ip6 +- [ meta load l4proto => reg 1 ] +- [ cmp eq reg 1 0x00000006 ] +- [ exthdr load tcpopt 1b @ 3 + 0 present => reg 1 ] +- [ cmp eq reg 1 0x00000000 ] +- + # tcp option window missing + inet + [ meta load l4proto => reg 1 ] +@@ -572,16 +537,6 @@ inet + [ exthdr load tcpopt 1b @ 3 + 0 present => reg 1 ] + [ cmp eq reg 1 0x00000000 ] + +-# tcp option maxseg size set 1360 +-ip +- [ immediate reg 1 0x00005005 ] +- [ exthdr write tcpopt reg 1 => 2b @ 2 + 2 ] +- +-# tcp option maxseg size set 1360 +-ip6 +- [ immediate reg 1 0x00005005 ] +- [ exthdr write tcpopt reg 1 => 2b @ 2 + 2 ] +- + # tcp option maxseg size set 1360 + inet + [ immediate reg 1 0x00005005 ] +-- +2.31.1 + diff --git a/SOURCES/0054-tcp-add-raw-tcp-option-match-support.patch b/SOURCES/0054-tcp-add-raw-tcp-option-match-support.patch new file mode 100644 index 0000000..e069466 --- /dev/null +++ b/SOURCES/0054-tcp-add-raw-tcp-option-match-support.patch @@ -0,0 +1,137 @@ +From 267d86b62132a009badd57b2ffcffed6ae682a1e Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Mon, 12 Jul 2021 17:44:08 +0200 +Subject: [PATCH] tcp: add raw tcp option match support + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1979334 +Upstream Status: nftables commit 881d8cb21c0b9 + +commit 881d8cb21c0b9168787b932f41b801593bde2216 +Author: Florian Westphal +Date: Mon Nov 2 20:10:25 2020 +0100 + + tcp: add raw tcp option match support + + tcp option @42,16,4 (@kind,offset,length). + + Signed-off-by: Florian Westphal +--- + doc/payload-expression.txt | 6 ++++++ + src/exthdr.c | 13 +++++++++---- + src/parser_bison.y | 5 +++++ + src/tcpopt.c | 2 ++ + tests/py/any/tcpopt.t | 2 ++ + tests/py/any/tcpopt.t.payload | 7 +++++++ + 6 files changed, 31 insertions(+), 4 deletions(-) + +diff --git a/doc/payload-expression.txt b/doc/payload-expression.txt +index 3a07321..b6d2a28 100644 +--- a/doc/payload-expression.txt ++++ b/doc/payload-expression.txt +@@ -591,6 +591,12 @@ TCP Timestamps | + kind, length, tsval, tsecr + |============================ + ++TCP option matching also supports raw expression syntax to access arbitrary options: ++[verse] ++*tcp option* ++[verse] ++*tcp option* *@*'number'*,*'offset'*,*'length' ++ + .IP Options + [options="header"] + |================== +diff --git a/src/exthdr.c b/src/exthdr.c +index 68d5aa5..5c75720 100644 +--- a/src/exthdr.c ++++ b/src/exthdr.c +@@ -32,10 +32,15 @@ static void exthdr_expr_print(const struct expr *expr, struct output_ctx *octx) + */ + unsigned int offset = expr->exthdr.offset / 64; + +- if (expr->exthdr.desc == NULL && +- expr->exthdr.offset == 0 && +- expr->exthdr.flags & NFT_EXTHDR_F_PRESENT) { +- nft_print(octx, "tcp option %d", expr->exthdr.raw_type); ++ if (expr->exthdr.desc == NULL) { ++ if (expr->exthdr.offset == 0 && ++ expr->exthdr.flags & NFT_EXTHDR_F_PRESENT) { ++ nft_print(octx, "tcp option %d", expr->exthdr.raw_type); ++ return; ++ } ++ ++ nft_print(octx, "tcp option @%u,%u,%u", expr->exthdr.raw_type, ++ expr->exthdr.offset, expr->len); + return; + } + +diff --git a/src/parser_bison.y b/src/parser_bison.y +index 4ea9364..5aedc55 100644 +--- a/src/parser_bison.y ++++ b/src/parser_bison.y +@@ -4718,6 +4718,11 @@ tcp_hdr_expr : TCP tcp_hdr_field + $$ = tcpopt_expr_alloc(&@$, $3, TCPOPT_COMMON_KIND); + $$->exthdr.flags = NFT_EXTHDR_F_PRESENT; + } ++ | TCP OPTION AT tcp_hdr_option_type COMMA NUM COMMA NUM ++ { ++ $$ = tcpopt_expr_alloc(&@$, $4, 0); ++ tcpopt_init_raw($$, $4, $6, $8, 0); ++ } + ; + + tcp_hdr_field : SPORT { $$ = TCPHDR_SPORT; } +diff --git a/src/tcpopt.c b/src/tcpopt.c +index 1cf97a5..05b5ee6 100644 +--- a/src/tcpopt.c ++++ b/src/tcpopt.c +@@ -197,6 +197,8 @@ void tcpopt_init_raw(struct expr *expr, uint8_t type, unsigned int off, + + if (flags & NFT_EXTHDR_F_PRESENT) + datatype_set(expr, &boolean_type); ++ else ++ datatype_set(expr, &integer_type); + + if (type >= array_size(tcpopt_protocols)) + return; +diff --git a/tests/py/any/tcpopt.t b/tests/py/any/tcpopt.t +index 7b17014..e759ac6 100644 +--- a/tests/py/any/tcpopt.t ++++ b/tests/py/any/tcpopt.t +@@ -31,6 +31,7 @@ tcp option timestamp length 1;ok + tcp option timestamp tsval 1;ok + tcp option timestamp tsecr 1;ok + tcp option 255 missing;ok ++tcp option @255,8,8 255;ok + + tcp option foobar;fail + tcp option foo bar;fail +@@ -40,6 +41,7 @@ tcp option eol left 1;fail + tcp option sack window;fail + tcp option sack window 1;fail + tcp option 256 exists;fail ++tcp option @255,8,8 256;fail + + tcp option window exists;ok + tcp option window missing;ok +diff --git a/tests/py/any/tcpopt.t.payload b/tests/py/any/tcpopt.t.payload +index 34f8e26..cddba61 100644 +--- a/tests/py/any/tcpopt.t.payload ++++ b/tests/py/any/tcpopt.t.payload +@@ -523,6 +523,13 @@ inet + [ exthdr load tcpopt 1b @ 255 + 0 present => reg 1 ] + [ cmp eq reg 1 0x00000000 ] + ++# tcp option @255,8,8 255 ++inet ++ [ meta load l4proto => reg 1 ] ++ [ cmp eq reg 1 0x00000006 ] ++ [ exthdr load tcpopt 1b @ 255 + 1 => reg 1 ] ++ [ cmp eq reg 1 0x000000ff ] ++ + # tcp option window exists + inet + [ meta load l4proto => reg 1 ] +-- +2.31.1 + diff --git a/SOURCES/0055-json-tcp-add-raw-tcp-option-match-support.patch b/SOURCES/0055-json-tcp-add-raw-tcp-option-match-support.patch new file mode 100644 index 0000000..324b5be --- /dev/null +++ b/SOURCES/0055-json-tcp-add-raw-tcp-option-match-support.patch @@ -0,0 +1,199 @@ +From ad566e27398e81ed803c4225179bb8df4718a2e9 Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Mon, 12 Jul 2021 17:44:08 +0200 +Subject: [PATCH] json: tcp: add raw tcp option match support + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1979334 +Upstream Status: nftables commit cb21869649208 + +commit cb21869649208118ed61354e2674858e4ff6c23c +Author: Florian Westphal +Date: Tue Nov 3 12:04:20 2020 +0100 + + json: tcp: add raw tcp option match support + + To similar change as in previous one, this time for the + jason (de)serialization. + + Re-uses the raw payload match syntax, i.e. base,offset,length. + + Signed-off-by: Florian Westphal +--- + src/json.c | 22 ++++++++-------- + src/parser_json.c | 52 ++++++++++++++++++++++++++------------ + tests/py/any/tcpopt.t.json | 34 +++++++++++++++++++++++++ + 3 files changed, 82 insertions(+), 26 deletions(-) + +diff --git a/src/json.c b/src/json.c +index 1906e7d..b77c6d2 100644 +--- a/src/json.c ++++ b/src/json.c +@@ -656,30 +656,32 @@ json_t *map_expr_json(const struct expr *expr, struct output_ctx *octx) + json_t *exthdr_expr_json(const struct expr *expr, struct output_ctx *octx) + { + const char *desc = expr->exthdr.desc ? +- expr->exthdr.desc->name : +- "unknown-exthdr"; ++ expr->exthdr.desc->name : NULL; + const char *field = expr->exthdr.tmpl->token; + json_t *root; + bool is_exists = expr->exthdr.flags & NFT_EXTHDR_F_PRESENT; + + if (expr->exthdr.op == NFT_EXTHDR_OP_TCPOPT) { ++ static const char *offstrs[] = { "", "1", "2", "3" }; + unsigned int offset = expr->exthdr.offset / 64; ++ const char *offstr = ""; + +- if (offset) { +- const char *offstrs[] = { "0", "1", "2", "3" }; +- const char *offstr = ""; +- ++ if (desc) { + if (offset < 4) + offstr = offstrs[offset]; + + root = json_pack("{s:s+}", "name", desc, offstr); ++ ++ if (!is_exists) ++ json_object_set_new(root, "field", json_string(field)); + } else { +- root = json_pack("{s:s}", "name", desc); ++ root = json_pack("{s:i, s:i, s:i}", ++ "base", expr->exthdr.raw_type, ++ "offset", expr->exthdr.offset, ++ "len", expr->len); ++ is_exists = false; + } + +- if (!is_exists) +- json_object_set_new(root, "field", json_string(field)); +- + return json_pack("{s:o}", "tcp option", root); + } + if (expr->exthdr.op == NFT_EXTHDR_OP_IPV4) { +diff --git a/src/parser_json.c b/src/parser_json.c +index ab2375f..fbf7db5 100644 +--- a/src/parser_json.c ++++ b/src/parser_json.c +@@ -500,6 +500,8 @@ static int json_parse_tcp_option_field(int type, const char *name, int *val) + return 1; + + desc = tcpopt_protocols[type]; ++ if (!desc) ++ return 1; + + for (i = 0; i < array_size(desc->templates); i++) { + if (desc->templates[i].token && +@@ -599,30 +601,48 @@ static struct expr *json_parse_payload_expr(struct json_ctx *ctx, + static struct expr *json_parse_tcp_option_expr(struct json_ctx *ctx, + const char *type, json_t *root) + { ++ int fieldval, kind, offset, len; + const char *desc, *field; +- int descval, fieldval; + struct expr *expr; + +- if (json_unpack_err(ctx, root, "{s:s}", "name", &desc)) +- return NULL; +- +- if (json_parse_tcp_option_type(desc, &descval)) { +- json_error(ctx, "Unknown tcp option name '%s'.", desc); +- return NULL; +- } ++ if (!json_unpack(root, "{s:i, s:i, s:i}", ++ "base", &kind, "offset", &offset, "len", &len)) { ++ uint32_t flag = 0; + +- if (json_unpack(root, "{s:s}", "field", &field)) { +- expr = tcpopt_expr_alloc(int_loc, descval, ++ expr = tcpopt_expr_alloc(int_loc, kind, + TCPOPT_COMMON_KIND); +- expr->exthdr.flags = NFT_EXTHDR_F_PRESENT; + ++ if (kind < 0 || kind > 255) ++ return NULL; ++ ++ if (offset == TCPOPT_COMMON_KIND && len == 8) ++ flag = NFT_EXTHDR_F_PRESENT; ++ ++ tcpopt_init_raw(expr, kind, offset, len, flag); + return expr; ++ } else if (!json_unpack(root, "{s:s}", "name", &desc)) { ++ if (json_parse_tcp_option_type(desc, &kind)) { ++ json_error(ctx, "Unknown tcp option name '%s'.", desc); ++ return NULL; ++ } ++ ++ if (json_unpack(root, "{s:s}", "field", &field)) { ++ expr = tcpopt_expr_alloc(int_loc, kind, ++ TCPOPT_COMMON_KIND); ++ expr->exthdr.flags = NFT_EXTHDR_F_PRESENT; ++ return expr; ++ } ++ ++ if (json_parse_tcp_option_field(kind, field, &fieldval)) { ++ json_error(ctx, "Unknown tcp option field '%s'.", field); ++ return NULL; ++ } ++ ++ return tcpopt_expr_alloc(int_loc, kind, fieldval); + } +- if (json_parse_tcp_option_field(descval, field, &fieldval)) { +- json_error(ctx, "Unknown tcp option field '%s'.", field); +- return NULL; +- } +- return tcpopt_expr_alloc(int_loc, descval, fieldval); ++ ++ json_error(ctx, "Invalid tcp option expression properties."); ++ return NULL; + } + + static int json_parse_ip_option_type(const char *name, int *val) +diff --git a/tests/py/any/tcpopt.t.json b/tests/py/any/tcpopt.t.json +index b15e36e..139e97d 100644 +--- a/tests/py/any/tcpopt.t.json ++++ b/tests/py/any/tcpopt.t.json +@@ -414,6 +414,40 @@ + } + ] + ++# tcp option 255 missing ++[ ++ { ++ "match": { ++ "left": { ++ "tcp option": { ++ "base": 255, ++ "len": 8, ++ "offset": 0 ++ } ++ }, ++ "op": "==", ++ "right": false ++ } ++ } ++] ++ ++# tcp option @255,8,8 255 ++[ ++ { ++ "match": { ++ "left": { ++ "tcp option": { ++ "base": 255, ++ "len": 8, ++ "offset": 8 ++ } ++ }, ++ "op": "==", ++ "right": 255 ++ } ++ } ++] ++ + # tcp option window exists + [ + { +-- +2.31.1 + diff --git a/SOURCES/0056-json-Simplify-non-tcpopt-exthdr-printing-a-bit.patch b/SOURCES/0056-json-Simplify-non-tcpopt-exthdr-printing-a-bit.patch new file mode 100644 index 0000000..1c21c46 --- /dev/null +++ b/SOURCES/0056-json-Simplify-non-tcpopt-exthdr-printing-a-bit.patch @@ -0,0 +1,57 @@ +From 2026f7d056679508f8506fbba7f578aa15af7c05 Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Mon, 12 Jul 2021 16:32:27 +0200 +Subject: [PATCH] json: Simplify non-tcpopt exthdr printing a bit + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1979334 +Upstream Status: nftables commit fd81d3ec3ae8b + +commit fd81d3ec3ae8b8d1d54a708d63b2dab2c8508c90 +Author: Phil Sutter +Date: Tue May 4 13:18:11 2021 +0200 + + json: Simplify non-tcpopt exthdr printing a bit + + This was just duplicate code apart from the object's name. + + Signed-off-by: Phil Sutter +--- + src/json.c | 18 +++++++----------- + 1 file changed, 7 insertions(+), 11 deletions(-) + +diff --git a/src/json.c b/src/json.c +index b77c6d2..a6d0716 100644 +--- a/src/json.c ++++ b/src/json.c +@@ -684,21 +684,17 @@ json_t *exthdr_expr_json(const struct expr *expr, struct output_ctx *octx) + + return json_pack("{s:o}", "tcp option", root); + } +- if (expr->exthdr.op == NFT_EXTHDR_OP_IPV4) { +- root = json_pack("{s:s}", "name", desc); + +- if (!is_exists) +- json_object_set_new(root, "field", json_string(field)); +- +- return json_pack("{s:o}", "ip option", root); +- } +- +- root = json_pack("{s:s}", +- "name", desc); ++ root = json_pack("{s:s}", "name", desc); + if (!is_exists) + json_object_set_new(root, "field", json_string(field)); + +- return json_pack("{s:o}", "exthdr", root); ++ switch (expr->exthdr.op) { ++ case NFT_EXTHDR_OP_IPV4: ++ return json_pack("{s:o}", "ip option", root); ++ default: ++ return json_pack("{s:o}", "exthdr", root); ++ } + } + + json_t *verdict_expr_json(const struct expr *expr, struct output_ctx *octx) +-- +2.31.1 + diff --git a/SOURCES/0057-scanner-introduce-start-condition-stack.patch b/SOURCES/0057-scanner-introduce-start-condition-stack.patch new file mode 100644 index 0000000..4a40b1d --- /dev/null +++ b/SOURCES/0057-scanner-introduce-start-condition-stack.patch @@ -0,0 +1,175 @@ +From c724812d9561021fb6a80c817d411d9ba2de5dbd Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Tue, 13 Jul 2021 13:54:12 +0200 +Subject: [PATCH] scanner: introduce start condition stack + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1979334 +Upstream Status: nftables commit 5896772fe3c5f + +commit 5896772fe3c5f01696188ea04957a825ee601b12 +Author: Florian Westphal +Date: Mon Mar 8 18:18:33 2021 +0100 + + scanner: introduce start condition stack + + Add a small initial chunk of flex start conditionals. + + This starts with two low-hanging fruits, numgen and j/symhash. + + NUMGEN and HASH start conditions are entered from flex when + the corresponding expression token is encountered. + + Flex returns to the INIT condition when the bison parser + has seen a complete numgen/hash statement. + + This intentionally uses a stack rather than BEGIN() + to eventually support nested states. + + The scanner_pop_start_cond() function argument is not used yet, but + will need to be used later to deal with nesting. + + Signed-off-by: Florian Westphal +--- + include/parser.h | 8 ++++++++ + src/parser_bison.y | 11 +++++++---- + src/scanner.l | 36 +++++++++++++++++++++++++++++------- + 3 files changed, 44 insertions(+), 11 deletions(-) + +diff --git a/include/parser.h b/include/parser.h +index 949284d..1d293f5 100644 +--- a/include/parser.h ++++ b/include/parser.h +@@ -28,6 +28,12 @@ struct parser_state { + struct list_head *cmds; + }; + ++enum startcond_type { ++ PARSER_SC_BEGIN, ++ PARSER_SC_EXPR_HASH, ++ PARSER_SC_EXPR_NUMGEN, ++}; ++ + struct mnl_socket; + + extern void parser_init(struct nft_ctx *nft, struct parser_state *state, +@@ -47,4 +53,6 @@ extern void scanner_push_buffer(void *scanner, + const struct input_descriptor *indesc, + const char *buffer); + ++extern void scanner_pop_start_cond(void *scanner, enum startcond_type sc); ++ + #endif /* NFTABLES_PARSER_H */ +diff --git a/src/parser_bison.y b/src/parser_bison.y +index 5aedc55..9a9447f 100644 +--- a/src/parser_bison.y ++++ b/src/parser_bison.y +@@ -840,6 +840,9 @@ opt_newline : NEWLINE + | /* empty */ + ; + ++close_scope_hash : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_HASH); }; ++close_scope_numgen : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_NUMGEN); }; ++ + common_block : INCLUDE QUOTED_STRING stmt_separator + { + if (scanner_include_file(nft, scanner, $2, &@$) < 0) { +@@ -4249,7 +4252,7 @@ numgen_type : INC { $$ = NFT_NG_INCREMENTAL; } + | RANDOM { $$ = NFT_NG_RANDOM; } + ; + +-numgen_expr : NUMGEN numgen_type MOD NUM offset_opt ++numgen_expr : NUMGEN numgen_type MOD NUM offset_opt close_scope_numgen + { + $$ = numgen_expr_alloc(&@$, $2, $4, $5); + } +@@ -4306,17 +4309,17 @@ xfrm_expr : IPSEC xfrm_dir xfrm_spnum xfrm_state_key + } + ; + +-hash_expr : JHASH expr MOD NUM SEED NUM offset_opt ++hash_expr : JHASH expr MOD NUM SEED NUM offset_opt close_scope_hash + { + $$ = hash_expr_alloc(&@$, $4, true, $6, $7, NFT_HASH_JENKINS); + $$->hash.expr = $2; + } +- | JHASH expr MOD NUM offset_opt ++ | JHASH expr MOD NUM offset_opt close_scope_hash + { + $$ = hash_expr_alloc(&@$, $4, false, 0, $5, NFT_HASH_JENKINS); + $$->hash.expr = $2; + } +- | SYMHASH MOD NUM offset_opt ++ | SYMHASH MOD NUM offset_opt close_scope_hash + { + $$ = hash_expr_alloc(&@$, $3, false, 0, $4, NFT_HASH_SYM); + } +diff --git a/src/scanner.l b/src/scanner.l +index 20b1b2d..68fe988 100644 +--- a/src/scanner.l ++++ b/src/scanner.l +@@ -98,6 +98,8 @@ static void reset_pos(struct parser_state *state, struct location *loc) + state->indesc->column = 1; + } + ++static void scanner_push_start_cond(void *scanner, enum startcond_type type); ++ + #define YY_USER_ACTION { \ + update_pos(yyget_extra(yyscanner), yylloc, yyleng); \ + update_offset(yyget_extra(yyscanner), yylloc, yyleng); \ +@@ -193,6 +195,9 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr}) + %option yylineno + %option nodefault + %option warn ++%option stack ++%s SCANSTATE_EXPR_HASH ++%s SCANSTATE_EXPR_NUMGEN + + %% + +@@ -548,15 +553,21 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr}) + "state" { return STATE; } + "status" { return STATUS; } + +-"numgen" { return NUMGEN; } +-"inc" { return INC; } +-"mod" { return MOD; } +-"offset" { return OFFSET; } ++"numgen" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_NUMGEN); return NUMGEN; } ++{ ++ "inc" { return INC; } ++} + +-"jhash" { return JHASH; } +-"symhash" { return SYMHASH; } +-"seed" { return SEED; } ++"jhash" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_HASH); return JHASH; } ++"symhash" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_HASH); return SYMHASH; } + ++{ ++ "seed" { return SEED; } ++} ++{ ++ "mod" { return MOD; } ++ "offset" { return OFFSET; } ++} + "dup" { return DUP; } + "fwd" { return FWD; } + +@@ -949,3 +960,14 @@ void scanner_destroy(struct nft_ctx *nft) + input_descriptor_list_destroy(state); + yylex_destroy(nft->scanner); + } ++ ++static void scanner_push_start_cond(void *scanner, enum startcond_type type) ++{ ++ yy_push_state((int)type, scanner); ++} ++ ++void scanner_pop_start_cond(void *scanner, enum startcond_type t) ++{ ++ yy_pop_state(scanner); ++ (void)yy_top_state(scanner); /* suppress gcc warning wrt. unused function */ ++} +-- +2.31.1 + diff --git a/SOURCES/0058-scanner-sctp-Move-to-own-scope.patch b/SOURCES/0058-scanner-sctp-Move-to-own-scope.patch new file mode 100644 index 0000000..9576e93 --- /dev/null +++ b/SOURCES/0058-scanner-sctp-Move-to-own-scope.patch @@ -0,0 +1,96 @@ +From 595e79b1ccdfa6b11cd6c2b1c8eda0161b58d22a Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Tue, 13 Jul 2021 13:54:12 +0200 +Subject: [PATCH] scanner: sctp: Move to own scope + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1979334 +Upstream Status: nftables commit 0925d7e214825 +Conflicts: Context change due to missing other scopes. + +commit 0925d7e214825628e7db4a86d5ebbad578ab0777 +Author: Phil Sutter +Date: Tue May 4 13:06:32 2021 +0200 + + scanner: sctp: Move to own scope + + This isolates only "vtag" token for now. + + Signed-off-by: Phil Sutter + Reviewed-by: Florian Westphal +--- + include/parser.h | 1 + + src/parser_bison.y | 5 +++-- + src/scanner.l | 8 ++++++-- + 3 files changed, 10 insertions(+), 4 deletions(-) + +diff --git a/include/parser.h b/include/parser.h +index 1d293f5..2e6ef4d 100644 +--- a/include/parser.h ++++ b/include/parser.h +@@ -30,6 +30,7 @@ struct parser_state { + + enum startcond_type { + PARSER_SC_BEGIN, ++ PARSER_SC_SCTP, + PARSER_SC_EXPR_HASH, + PARSER_SC_EXPR_NUMGEN, + }; +diff --git a/src/parser_bison.y b/src/parser_bison.y +index 9a9447f..beb5995 100644 +--- a/src/parser_bison.y ++++ b/src/parser_bison.y +@@ -842,6 +842,7 @@ opt_newline : NEWLINE + + close_scope_hash : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_HASH); }; + close_scope_numgen : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_NUMGEN); }; ++close_scope_sctp : { scanner_pop_start_cond(nft->scanner, PARSER_SC_SCTP); }; + + common_block : INCLUDE QUOTED_STRING stmt_separator + { +@@ -4059,7 +4060,7 @@ primary_rhs_expr : symbol_expr { $$ = $1; } + BYTEORDER_HOST_ENDIAN, + sizeof(data) * BITS_PER_BYTE, &data); + } +- | SCTP ++ | SCTP close_scope_sctp + { + uint8_t data = IPPROTO_SCTP; + $$ = constant_expr_alloc(&@$, &inet_protocol_type, +@@ -4782,7 +4783,7 @@ dccp_hdr_field : SPORT { $$ = DCCPHDR_SPORT; } + | TYPE { $$ = DCCPHDR_TYPE; } + ; + +-sctp_hdr_expr : SCTP sctp_hdr_field ++sctp_hdr_expr : SCTP sctp_hdr_field close_scope_sctp + { + $$ = payload_expr_alloc(&@$, &proto_sctp, $2); + } +diff --git a/src/scanner.l b/src/scanner.l +index 68fe988..b79ae55 100644 +--- a/src/scanner.l ++++ b/src/scanner.l +@@ -196,6 +196,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr}) + %option nodefault + %option warn + %option stack ++%s SCANSTATE_SCTP + %s SCANSTATE_EXPR_HASH + %s SCANSTATE_EXPR_NUMGEN + +@@ -488,8 +489,11 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr}) + + "dccp" { return DCCP; } + +-"sctp" { return SCTP; } +-"vtag" { return VTAG; } ++"sctp" { scanner_push_start_cond(yyscanner, SCANSTATE_SCTP); return SCTP; } ++ ++{ ++ "vtag" { return VTAG; } ++} + + "rt" { return RT; } + "rt0" { return RT0; } +-- +2.31.1 + diff --git a/SOURCES/0059-exthdr-Implement-SCTP-Chunk-matching.patch b/SOURCES/0059-exthdr-Implement-SCTP-Chunk-matching.patch new file mode 100644 index 0000000..e095e66 --- /dev/null +++ b/SOURCES/0059-exthdr-Implement-SCTP-Chunk-matching.patch @@ -0,0 +1,1625 @@ +From 5a8d6197929e30520bb3839c9165d89930888daf Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Tue, 13 Jul 2021 13:54:42 +0200 +Subject: [PATCH] exthdr: Implement SCTP Chunk matching + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1979334 +Upstream Status: nftables commit 0e3871cfd9a1e +Conflicts: + * Context changes due to missing other scopes. + * Context change due to missing commit 6e6ef00028f1c + ("exthdr: remove tcp dependency for tcp option matching"). + +commit 0e3871cfd9a1e32a4ac041ce87a8057b11a89924 +Author: Phil Sutter +Date: Tue May 4 13:41:38 2021 +0200 + + exthdr: Implement SCTP Chunk matching + + Extend exthdr expression to support scanning through SCTP packet chunks + and matching on fixed fields' values. + + Signed-off-by: Phil Sutter + Acked-by: Florian Westphal +--- + doc/libnftables-json.adoc | 13 + + doc/payload-expression.txt | 53 +++ + include/linux/netfilter/nf_tables.h | 2 + + include/parser.h | 1 + + include/sctp_chunk.h | 87 +++++ + src/Makefile.am | 1 + + src/evaluate.c | 2 + + src/exthdr.c | 8 + + src/json.c | 2 + + src/parser_bison.y | 148 ++++++++- + src/parser_json.c | 49 +++ + src/scanner.l | 38 +++ + src/sctp_chunk.c | 261 +++++++++++++++ + tests/py/inet/sctp.t | 37 +++ + tests/py/inet/sctp.t.json | 478 ++++++++++++++++++++++++++++ + tests/py/inet/sctp.t.payload | 155 +++++++++ + 16 files changed, 1333 insertions(+), 2 deletions(-) + create mode 100644 include/sctp_chunk.h + create mode 100644 src/sctp_chunk.c + +diff --git a/doc/libnftables-json.adoc b/doc/libnftables-json.adoc +index 858abbf..fba4cb0 100644 +--- a/doc/libnftables-json.adoc ++++ b/doc/libnftables-json.adoc +@@ -1200,6 +1200,19 @@ Create a reference to a field (*field*) of a TCP option header (*name*). + If the *field* property is not given, the expression is to be used as a TCP option + existence check in a *match* statement with a boolean on the right hand side. + ++=== SCTP CHUNK ++[verse] ++*{ "sctp chunk": { ++ "name":* 'STRING'*, ++ "field":* 'STRING' ++*}}* ++ ++Create a reference to a field (*field*) of an SCTP chunk (*name*). ++ ++If the *field* property is not given, the expression is to be used as an SCTP ++chunk existence check in a *match* statement with a boolean on the right hand ++side. ++ + === META + [verse] + ____ +diff --git a/doc/payload-expression.txt b/doc/payload-expression.txt +index b6d2a28..bd03ca2 100644 +--- a/doc/payload-expression.txt ++++ b/doc/payload-expression.txt +@@ -369,7 +369,33 @@ integer (16 bit) + SCTP HEADER EXPRESSION + ~~~~~~~~~~~~~~~~~~~~~~~ + [verse] ++____ + *sctp* {*sport* | *dport* | *vtag* | *checksum*} ++*sctp chunk* 'CHUNK' [ 'FIELD' ] ++ ++'CHUNK' := *data* | *init* | *init-ack* | *sack* | *heartbeat* | ++ *heartbeat-ack* | *abort* | *shutdown* | *shutdown-ack* | *error* | ++ *cookie-echo* | *cookie-ack* | *ecne* | *cwr* | *shutdown-complete* ++ | *asconf-ack* | *forward-tsn* | *asconf* ++ ++'FIELD' := 'COMMON_FIELD' | 'DATA_FIELD' | 'INIT_FIELD' | 'INIT_ACK_FIELD' | ++ 'SACK_FIELD' | 'SHUTDOWN_FIELD' | 'ECNE_FIELD' | 'CWR_FIELD' | ++ 'ASCONF_ACK_FIELD' | 'FORWARD_TSN_FIELD' | 'ASCONF_FIELD' ++ ++'COMMON_FIELD' := *type* | *flags* | *length* ++'DATA_FIELD' := *tsn* | *stream* | *ssn* | *ppid* ++'INIT_FIELD' := *init-tag* | *a-rwnd* | *num-outbound-streams* | ++ *num-inbound-streams* | *initial-tsn* ++'INIT_ACK_FIELD' := 'INIT_FIELD' ++'SACK_FIELD' := *cum-tsn-ack* | *a-rwnd* | *num-gap-ack-blocks* | ++ *num-dup-tsns* ++'SHUTDOWN_FIELD' := *cum-tsn-ack* ++'ECNE_FIELD' := *lowest-tsn* ++'CWR_FIELD' := *lowest-tsn* ++'ASCONF_ACK_FIELD' := *seqno* ++'FORWARD_TSN_FIELD' := *new-cum-tsn* ++'ASCONF_FIELD' := *seqno* ++____ + + .SCTP header expression + [options="header"] +@@ -387,8 +413,35 @@ integer (32 bit) + |checksum| + Checksum| + integer (32 bit) ++|chunk| ++Search chunk in packet| ++without 'FIELD', boolean indicating existence + |================ + ++.SCTP chunk fields ++[options="header"] ++|================== ++|Name| Width in bits | Chunk | Notes ++|type| 8 | all | not useful, defined by chunk type ++|flags| 8 | all | semantics defined on per-chunk basis ++|length| 16 | all | length of this chunk in bytes excluding padding ++|tsn| 32 | data | transmission sequence number ++|stream| 16 | data | stream identifier ++|ssn| 16 | data | stream sequence number ++|ppid| 32 | data | payload protocol identifier ++|init-tag| 32 | init, init-ack | initiate tag ++|a-rwnd| 32 | init, init-ack, sack | advertised receiver window credit ++|num-outbound-streams| 16 | init, init-ack | number of outbound streams ++|num-inbound-streams| 16 | init, init-ack | number of inbound streams ++|initial-tsn| 32 | init, init-ack | initial transmit sequence number ++|cum-tsn-ack| 32 | sack, shutdown | cumulative transmission sequence number acknowledged ++|num-gap-ack-blocks| 16 | sack | number of Gap Ack Blocks included ++|num-dup-tsns| 16 | sack | number of duplicate transmission sequence numbers received ++|lowest-tsn| 32 | ecne, cwr | lowest transmission sequence number ++|seqno| 32 | asconf-ack, asconf | sequence number ++|new-cum-tsn| 32 | forward-tsn | new cumulative transmission sequence number ++|================== ++ + DCCP HEADER EXPRESSION + ~~~~~~~~~~~~~~~~~~~~~~ + [verse] +diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h +index 1328b8e..960a5b4 100644 +--- a/include/linux/netfilter/nf_tables.h ++++ b/include/linux/netfilter/nf_tables.h +@@ -755,11 +755,13 @@ enum nft_exthdr_flags { + * @NFT_EXTHDR_OP_IPV6: match against ipv6 extension headers + * @NFT_EXTHDR_OP_TCP: match against tcp options + * @NFT_EXTHDR_OP_IPV4: match against ipv4 options ++ * @NFT_EXTHDR_OP_SCTP: match against sctp chunks + */ + enum nft_exthdr_op { + NFT_EXTHDR_OP_IPV6, + NFT_EXTHDR_OP_TCPOPT, + NFT_EXTHDR_OP_IPV4, ++ NFT_EXTHDR_OP_SCTP, + __NFT_EXTHDR_OP_MAX + }; + #define NFT_EXTHDR_OP_MAX (__NFT_EXTHDR_OP_MAX - 1) +diff --git a/include/parser.h b/include/parser.h +index 2e6ef4d..99bed3c 100644 +--- a/include/parser.h ++++ b/include/parser.h +@@ -33,6 +33,7 @@ enum startcond_type { + PARSER_SC_SCTP, + PARSER_SC_EXPR_HASH, + PARSER_SC_EXPR_NUMGEN, ++ PARSER_SC_EXPR_SCTP_CHUNK, + }; + + struct mnl_socket; +diff --git a/include/sctp_chunk.h b/include/sctp_chunk.h +new file mode 100644 +index 0000000..3819200 +--- /dev/null ++++ b/include/sctp_chunk.h +@@ -0,0 +1,87 @@ ++/* ++ * Copyright Red Hat ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 (or any ++ * later) as published by the Free Software Foundation. ++ */ ++ ++#ifndef NFTABLES_SCTP_CHUNK_H ++#define NFTABLES_SCTP_CHUNK_H ++ ++/* SCTP chunk types used on wire */ ++enum sctp_hdr_chunk_types { ++ SCTP_CHUNK_TYPE_DATA = 0, ++ SCTP_CHUNK_TYPE_INIT = 1, ++ SCTP_CHUNK_TYPE_INIT_ACK = 2, ++ SCTP_CHUNK_TYPE_SACK = 3, ++ SCTP_CHUNK_TYPE_HEARTBEAT = 4, ++ SCTP_CHUNK_TYPE_HEARTBEAT_ACK = 5, ++ SCTP_CHUNK_TYPE_ABORT = 6, ++ SCTP_CHUNK_TYPE_SHUTDOWN = 7, ++ SCTP_CHUNK_TYPE_SHUTDOWN_ACK = 8, ++ SCTP_CHUNK_TYPE_ERROR = 9, ++ SCTP_CHUNK_TYPE_COOKIE_ECHO = 10, ++ SCTP_CHUNK_TYPE_COOKIE_ACK = 11, ++ SCTP_CHUNK_TYPE_ECNE = 12, ++ SCTP_CHUNK_TYPE_CWR = 13, ++ SCTP_CHUNK_TYPE_SHUTDOWN_COMPLETE = 14, ++ SCTP_CHUNK_TYPE_ASCONF_ACK = 128, ++ SCTP_CHUNK_TYPE_FORWARD_TSN = 192, ++ SCTP_CHUNK_TYPE_ASCONF = 193, ++}; ++ ++enum sctp_hdr_chunk_common_fields { ++ SCTP_CHUNK_COMMON_TYPE, ++ SCTP_CHUNK_COMMON_FLAGS, ++ SCTP_CHUNK_COMMON_LENGTH, ++ __SCTP_CHUNK_COMMON_MAX, ++}; ++ ++#define SCTP_CHUNK_START_INDEX __SCTP_CHUNK_COMMON_MAX ++ ++enum sctp_hdr_chunk_data_fields { ++ SCTP_CHUNK_DATA_TSN = SCTP_CHUNK_START_INDEX, ++ SCTP_CHUNK_DATA_STREAM, ++ SCTP_CHUNK_DATA_SSN, ++ SCTP_CHUNK_DATA_PPID, ++}; ++ ++enum sctp_hdr_chunk_init_fields { ++ SCTP_CHUNK_INIT_TAG = SCTP_CHUNK_START_INDEX, ++ SCTP_CHUNK_INIT_RWND, ++ SCTP_CHUNK_INIT_OSTREAMS, ++ SCTP_CHUNK_INIT_ISTREAMS, ++ SCTP_CHUNK_INIT_TSN, ++}; ++ ++enum sctp_hdr_chunk_sack_fields { ++ SCTP_CHUNK_SACK_CTSN_ACK = SCTP_CHUNK_START_INDEX, ++ SCTP_CHUNK_SACK_RWND, ++ SCTP_CHUNK_SACK_GACK_BLOCKS, ++ SCTP_CHUNK_SACK_DUP_TSNS, ++}; ++ ++enum sctp_hdr_chunk_shutdown_fields { ++ SCTP_CHUNK_SHUTDOWN_CTSN_ACK = SCTP_CHUNK_START_INDEX, ++}; ++ ++enum sctp_hdr_chunk_ecne_cwr_fields { ++ SCTP_CHUNK_ECNE_CWR_MIN_TSN = SCTP_CHUNK_START_INDEX, ++}; ++ ++enum sctp_hdr_chunk_asconf_fields { ++ SCTP_CHUNK_ASCONF_SEQNO = SCTP_CHUNK_START_INDEX, ++}; ++ ++enum sctp_hdr_chunk_fwd_tsn_fields { ++ SCTP_CHUNK_FORWARD_TSN_NCTSN = SCTP_CHUNK_START_INDEX, ++}; ++ ++struct expr *sctp_chunk_expr_alloc(const struct location *loc, ++ unsigned int type, unsigned int field); ++void sctp_chunk_init_raw(struct expr *expr, uint8_t type, unsigned int off, ++ unsigned int len, uint32_t flags); ++const struct exthdr_desc *sctp_chunk_protocol_find(const char *name); ++ ++#endif /* NFTABLES_SCTP_CHUNK_H */ +diff --git a/src/Makefile.am b/src/Makefile.am +index 740c21f..366820b 100644 +--- a/src/Makefile.am ++++ b/src/Makefile.am +@@ -64,6 +64,7 @@ libnftables_la_SOURCES = \ + tcpopt.c \ + socket.c \ + print.c \ ++ sctp_chunk.c \ + libnftables.c \ + libnftables.map + +diff --git a/src/evaluate.c b/src/evaluate.c +index 99a66c2..00ec20b 100644 +--- a/src/evaluate.c ++++ b/src/evaluate.c +@@ -579,6 +579,8 @@ static int expr_evaluate_exthdr(struct eval_ctx *ctx, struct expr **exprp) + dependency = &proto_tcp; + pb = PROTO_BASE_TRANSPORT_HDR; + break; ++ case NFT_EXTHDR_OP_SCTP: ++ return __expr_evaluate_exthdr(ctx, exprp); + case NFT_EXTHDR_OP_IPV4: + dependency = &proto_ip; + break; +diff --git a/src/exthdr.c b/src/exthdr.c +index 5c75720..f5689e7 100644 +--- a/src/exthdr.c ++++ b/src/exthdr.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + + static void exthdr_expr_print(const struct expr *expr, struct output_ctx *octx) + { +@@ -55,6 +56,11 @@ static void exthdr_expr_print(const struct expr *expr, struct output_ctx *octx) + if (expr->exthdr.flags & NFT_EXTHDR_F_PRESENT) + return; + nft_print(octx, " %s", expr->exthdr.tmpl->token); ++ } else if (expr->exthdr.op == NFT_EXTHDR_OP_SCTP) { ++ nft_print(octx, "sctp chunk %s", expr->exthdr.desc->name); ++ if (expr->exthdr.flags & NFT_EXTHDR_F_PRESENT) ++ return; ++ nft_print(octx, " %s", expr->exthdr.tmpl->token); + } else { + if (expr->exthdr.flags & NFT_EXTHDR_F_PRESENT) + nft_print(octx, "exthdr %s", expr->exthdr.desc->name); +@@ -197,6 +203,8 @@ void exthdr_init_raw(struct expr *expr, uint8_t type, + return tcpopt_init_raw(expr, type, offset, len, flags); + if (op == NFT_EXTHDR_OP_IPV4) + return ipopt_init_raw(expr, type, offset, len, flags, true); ++ if (op == NFT_EXTHDR_OP_SCTP) ++ return sctp_chunk_init_raw(expr, type, offset, len, flags); + + expr->len = len; + expr->exthdr.flags = flags; +diff --git a/src/json.c b/src/json.c +index a6d0716..dfc9031 100644 +--- a/src/json.c ++++ b/src/json.c +@@ -692,6 +692,8 @@ json_t *exthdr_expr_json(const struct expr *expr, struct output_ctx *octx) + switch (expr->exthdr.op) { + case NFT_EXTHDR_OP_IPV4: + return json_pack("{s:o}", "ip option", root); ++ case NFT_EXTHDR_OP_SCTP: ++ return json_pack("{s:o}", "sctp chunk", root); + default: + return json_pack("{s:o}", "exthdr", root); + } +diff --git a/src/parser_bison.y b/src/parser_bison.y +index beb5995..5ab5744 100644 +--- a/src/parser_bison.y ++++ b/src/parser_bison.y +@@ -38,6 +38,7 @@ + #include + #include + #include ++#include + + #include "parser_bison.h" + +@@ -402,6 +403,40 @@ int nft_lex(void *, void *, void *); + %token DCCP "dccp" + + %token SCTP "sctp" ++%token CHUNK "chunk" ++%token DATA "data" ++%token INIT "init" ++%token INIT_ACK "init-ack" ++%token HEARTBEAT "heartbeat" ++%token HEARTBEAT_ACK "heartbeat-ack" ++%token ABORT "abort" ++%token SHUTDOWN "shutdown" ++%token SHUTDOWN_ACK "shutdown-ack" ++%token ERROR "error" ++%token COOKIE_ECHO "cookie-echo" ++%token COOKIE_ACK "cookie-ack" ++%token ECNE "ecne" ++%token CWR "cwr" ++%token SHUTDOWN_COMPLETE "shutdown-complete" ++%token ASCONF_ACK "asconf-ack" ++%token FORWARD_TSN "forward-tsn" ++%token ASCONF "asconf" ++%token TSN "tsn" ++%token STREAM "stream" ++%token SSN "ssn" ++%token PPID "ppid" ++%token INIT_TAG "init-tag" ++%token A_RWND "a-rwnd" ++%token NUM_OSTREAMS "num-outbound-streams" ++%token NUM_ISTREAMS "num-inbound-streams" ++%token INIT_TSN "initial-tsn" ++%token CUM_TSN_ACK "cum-tsn-ack" ++%token NUM_GACK_BLOCKS "num-gap-ack-blocks" ++%token NUM_DUP_TSNS "num-dup-tsns" ++%token LOWEST_TSN "lowest-tsn" ++%token SEQNO "seqno" ++%token NEW_CUM_TSN "new-cum-tsn" ++ + %token VTAG "vtag" + + %token RT "rt" +@@ -746,9 +781,12 @@ int nft_lex(void *, void *, void *); + %type udp_hdr_expr udplite_hdr_expr + %destructor { expr_free($$); } udp_hdr_expr udplite_hdr_expr + %type udp_hdr_field udplite_hdr_field +-%type dccp_hdr_expr sctp_hdr_expr +-%destructor { expr_free($$); } dccp_hdr_expr sctp_hdr_expr ++%type dccp_hdr_expr sctp_hdr_expr sctp_chunk_alloc ++%destructor { expr_free($$); } dccp_hdr_expr sctp_hdr_expr sctp_chunk_alloc + %type dccp_hdr_field sctp_hdr_field ++%type sctp_chunk_type sctp_chunk_common_field ++%type sctp_chunk_data_field sctp_chunk_init_field ++%type sctp_chunk_sack_field + %type th_hdr_expr + %destructor { expr_free($$); } th_hdr_expr + %type th_hdr_field +@@ -843,6 +881,7 @@ opt_newline : NEWLINE + close_scope_hash : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_HASH); }; + close_scope_numgen : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_NUMGEN); }; + close_scope_sctp : { scanner_pop_start_cond(nft->scanner, PARSER_SC_SCTP); }; ++close_scope_sctp_chunk : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_SCTP_CHUNK); }; + + common_block : INCLUDE QUOTED_STRING stmt_separator + { +@@ -4783,10 +4822,115 @@ dccp_hdr_field : SPORT { $$ = DCCPHDR_SPORT; } + | TYPE { $$ = DCCPHDR_TYPE; } + ; + ++sctp_chunk_type : DATA { $$ = SCTP_CHUNK_TYPE_DATA; } ++ | INIT { $$ = SCTP_CHUNK_TYPE_INIT; } ++ | INIT_ACK { $$ = SCTP_CHUNK_TYPE_INIT_ACK; } ++ | SACK { $$ = SCTP_CHUNK_TYPE_SACK; } ++ | HEARTBEAT { $$ = SCTP_CHUNK_TYPE_HEARTBEAT; } ++ | HEARTBEAT_ACK { $$ = SCTP_CHUNK_TYPE_HEARTBEAT_ACK; } ++ | ABORT { $$ = SCTP_CHUNK_TYPE_ABORT; } ++ | SHUTDOWN { $$ = SCTP_CHUNK_TYPE_SHUTDOWN; } ++ | SHUTDOWN_ACK { $$ = SCTP_CHUNK_TYPE_SHUTDOWN_ACK; } ++ | ERROR { $$ = SCTP_CHUNK_TYPE_ERROR; } ++ | COOKIE_ECHO { $$ = SCTP_CHUNK_TYPE_COOKIE_ECHO; } ++ | COOKIE_ACK { $$ = SCTP_CHUNK_TYPE_COOKIE_ACK; } ++ | ECNE { $$ = SCTP_CHUNK_TYPE_ECNE; } ++ | CWR { $$ = SCTP_CHUNK_TYPE_CWR; } ++ | SHUTDOWN_COMPLETE { $$ = SCTP_CHUNK_TYPE_SHUTDOWN_COMPLETE; } ++ | ASCONF_ACK { $$ = SCTP_CHUNK_TYPE_ASCONF_ACK; } ++ | FORWARD_TSN { $$ = SCTP_CHUNK_TYPE_FORWARD_TSN; } ++ | ASCONF { $$ = SCTP_CHUNK_TYPE_ASCONF; } ++ ; ++ ++sctp_chunk_common_field : TYPE { $$ = SCTP_CHUNK_COMMON_TYPE; } ++ | FLAGS { $$ = SCTP_CHUNK_COMMON_FLAGS; } ++ | LENGTH { $$ = SCTP_CHUNK_COMMON_LENGTH; } ++ ; ++ ++sctp_chunk_data_field : TSN { $$ = SCTP_CHUNK_DATA_TSN; } ++ | STREAM { $$ = SCTP_CHUNK_DATA_STREAM; } ++ | SSN { $$ = SCTP_CHUNK_DATA_SSN; } ++ | PPID { $$ = SCTP_CHUNK_DATA_PPID; } ++ ; ++ ++sctp_chunk_init_field : INIT_TAG { $$ = SCTP_CHUNK_INIT_TAG; } ++ | A_RWND { $$ = SCTP_CHUNK_INIT_RWND; } ++ | NUM_OSTREAMS { $$ = SCTP_CHUNK_INIT_OSTREAMS; } ++ | NUM_ISTREAMS { $$ = SCTP_CHUNK_INIT_ISTREAMS; } ++ | INIT_TSN { $$ = SCTP_CHUNK_INIT_TSN; } ++ ; ++ ++sctp_chunk_sack_field : CUM_TSN_ACK { $$ = SCTP_CHUNK_SACK_CTSN_ACK; } ++ | A_RWND { $$ = SCTP_CHUNK_SACK_RWND; } ++ | NUM_GACK_BLOCKS { $$ = SCTP_CHUNK_SACK_GACK_BLOCKS; } ++ | NUM_DUP_TSNS { $$ = SCTP_CHUNK_SACK_DUP_TSNS; } ++ ; ++ ++sctp_chunk_alloc : sctp_chunk_type ++ { ++ $$ = sctp_chunk_expr_alloc(&@$, $1, SCTP_CHUNK_COMMON_TYPE); ++ $$->exthdr.flags = NFT_EXTHDR_F_PRESENT; ++ } ++ | sctp_chunk_type sctp_chunk_common_field ++ { ++ $$ = sctp_chunk_expr_alloc(&@$, $1, $2); ++ } ++ | DATA sctp_chunk_data_field ++ { ++ $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_DATA, $2); ++ } ++ | INIT sctp_chunk_init_field ++ { ++ $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_INIT, $2); ++ } ++ | INIT_ACK sctp_chunk_init_field ++ { ++ $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_INIT_ACK, $2); ++ } ++ | SACK sctp_chunk_sack_field ++ { ++ $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_SACK, $2); ++ } ++ | SHUTDOWN CUM_TSN_ACK ++ { ++ $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_SHUTDOWN, ++ SCTP_CHUNK_SHUTDOWN_CTSN_ACK); ++ } ++ | ECNE LOWEST_TSN ++ { ++ $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_ECNE, ++ SCTP_CHUNK_ECNE_CWR_MIN_TSN); ++ } ++ | CWR LOWEST_TSN ++ { ++ $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_CWR, ++ SCTP_CHUNK_ECNE_CWR_MIN_TSN); ++ } ++ | ASCONF_ACK SEQNO ++ { ++ $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_ASCONF_ACK, ++ SCTP_CHUNK_ASCONF_SEQNO); ++ } ++ | FORWARD_TSN NEW_CUM_TSN ++ { ++ $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_FORWARD_TSN, ++ SCTP_CHUNK_FORWARD_TSN_NCTSN); ++ } ++ | ASCONF SEQNO ++ { ++ $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_ASCONF, ++ SCTP_CHUNK_ASCONF_SEQNO); ++ } ++ ; ++ + sctp_hdr_expr : SCTP sctp_hdr_field close_scope_sctp + { + $$ = payload_expr_alloc(&@$, &proto_sctp, $2); + } ++ | SCTP CHUNK sctp_chunk_alloc close_scope_sctp_chunk close_scope_sctp ++ { ++ $$ = $3; ++ } + ; + + sctp_hdr_field : SPORT { $$ = SCTPHDR_SPORT; } +diff --git a/src/parser_json.c b/src/parser_json.c +index fbf7db5..a069a89 100644 +--- a/src/parser_json.c ++++ b/src/parser_json.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -705,6 +706,53 @@ static struct expr *json_parse_ip_option_expr(struct json_ctx *ctx, + return ipopt_expr_alloc(int_loc, descval, fieldval, 0); + } + ++static int json_parse_sctp_chunk_field(const struct exthdr_desc *desc, ++ const char *name, int *val) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < array_size(desc->templates); i++) { ++ if (desc->templates[i].token && ++ !strcmp(desc->templates[i].token, name)) { ++ if (val) ++ *val = i; ++ return 0; ++ } ++ } ++ return 1; ++} ++ ++static struct expr *json_parse_sctp_chunk_expr(struct json_ctx *ctx, ++ const char *type, json_t *root) ++{ ++ const struct exthdr_desc *desc; ++ const char *name, *field; ++ struct expr *expr; ++ int fieldval; ++ ++ if (json_unpack_err(ctx, root, "{s:s}", "name", &name)) ++ return NULL; ++ ++ desc = sctp_chunk_protocol_find(name); ++ if (!desc) { ++ json_error(ctx, "Unknown sctp chunk name '%s'.", name); ++ return NULL; ++ } ++ ++ if (json_unpack(root, "{s:s}", "field", &field)) { ++ expr = sctp_chunk_expr_alloc(int_loc, desc->type, ++ SCTP_CHUNK_COMMON_TYPE); ++ expr->exthdr.flags = NFT_EXTHDR_F_PRESENT; ++ ++ return expr; ++ } ++ if (json_parse_sctp_chunk_field(desc, field, &fieldval)) { ++ json_error(ctx, "Unknown sctp chunk field '%s'.", field); ++ return NULL; ++ } ++ return sctp_chunk_expr_alloc(int_loc, desc->type, fieldval); ++} ++ + static const struct exthdr_desc *exthdr_lookup_byname(const char *name) + { + const struct exthdr_desc *exthdr_tbl[] = { +@@ -1410,6 +1458,7 @@ static struct expr *json_parse_expr(struct json_ctx *ctx, json_t *root) + { "exthdr", json_parse_exthdr_expr, CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT }, + { "tcp option", json_parse_tcp_option_expr, CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_CONCAT }, + { "ip option", json_parse_ip_option_expr, CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_CONCAT }, ++ { "sctp chunk", json_parse_sctp_chunk_expr, CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_CONCAT }, + { "meta", json_parse_meta_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT }, + { "osf", json_parse_osf_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_MAP | CTX_F_CONCAT }, + { "ipsec", json_parse_xfrm_expr, CTX_F_PRIMARY | CTX_F_MAP | CTX_F_CONCAT }, +diff --git a/src/scanner.l b/src/scanner.l +index b79ae55..fe1b8ad 100644 +--- a/src/scanner.l ++++ b/src/scanner.l +@@ -199,6 +199,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr}) + %s SCANSTATE_SCTP + %s SCANSTATE_EXPR_HASH + %s SCANSTATE_EXPR_NUMGEN ++%s SCANSTATE_EXPR_SCTP_CHUNK + + %% + +@@ -492,9 +493,46 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr}) + "sctp" { scanner_push_start_cond(yyscanner, SCANSTATE_SCTP); return SCTP; } + + { ++ "chunk" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_SCTP_CHUNK); return CHUNK; } + "vtag" { return VTAG; } + } + ++{ ++ "data" { return DATA; } ++ "init" { return INIT; } ++ "init-ack" { return INIT_ACK; } ++ "heartbeat" { return HEARTBEAT; } ++ "heartbeat-ack" { return HEARTBEAT_ACK; } ++ "abort" { return ABORT; } ++ "shutdown" { return SHUTDOWN; } ++ "shutdown-ack" { return SHUTDOWN_ACK; } ++ "error" { return ERROR; } ++ "cookie-echo" { return COOKIE_ECHO; } ++ "cookie-ack" { return COOKIE_ACK; } ++ "ecne" { return ECNE; } ++ "cwr" { return CWR; } ++ "shutdown-complete" { return SHUTDOWN_COMPLETE; } ++ "asconf-ack" { return ASCONF_ACK; } ++ "forward-tsn" { return FORWARD_TSN; } ++ "asconf" { return ASCONF; } ++ ++ "tsn" { return TSN; } ++ "stream" { return STREAM; } ++ "ssn" { return SSN; } ++ "ppid" { return PPID; } ++ "init-tag" { return INIT_TAG; } ++ "a-rwnd" { return A_RWND; } ++ "num-outbound-streams" { return NUM_OSTREAMS; } ++ "num-inbound-streams" { return NUM_ISTREAMS; } ++ "initial-tsn" { return INIT_TSN; } ++ "cum-tsn-ack" { return CUM_TSN_ACK; } ++ "num-gap-ack-blocks" { return NUM_GACK_BLOCKS; } ++ "num-dup-tsns" { return NUM_DUP_TSNS; } ++ "lowest-tsn" { return LOWEST_TSN; } ++ "seqno" { return SEQNO; } ++ "new-cum-tsn" { return NEW_CUM_TSN; } ++} ++ + "rt" { return RT; } + "rt0" { return RT0; } + "rt2" { return RT2; } +diff --git a/src/sctp_chunk.c b/src/sctp_chunk.c +new file mode 100644 +index 0000000..6e73e72 +--- /dev/null ++++ b/src/sctp_chunk.c +@@ -0,0 +1,261 @@ ++/* ++ * Copyright Red Hat ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 (or any ++ * later) as published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++ ++#include ++ ++#define PHT(__token, __offset, __len) \ ++ PROTO_HDR_TEMPLATE(__token, &integer_type, BYTEORDER_BIG_ENDIAN, \ ++ __offset, __len) ++ ++static const struct exthdr_desc sctp_chunk_data = { ++ .name = "data", ++ .type = SCTP_CHUNK_TYPE_DATA, ++ .templates = { ++ [SCTP_CHUNK_COMMON_TYPE] = PHT("type", 0, 8), ++ [SCTP_CHUNK_COMMON_FLAGS] = PHT("flags", 8, 8), ++ [SCTP_CHUNK_COMMON_LENGTH] = PHT("length", 16, 16), ++ [SCTP_CHUNK_DATA_TSN] = PHT("tsn", 32, 32), ++ [SCTP_CHUNK_DATA_STREAM] = PHT("stream", 64, 16), ++ [SCTP_CHUNK_DATA_SSN] = PHT("ssn", 80, 16), ++ [SCTP_CHUNK_DATA_PPID] = PHT("ppid", 96, 32), ++ }, ++}; ++ ++static const struct exthdr_desc sctp_chunk_init = { ++ .name = "init", ++ .type = SCTP_CHUNK_TYPE_INIT, ++ .templates = { ++ [SCTP_CHUNK_COMMON_TYPE] = PHT("type", 0, 8), ++ [SCTP_CHUNK_COMMON_FLAGS] = PHT("flags", 8, 8), ++ [SCTP_CHUNK_COMMON_LENGTH] = PHT("length", 16, 16), ++ [SCTP_CHUNK_INIT_TAG] = PHT("init-tag", 32, 32), ++ [SCTP_CHUNK_INIT_RWND] = PHT("a-rwnd", 64, 32), ++ [SCTP_CHUNK_INIT_OSTREAMS] = PHT("num-outbound-streams", 96, 16), ++ [SCTP_CHUNK_INIT_ISTREAMS] = PHT("num-inbound-streams", 112, 16), ++ [SCTP_CHUNK_INIT_TSN] = PHT("initial-tsn", 128, 32), ++ }, ++}; ++ ++static const struct exthdr_desc sctp_chunk_init_ack = { ++ .name = "init-ack", ++ .type = SCTP_CHUNK_TYPE_INIT_ACK, ++ .templates = { ++ [SCTP_CHUNK_COMMON_TYPE] = PHT("type", 0, 8), ++ [SCTP_CHUNK_COMMON_FLAGS] = PHT("flags", 8, 8), ++ [SCTP_CHUNK_COMMON_LENGTH] = PHT("length", 16, 16), ++ [SCTP_CHUNK_INIT_TAG] = PHT("init-tag", 32, 32), ++ [SCTP_CHUNK_INIT_RWND] = PHT("a-rwnd", 64, 32), ++ [SCTP_CHUNK_INIT_OSTREAMS] = PHT("num-outbound-streams", 96, 16), ++ [SCTP_CHUNK_INIT_ISTREAMS] = PHT("num-inbound-streams", 112, 16), ++ [SCTP_CHUNK_INIT_TSN] = PHT("initial-tsn", 128, 32), ++ }, ++}; ++ ++static const struct exthdr_desc sctp_chunk_sack = { ++ .name = "sack", ++ .type = SCTP_CHUNK_TYPE_SACK, ++ .templates = { ++ [SCTP_CHUNK_COMMON_TYPE] = PHT("type", 0, 8), ++ [SCTP_CHUNK_COMMON_FLAGS] = PHT("flags", 8, 8), ++ [SCTP_CHUNK_COMMON_LENGTH] = PHT("length", 16, 16), ++ [SCTP_CHUNK_SACK_CTSN_ACK] = PHT("cum-tsn-ack", 32, 32), ++ [SCTP_CHUNK_SACK_RWND] = PHT("a-rwnd", 64, 32), ++ [SCTP_CHUNK_SACK_GACK_BLOCKS] = PHT("num-gap-ack-blocks", 96, 16), ++ [SCTP_CHUNK_SACK_DUP_TSNS] = PHT("num-dup-tsns", 112, 16), ++ }, ++}; ++ ++static const struct exthdr_desc sctp_chunk_shutdown = { ++ .name = "shutdown", ++ .type = SCTP_CHUNK_TYPE_SHUTDOWN, ++ .templates = { ++ [SCTP_CHUNK_COMMON_TYPE] = PHT("type", 0, 8), ++ [SCTP_CHUNK_COMMON_FLAGS] = PHT("flags", 8, 8), ++ [SCTP_CHUNK_COMMON_LENGTH] = PHT("length", 16, 16), ++ [SCTP_CHUNK_SHUTDOWN_CTSN_ACK] = PHT("cum-tsn-ack", 32, 32), ++ }, ++}; ++ ++static const struct exthdr_desc sctp_chunk_ecne = { ++ .name = "ecne", ++ .type = SCTP_CHUNK_TYPE_ECNE, ++ .templates = { ++ [SCTP_CHUNK_COMMON_TYPE] = PHT("type", 0, 8), ++ [SCTP_CHUNK_COMMON_FLAGS] = PHT("flags", 8, 8), ++ [SCTP_CHUNK_COMMON_LENGTH] = PHT("length", 16, 16), ++ [SCTP_CHUNK_ECNE_CWR_MIN_TSN] = PHT("lowest-tsn", 32, 32), ++ }, ++}; ++ ++static const struct exthdr_desc sctp_chunk_cwr = { ++ .name = "cwr", ++ .type = SCTP_CHUNK_TYPE_CWR, ++ .templates = { ++ [SCTP_CHUNK_COMMON_TYPE] = PHT("type", 0, 8), ++ [SCTP_CHUNK_COMMON_FLAGS] = PHT("flags", 8, 8), ++ [SCTP_CHUNK_COMMON_LENGTH] = PHT("length", 16, 16), ++ [SCTP_CHUNK_ECNE_CWR_MIN_TSN] = PHT("lowest-tsn", 32, 32), ++ }, ++}; ++ ++static const struct exthdr_desc sctp_chunk_asconf_ack = { ++ .name = "asconf-ack", ++ .type = SCTP_CHUNK_TYPE_ASCONF_ACK, ++ .templates = { ++ [SCTP_CHUNK_COMMON_TYPE] = PHT("type", 0, 8), ++ [SCTP_CHUNK_COMMON_FLAGS] = PHT("flags", 8, 8), ++ [SCTP_CHUNK_COMMON_LENGTH] = PHT("length", 16, 16), ++ [SCTP_CHUNK_ASCONF_SEQNO] = PHT("seqno", 32, 32), ++ }, ++}; ++ ++static const struct exthdr_desc sctp_chunk_forward_tsn = { ++ .name = "forward-tsn", ++ .type = SCTP_CHUNK_TYPE_FORWARD_TSN, ++ .templates = { ++ [SCTP_CHUNK_COMMON_TYPE] = PHT("type", 0, 8), ++ [SCTP_CHUNK_COMMON_FLAGS] = PHT("flags", 8, 8), ++ [SCTP_CHUNK_COMMON_LENGTH] = PHT("length", 16, 16), ++ [SCTP_CHUNK_FORWARD_TSN_NCTSN] = PHT("new-cum-tsn", 32, 32), ++ }, ++}; ++ ++static const struct exthdr_desc sctp_chunk_asconf = { ++ .name = "asconf", ++ .type = SCTP_CHUNK_TYPE_ASCONF, ++ .templates = { ++ [SCTP_CHUNK_COMMON_TYPE] = PHT("type", 0, 8), ++ [SCTP_CHUNK_COMMON_FLAGS] = PHT("flags", 8, 8), ++ [SCTP_CHUNK_COMMON_LENGTH] = PHT("length", 16, 16), ++ [SCTP_CHUNK_ASCONF_SEQNO] = PHT("seqno", 32, 32), ++ }, ++}; ++ ++#define SCTP_CHUNK_DESC_GENERATOR(descname, hname, desctype) \ ++static const struct exthdr_desc sctp_chunk_##descname = { \ ++ .name = #hname, \ ++ .type = SCTP_CHUNK_TYPE_##desctype, \ ++ .templates = { \ ++ [SCTP_CHUNK_COMMON_TYPE] = PHT("type", 0, 8), \ ++ [SCTP_CHUNK_COMMON_FLAGS] = PHT("flags", 8, 8), \ ++ [SCTP_CHUNK_COMMON_LENGTH] = PHT("length", 16, 16),\ ++ }, \ ++}; ++ ++SCTP_CHUNK_DESC_GENERATOR(heartbeat, heartbeat, HEARTBEAT) ++SCTP_CHUNK_DESC_GENERATOR(heartbeat_ack, heartbeat-ack, HEARTBEAT_ACK) ++SCTP_CHUNK_DESC_GENERATOR(abort, abort, ABORT) ++SCTP_CHUNK_DESC_GENERATOR(shutdown_ack, shutdown-ack, SHUTDOWN_ACK) ++SCTP_CHUNK_DESC_GENERATOR(error, error, ERROR) ++SCTP_CHUNK_DESC_GENERATOR(cookie_echo, cookie-echo, COOKIE_ECHO) ++SCTP_CHUNK_DESC_GENERATOR(cookie_ack, cookie-ack, COOKIE_ACK) ++SCTP_CHUNK_DESC_GENERATOR(shutdown_complete, shutdown-complete, SHUTDOWN_COMPLETE) ++ ++#undef SCTP_CHUNK_DESC_GENERATOR ++ ++static const struct exthdr_desc *sctp_chunk_protocols[] = { ++ [SCTP_CHUNK_TYPE_DATA] = &sctp_chunk_data, ++ [SCTP_CHUNK_TYPE_INIT] = &sctp_chunk_init, ++ [SCTP_CHUNK_TYPE_INIT_ACK] = &sctp_chunk_init_ack, ++ [SCTP_CHUNK_TYPE_SACK] = &sctp_chunk_sack, ++ [SCTP_CHUNK_TYPE_HEARTBEAT] = &sctp_chunk_heartbeat, ++ [SCTP_CHUNK_TYPE_HEARTBEAT_ACK] = &sctp_chunk_heartbeat_ack, ++ [SCTP_CHUNK_TYPE_ABORT] = &sctp_chunk_abort, ++ [SCTP_CHUNK_TYPE_SHUTDOWN] = &sctp_chunk_shutdown, ++ [SCTP_CHUNK_TYPE_SHUTDOWN_ACK] = &sctp_chunk_shutdown_ack, ++ [SCTP_CHUNK_TYPE_ERROR] = &sctp_chunk_error, ++ [SCTP_CHUNK_TYPE_COOKIE_ECHO] = &sctp_chunk_cookie_echo, ++ [SCTP_CHUNK_TYPE_COOKIE_ACK] = &sctp_chunk_cookie_ack, ++ [SCTP_CHUNK_TYPE_ECNE] = &sctp_chunk_ecne, ++ [SCTP_CHUNK_TYPE_CWR] = &sctp_chunk_cwr, ++ [SCTP_CHUNK_TYPE_SHUTDOWN_COMPLETE] = &sctp_chunk_shutdown_complete, ++ [SCTP_CHUNK_TYPE_ASCONF_ACK] = &sctp_chunk_asconf_ack, ++ [SCTP_CHUNK_TYPE_FORWARD_TSN] = &sctp_chunk_forward_tsn, ++ [SCTP_CHUNK_TYPE_ASCONF] = &sctp_chunk_asconf, ++}; ++ ++const struct exthdr_desc *sctp_chunk_protocol_find(const char *name) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < array_size(sctp_chunk_protocols); i++) { ++ if (sctp_chunk_protocols[i] && ++ !strcmp(sctp_chunk_protocols[i]->name, name)) ++ return sctp_chunk_protocols[i]; ++ } ++ return NULL; ++} ++ ++struct expr *sctp_chunk_expr_alloc(const struct location *loc, ++ unsigned int type, unsigned int field) ++{ ++ const struct proto_hdr_template *tmpl; ++ const struct exthdr_desc *desc = NULL; ++ struct expr *expr; ++ ++ if (type < array_size(sctp_chunk_protocols)) ++ desc = sctp_chunk_protocols[type]; ++ ++ if (!desc) ++ return NULL; ++ ++ tmpl = &desc->templates[field]; ++ if (!tmpl) ++ return NULL; ++ ++ expr = expr_alloc(loc, EXPR_EXTHDR, tmpl->dtype, ++ BYTEORDER_BIG_ENDIAN, tmpl->len); ++ expr->exthdr.desc = desc; ++ expr->exthdr.tmpl = tmpl; ++ expr->exthdr.op = NFT_EXTHDR_OP_SCTP; ++ expr->exthdr.raw_type = desc->type; ++ expr->exthdr.offset = tmpl->offset; ++ ++ return expr; ++} ++ ++void sctp_chunk_init_raw(struct expr *expr, uint8_t type, unsigned int off, ++ unsigned int len, uint32_t flags) ++{ ++ const struct proto_hdr_template *tmpl; ++ unsigned int i; ++ ++ assert(expr->etype == EXPR_EXTHDR); ++ ++ expr->len = len; ++ expr->exthdr.flags = flags; ++ expr->exthdr.offset = off; ++ expr->exthdr.op = NFT_EXTHDR_OP_SCTP; ++ ++ if (flags & NFT_EXTHDR_F_PRESENT) ++ datatype_set(expr, &boolean_type); ++ else ++ datatype_set(expr, &integer_type); ++ ++ if (type >= array_size(sctp_chunk_protocols)) ++ return; ++ ++ expr->exthdr.desc = sctp_chunk_protocols[type]; ++ expr->exthdr.flags = flags; ++ assert(expr->exthdr.desc != NULL); ++ ++ for (i = 0; i < array_size(expr->exthdr.desc->templates); ++i) { ++ tmpl = &expr->exthdr.desc->templates[i]; ++ if (tmpl->offset != off || tmpl->len != len) ++ continue; ++ ++ if ((flags & NFT_EXTHDR_F_PRESENT) == 0) ++ datatype_set(expr, tmpl->dtype); ++ ++ expr->exthdr.tmpl = tmpl; ++ break; ++ } ++} +diff --git a/tests/py/inet/sctp.t b/tests/py/inet/sctp.t +index 5188b57..3d1c2fd 100644 +--- a/tests/py/inet/sctp.t ++++ b/tests/py/inet/sctp.t +@@ -41,3 +41,40 @@ sctp vtag {33, 55, 67, 88};ok + sctp vtag != {33, 55, 67, 88};ok + sctp vtag { 33-55};ok + sctp vtag != { 33-55};ok ++ ++# assert all chunk types are recognized ++sctp chunk data exists;ok ++sctp chunk init exists;ok ++sctp chunk init-ack exists;ok ++sctp chunk sack exists;ok ++sctp chunk heartbeat exists;ok ++sctp chunk heartbeat-ack exists;ok ++sctp chunk abort exists;ok ++sctp chunk shutdown exists;ok ++sctp chunk shutdown-ack exists;ok ++sctp chunk error exists;ok ++sctp chunk cookie-echo exists;ok ++sctp chunk cookie-ack exists;ok ++sctp chunk ecne exists;ok ++sctp chunk cwr exists;ok ++sctp chunk shutdown-complete exists;ok ++sctp chunk asconf-ack exists;ok ++sctp chunk forward-tsn exists;ok ++sctp chunk asconf exists;ok ++ ++# test common header fields in random chunk types ++sctp chunk data type 0;ok ++sctp chunk init flags 23;ok ++sctp chunk init-ack length 42;ok ++ ++# test one custom field in every applicable chunk type ++sctp chunk data stream 1337;ok ++sctp chunk init initial-tsn 5;ok ++sctp chunk init-ack num-outbound-streams 3;ok ++sctp chunk sack a-rwnd 1;ok ++sctp chunk shutdown cum-tsn-ack 65535;ok ++sctp chunk ecne lowest-tsn 5;ok ++sctp chunk cwr lowest-tsn 8;ok ++sctp chunk asconf-ack seqno 12345;ok ++sctp chunk forward-tsn new-cum-tsn 31337;ok ++sctp chunk asconf seqno 12345;ok +diff --git a/tests/py/inet/sctp.t.json b/tests/py/inet/sctp.t.json +index 2684b03..8135686 100644 +--- a/tests/py/inet/sctp.t.json ++++ b/tests/py/inet/sctp.t.json +@@ -608,3 +608,481 @@ + } + ] + ++# sctp chunk data exists ++[ ++ { ++ "match": { ++ "left": { ++ "sctp chunk": { ++ "name": "data" ++ } ++ }, ++ "op": "==", ++ "right": true ++ } ++ } ++] ++ ++# sctp chunk init exists ++[ ++ { ++ "match": { ++ "left": { ++ "sctp chunk": { ++ "name": "init" ++ } ++ }, ++ "op": "==", ++ "right": true ++ } ++ } ++] ++ ++# sctp chunk init-ack exists ++[ ++ { ++ "match": { ++ "left": { ++ "sctp chunk": { ++ "name": "init-ack" ++ } ++ }, ++ "op": "==", ++ "right": true ++ } ++ } ++] ++ ++# sctp chunk sack exists ++[ ++ { ++ "match": { ++ "left": { ++ "sctp chunk": { ++ "name": "sack" ++ } ++ }, ++ "op": "==", ++ "right": true ++ } ++ } ++] ++ ++# sctp chunk heartbeat exists ++[ ++ { ++ "match": { ++ "left": { ++ "sctp chunk": { ++ "name": "heartbeat" ++ } ++ }, ++ "op": "==", ++ "right": true ++ } ++ } ++] ++ ++# sctp chunk heartbeat-ack exists ++[ ++ { ++ "match": { ++ "left": { ++ "sctp chunk": { ++ "name": "heartbeat-ack" ++ } ++ }, ++ "op": "==", ++ "right": true ++ } ++ } ++] ++ ++# sctp chunk abort exists ++[ ++ { ++ "match": { ++ "left": { ++ "sctp chunk": { ++ "name": "abort" ++ } ++ }, ++ "op": "==", ++ "right": true ++ } ++ } ++] ++ ++# sctp chunk shutdown exists ++[ ++ { ++ "match": { ++ "left": { ++ "sctp chunk": { ++ "name": "shutdown" ++ } ++ }, ++ "op": "==", ++ "right": true ++ } ++ } ++] ++ ++# sctp chunk shutdown-ack exists ++[ ++ { ++ "match": { ++ "left": { ++ "sctp chunk": { ++ "name": "shutdown-ack" ++ } ++ }, ++ "op": "==", ++ "right": true ++ } ++ } ++] ++ ++# sctp chunk error exists ++[ ++ { ++ "match": { ++ "left": { ++ "sctp chunk": { ++ "name": "error" ++ } ++ }, ++ "op": "==", ++ "right": true ++ } ++ } ++] ++ ++# sctp chunk cookie-echo exists ++[ ++ { ++ "match": { ++ "left": { ++ "sctp chunk": { ++ "name": "cookie-echo" ++ } ++ }, ++ "op": "==", ++ "right": true ++ } ++ } ++] ++ ++# sctp chunk cookie-ack exists ++[ ++ { ++ "match": { ++ "left": { ++ "sctp chunk": { ++ "name": "cookie-ack" ++ } ++ }, ++ "op": "==", ++ "right": true ++ } ++ } ++] ++ ++# sctp chunk ecne exists ++[ ++ { ++ "match": { ++ "left": { ++ "sctp chunk": { ++ "name": "ecne" ++ } ++ }, ++ "op": "==", ++ "right": true ++ } ++ } ++] ++ ++# sctp chunk cwr exists ++[ ++ { ++ "match": { ++ "left": { ++ "sctp chunk": { ++ "name": "cwr" ++ } ++ }, ++ "op": "==", ++ "right": true ++ } ++ } ++] ++ ++# sctp chunk shutdown-complete exists ++[ ++ { ++ "match": { ++ "left": { ++ "sctp chunk": { ++ "name": "shutdown-complete" ++ } ++ }, ++ "op": "==", ++ "right": true ++ } ++ } ++] ++ ++# sctp chunk asconf-ack exists ++[ ++ { ++ "match": { ++ "left": { ++ "sctp chunk": { ++ "name": "asconf-ack" ++ } ++ }, ++ "op": "==", ++ "right": true ++ } ++ } ++] ++ ++# sctp chunk forward-tsn exists ++[ ++ { ++ "match": { ++ "left": { ++ "sctp chunk": { ++ "name": "forward-tsn" ++ } ++ }, ++ "op": "==", ++ "right": true ++ } ++ } ++] ++ ++# sctp chunk asconf exists ++[ ++ { ++ "match": { ++ "left": { ++ "sctp chunk": { ++ "name": "asconf" ++ } ++ }, ++ "op": "==", ++ "right": true ++ } ++ } ++] ++ ++# sctp chunk data type 0 ++[ ++ { ++ "match": { ++ "left": { ++ "sctp chunk": { ++ "field": "type", ++ "name": "data" ++ } ++ }, ++ "op": "==", ++ "right": 0 ++ } ++ } ++] ++ ++# sctp chunk init flags 23 ++[ ++ { ++ "match": { ++ "left": { ++ "sctp chunk": { ++ "field": "flags", ++ "name": "init" ++ } ++ }, ++ "op": "==", ++ "right": 23 ++ } ++ } ++] ++ ++# sctp chunk init-ack length 42 ++[ ++ { ++ "match": { ++ "left": { ++ "sctp chunk": { ++ "field": "length", ++ "name": "init-ack" ++ } ++ }, ++ "op": "==", ++ "right": 42 ++ } ++ } ++] ++ ++# sctp chunk data stream 1337 ++[ ++ { ++ "match": { ++ "left": { ++ "sctp chunk": { ++ "field": "stream", ++ "name": "data" ++ } ++ }, ++ "op": "==", ++ "right": 1337 ++ } ++ } ++] ++ ++# sctp chunk init initial-tsn 5 ++[ ++ { ++ "match": { ++ "left": { ++ "sctp chunk": { ++ "field": "initial-tsn", ++ "name": "init" ++ } ++ }, ++ "op": "==", ++ "right": 5 ++ } ++ } ++] ++ ++# sctp chunk init-ack num-outbound-streams 3 ++[ ++ { ++ "match": { ++ "left": { ++ "sctp chunk": { ++ "field": "num-outbound-streams", ++ "name": "init-ack" ++ } ++ }, ++ "op": "==", ++ "right": 3 ++ } ++ } ++] ++ ++# sctp chunk sack a-rwnd 1 ++[ ++ { ++ "match": { ++ "left": { ++ "sctp chunk": { ++ "field": "a-rwnd", ++ "name": "sack" ++ } ++ }, ++ "op": "==", ++ "right": 1 ++ } ++ } ++] ++ ++# sctp chunk shutdown cum-tsn-ack 65535 ++[ ++ { ++ "match": { ++ "left": { ++ "sctp chunk": { ++ "field": "cum-tsn-ack", ++ "name": "shutdown" ++ } ++ }, ++ "op": "==", ++ "right": 65535 ++ } ++ } ++] ++ ++# sctp chunk ecne lowest-tsn 5 ++[ ++ { ++ "match": { ++ "left": { ++ "sctp chunk": { ++ "field": "lowest-tsn", ++ "name": "ecne" ++ } ++ }, ++ "op": "==", ++ "right": 5 ++ } ++ } ++] ++ ++# sctp chunk cwr lowest-tsn 8 ++[ ++ { ++ "match": { ++ "left": { ++ "sctp chunk": { ++ "field": "lowest-tsn", ++ "name": "cwr" ++ } ++ }, ++ "op": "==", ++ "right": 8 ++ } ++ } ++] ++ ++# sctp chunk asconf-ack seqno 12345 ++[ ++ { ++ "match": { ++ "left": { ++ "sctp chunk": { ++ "field": "seqno", ++ "name": "asconf-ack" ++ } ++ }, ++ "op": "==", ++ "right": 12345 ++ } ++ } ++] ++ ++# sctp chunk forward-tsn new-cum-tsn 31337 ++[ ++ { ++ "match": { ++ "left": { ++ "sctp chunk": { ++ "field": "new-cum-tsn", ++ "name": "forward-tsn" ++ } ++ }, ++ "op": "==", ++ "right": 31337 ++ } ++ } ++] ++ ++# sctp chunk asconf seqno 12345 ++[ ++ { ++ "match": { ++ "left": { ++ "sctp chunk": { ++ "field": "seqno", ++ "name": "asconf" ++ } ++ }, ++ "op": "==", ++ "right": 12345 ++ } ++ } ++] ++ +diff --git a/tests/py/inet/sctp.t.payload b/tests/py/inet/sctp.t.payload +index ecfcc72..9c4854c 100644 +--- a/tests/py/inet/sctp.t.payload ++++ b/tests/py/inet/sctp.t.payload +@@ -274,3 +274,158 @@ inet test-inet input + [ payload load 4b @ transport header + 4 => reg 1 ] + [ lookup reg 1 set __set%d 0x1 ] + ++# sctp chunk data exists ++ip ++ [ exthdr load 1b @ 0 + 0 present => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# sctp chunk init exists ++ip ++ [ exthdr load 1b @ 1 + 0 present => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# sctp chunk init-ack exists ++ip ++ [ exthdr load 1b @ 2 + 0 present => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# sctp chunk sack exists ++ip ++ [ exthdr load 1b @ 3 + 0 present => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# sctp chunk heartbeat exists ++ip ++ [ exthdr load 1b @ 4 + 0 present => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# sctp chunk heartbeat-ack exists ++ip ++ [ exthdr load 1b @ 5 + 0 present => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# sctp chunk abort exists ++ip ++ [ exthdr load 1b @ 6 + 0 present => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# sctp chunk shutdown exists ++ip ++ [ exthdr load 1b @ 7 + 0 present => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# sctp chunk shutdown-ack exists ++ip ++ [ exthdr load 1b @ 8 + 0 present => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# sctp chunk error exists ++ip ++ [ exthdr load 1b @ 9 + 0 present => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# sctp chunk cookie-echo exists ++ip ++ [ exthdr load 1b @ 10 + 0 present => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# sctp chunk cookie-ack exists ++ip ++ [ exthdr load 1b @ 11 + 0 present => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# sctp chunk ecne exists ++ip ++ [ exthdr load 1b @ 12 + 0 present => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# sctp chunk cwr exists ++ip ++ [ exthdr load 1b @ 13 + 0 present => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# sctp chunk shutdown-complete exists ++ip ++ [ exthdr load 1b @ 14 + 0 present => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# sctp chunk asconf-ack exists ++ip ++ [ exthdr load 1b @ 128 + 0 present => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# sctp chunk forward-tsn exists ++ip ++ [ exthdr load 1b @ 192 + 0 present => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# sctp chunk asconf exists ++ip ++ [ exthdr load 1b @ 193 + 0 present => reg 1 ] ++ [ cmp eq reg 1 0x00000001 ] ++ ++# sctp chunk data type 0 ++ip ++ [ exthdr load 1b @ 0 + 0 => reg 1 ] ++ [ cmp eq reg 1 0x00000000 ] ++ ++# sctp chunk init flags 23 ++ip ++ [ exthdr load 1b @ 1 + 1 => reg 1 ] ++ [ cmp eq reg 1 0x00000017 ] ++ ++# sctp chunk init-ack length 42 ++ip ++ [ exthdr load 2b @ 2 + 2 => reg 1 ] ++ [ cmp eq reg 1 0x00002a00 ] ++ ++# sctp chunk data stream 1337 ++ip ++ [ exthdr load 2b @ 0 + 8 => reg 1 ] ++ [ cmp eq reg 1 0x00003905 ] ++ ++# sctp chunk init initial-tsn 5 ++ip ++ [ exthdr load 4b @ 1 + 16 => reg 1 ] ++ [ cmp eq reg 1 0x05000000 ] ++ ++# sctp chunk init-ack num-outbound-streams 3 ++ip ++ [ exthdr load 2b @ 2 + 12 => reg 1 ] ++ [ cmp eq reg 1 0x00000300 ] ++ ++# sctp chunk sack a-rwnd 1 ++ip ++ [ exthdr load 4b @ 3 + 8 => reg 1 ] ++ [ cmp eq reg 1 0x01000000 ] ++ ++# sctp chunk shutdown cum-tsn-ack 65535 ++ip ++ [ exthdr load 4b @ 7 + 4 => reg 1 ] ++ [ cmp eq reg 1 0xffff0000 ] ++ ++# sctp chunk ecne lowest-tsn 5 ++ip ++ [ exthdr load 4b @ 12 + 4 => reg 1 ] ++ [ cmp eq reg 1 0x05000000 ] ++ ++# sctp chunk cwr lowest-tsn 8 ++ip ++ [ exthdr load 4b @ 13 + 4 => reg 1 ] ++ [ cmp eq reg 1 0x08000000 ] ++ ++# sctp chunk asconf-ack seqno 12345 ++ip ++ [ exthdr load 4b @ 128 + 4 => reg 1 ] ++ [ cmp eq reg 1 0x39300000 ] ++ ++# sctp chunk forward-tsn new-cum-tsn 31337 ++ip ++ [ exthdr load 4b @ 192 + 4 => reg 1 ] ++ [ cmp eq reg 1 0x697a0000 ] ++ ++# sctp chunk asconf seqno 12345 ++ip ++ [ exthdr load 4b @ 193 + 4 => reg 1 ] ++ [ cmp eq reg 1 0x39300000 ] ++ +-- +2.31.1 + diff --git a/SOURCES/0060-include-missing-sctp_chunk.h-in-Makefile.am.patch b/SOURCES/0060-include-missing-sctp_chunk.h-in-Makefile.am.patch new file mode 100644 index 0000000..9bafe70 --- /dev/null +++ b/SOURCES/0060-include-missing-sctp_chunk.h-in-Makefile.am.patch @@ -0,0 +1,37 @@ +From 7ba8ea2cf06230e647b096f40d3006abec45f801 Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Mon, 12 Jul 2021 16:33:20 +0200 +Subject: [PATCH] include: missing sctp_chunk.h in Makefile.am + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1979334 +Upstream Status: nftables commit 117ceb4f52711 + +commit 117ceb4f527119a6d44bf5e23f2ff7a8d116658a +Author: Pablo Neira Ayuso +Date: Tue May 25 14:04:36 2021 +0200 + + include: missing sctp_chunk.h in Makefile.am + + Fix make distcheck. + + Fixes: 0e3871cfd9a1 ("exthdr: Implement SCTP Chunk matching") + Signed-off-by: Pablo Neira Ayuso +--- + include/Makefile.am | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/include/Makefile.am b/include/Makefile.am +index 04a4a61..4ee5124 100644 +--- a/include/Makefile.am ++++ b/include/Makefile.am +@@ -30,6 +30,7 @@ noinst_HEADERS = cli.h \ + osf.h \ + parser.h \ + proto.h \ ++ sctp_chunk.h \ + socket.h \ + rule.h \ + rt.h \ +-- +2.31.1 + diff --git a/SOURCES/0061-doc-nft.8-Extend-monitor-description-by-trace.patch b/SOURCES/0061-doc-nft.8-Extend-monitor-description-by-trace.patch new file mode 100644 index 0000000..1d4174d --- /dev/null +++ b/SOURCES/0061-doc-nft.8-Extend-monitor-description-by-trace.patch @@ -0,0 +1,71 @@ +From 5a735f26b0c6617b2851a7399c8ad118e89deba8 Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Mon, 12 Jul 2021 16:34:38 +0200 +Subject: [PATCH] doc: nft.8: Extend monitor description by trace + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1820365 +Upstream Status: nftables commit 2acf8b2caea19 + +commit 2acf8b2caea19d8abd46d475a908f8d6afb33aa0 +Author: Phil Sutter +Date: Wed May 19 13:12:48 2021 +0200 + + doc: nft.8: Extend monitor description by trace + + Briefly describe 'nft monitor trace' command functionality. + + Signed-off-by: Phil Sutter +--- + doc/nft.txt | 25 ++++++++++++++++++++++--- + 1 file changed, 22 insertions(+), 3 deletions(-) + +diff --git a/doc/nft.txt b/doc/nft.txt +index abb9260..9cc35ee 100644 +--- a/doc/nft.txt ++++ b/doc/nft.txt +@@ -734,13 +734,26 @@ These are some additional commands included in nft. + MONITOR + ~~~~~~~~ + The monitor command allows you to listen to Netlink events produced by the +-nf_tables subsystem, related to creation and deletion of objects. When they ++nf_tables subsystem. These are either related to creation and deletion of ++objects or to packets for which *meta nftrace* was enabled. When they + occur, nft will print to stdout the monitored events in either JSON or + native nft format. + + +-To filter events related to a concrete object, use one of the keywords 'tables', 'chains', 'sets', 'rules', 'elements', 'ruleset'. + ++[verse] ++____ ++*monitor* [*new* | *destroy*] 'MONITOR_OBJECT' ++*monitor* *trace* ++ ++'MONITOR_OBJECT' := *tables* | *chains* | *sets* | *rules* | *elements* | *ruleset* ++____ ++ ++To filter events related to a concrete object, use one of the keywords in ++'MONITOR_OBJECT'. + +-To filter events related to a concrete action, use keyword 'new' or 'destroy'. ++To filter events related to a concrete action, use keyword *new* or *destroy*. ++ ++The second form of invocation takes no further options and exclusively prints ++events generated for packets with *nftrace* enabled. + + Hit ^C to finish the monitor operation. + +@@ -764,6 +777,12 @@ Hit ^C to finish the monitor operation. + % nft monitor ruleset + --------------------- + ++.Trace incoming packets from host 10.0.0.1 ++------------------------------------------ ++% nft add rule filter input ip saddr 10.0.0.1 meta nftrace set 1 ++% nft monitor trace ++------------------------------------------ ++ + ERROR REPORTING + --------------- + When an error is detected, nft shows the line(s) containing the error, the +-- +2.31.1 + diff --git a/SOURCES/0062-tests-shell-Fix-bogus-testsuite-failure-with-100Hz.patch b/SOURCES/0062-tests-shell-Fix-bogus-testsuite-failure-with-100Hz.patch new file mode 100644 index 0000000..0c6f24b --- /dev/null +++ b/SOURCES/0062-tests-shell-Fix-bogus-testsuite-failure-with-100Hz.patch @@ -0,0 +1,44 @@ +From e8300966510001e38f2b6530607bac2a93de5c2e Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Mon, 2 Aug 2021 14:35:08 +0200 +Subject: [PATCH] tests: shell: Fix bogus testsuite failure with 100Hz + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1919203 +Upstream Status: nftables commit c9c5b5f621c37 + +commit c9c5b5f621c37d17140dac682d211825ef321093 +Author: Phil Sutter +Date: Mon Jul 26 15:27:32 2021 +0200 + + tests: shell: Fix bogus testsuite failure with 100Hz + + On kernels with CONFIG_HZ=100, clock granularity does not allow tracking + timeouts in single digit ms range. Change sets/0031set_timeout_size_0 to + not expose this detail. + + Signed-off-by: Phil Sutter + Acked-by: Florian Westphal +--- + tests/shell/testcases/sets/0031set_timeout_size_0 | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/tests/shell/testcases/sets/0031set_timeout_size_0 b/tests/shell/testcases/sets/0031set_timeout_size_0 +index 9edd5f6..796640d 100755 +--- a/tests/shell/testcases/sets/0031set_timeout_size_0 ++++ b/tests/shell/testcases/sets/0031set_timeout_size_0 +@@ -3,10 +3,10 @@ + RULESET="add table x + add set x y { type ipv4_addr; size 128; timeout 30s; flags dynamic; } + add chain x test +-add rule x test set update ip saddr timeout 1d2h3m4s8ms @y ++add rule x test set update ip saddr timeout 1d2h3m4s10ms @y + add rule x test set update ip daddr timeout 100ms @y" + + set -e + $NFT -f - <<< "$RULESET" +-$NFT list chain x test | grep -q 'update @y { ip saddr timeout 1d2h3m4s8ms }' ++$NFT list chain x test | grep -q 'update @y { ip saddr timeout 1d2h3m4s10ms }' + $NFT list chain x test | grep -q 'update @y { ip daddr timeout 100ms }' +-- +2.31.1 + diff --git a/SPECS/nftables.spec b/SPECS/nftables.spec index a45844a..8a4bcdf 100644 --- a/SPECS/nftables.spec +++ b/SPECS/nftables.spec @@ -1,5 +1,5 @@ %define rpmversion 0.9.3 -%define specrelease 20 +%define specrelease 21 Name: nftables Version: %{rpmversion} @@ -64,6 +64,21 @@ Patch44: 0044-tests-monitor-use-correct-nft-value-in-EXIT-trap.patch Patch45: 0045-evaluate-Reject-quoted-strings-containing-only-wildc.patch Patch46: 0046-src-Support-odd-sized-payload-matches.patch Patch47: 0047-src-Optimize-prefix-matches-on-byte-boundaries.patch +Patch48: 0048-tests-py-Move-tcpopt.t-to-any-directory.patch +Patch49: 0049-parser-merge-sack-perm-sack-permitted-and-maxseg-mss.patch +Patch50: 0050-tcpopts-clean-up-parser-tcpopt.c-plumbing.patch +Patch51: 0051-tcpopt-rename-noop-to-nop.patch +Patch52: 0052-tcpopt-split-tcpopt_hdr_fields-into-per-option-enum.patch +Patch53: 0053-tcpopt-allow-to-check-for-presence-of-any-tcp-option.patch +Patch54: 0054-tcp-add-raw-tcp-option-match-support.patch +Patch55: 0055-json-tcp-add-raw-tcp-option-match-support.patch +Patch56: 0056-json-Simplify-non-tcpopt-exthdr-printing-a-bit.patch +Patch57: 0057-scanner-introduce-start-condition-stack.patch +Patch58: 0058-scanner-sctp-Move-to-own-scope.patch +Patch59: 0059-exthdr-Implement-SCTP-Chunk-matching.patch +Patch60: 0060-include-missing-sctp_chunk.h-in-Makefile.am.patch +Patch61: 0061-doc-nft.8-Extend-monitor-description-by-trace.patch +Patch62: 0062-tests-shell-Fix-bogus-testsuite-failure-with-100Hz.patch BuildRequires: autogen BuildRequires: autoconf @@ -180,6 +195,23 @@ touch -r %{SOURCE2} $RPM_BUILD_ROOT/%{python3_sitelib}/nftables/nftables.py %{python3_sitelib}/nftables/ %changelog +* Mon Aug 02 2021 Phil Sutter [0.9.3-21.el8] +- tests: shell: Fix bogus testsuite failure with 100Hz (Phil Sutter) [1919203] +- doc: nft.8: Extend monitor description by trace (Phil Sutter) [1820365] +- include: missing sctp_chunk.h in Makefile.am (Phil Sutter) [1979334] +- exthdr: Implement SCTP Chunk matching (Phil Sutter) [1979334] +- scanner: sctp: Move to own scope (Phil Sutter) [1979334] +- scanner: introduce start condition stack (Phil Sutter) [1979334] +- json: Simplify non-tcpopt exthdr printing a bit (Phil Sutter) [1979334] +- json: tcp: add raw tcp option match support (Phil Sutter) [1979334] +- tcp: add raw tcp option match support (Phil Sutter) [1979334] +- tcpopt: allow to check for presence of any tcp option (Phil Sutter) [1979334] +- tcpopt: split tcpopt_hdr_fields into per-option enum (Phil Sutter) [1979334] +- tcpopt: rename noop to nop (Phil Sutter) [1979334] +- tcpopts: clean up parser -> tcpopt.c plumbing (Phil Sutter) [1979334] +- parser: merge sack-perm/sack-permitted and maxseg/mss (Phil Sutter) [1979334] +- tests/py: Move tcpopt.t to any/ directory (Phil Sutter) [1979334] + * Thu May 20 2021 Phil Sutter [0.9.3-20.el8] - src: Optimize prefix matches on byte-boundaries (Phil Sutter) [1934926] - src: Support odd-sized payload matches (Phil Sutter) [1934926]