@@ -239,6 +239,9 @@ static struct expr *payload_expr_parse_udata(const struct nftnl_udata *attr)
expr = payload_expr_alloc(&internal_location, desc, type);
+ if (desc == &proto_th)
+ expr->payload.is_raw = true;
+
if (len)
expr->len = len;
new file mode 100755
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+# 'th dport' in a typeof map is restored from set userdata. A later
+# transaction re-evaluating it must not fail with a bogus
+# "conflicting transport layer protocols specified: tcp vs. th".
+
+set -e
+
+$NFT -f - <<EOF
+table ip t {
+ map m {
+ typeof ip saddr : ip daddr . th dport
+ elements = { 10.1.1.1 : 10.2.3.4 . 4242 }
+ }
+
+ chain c {
+ type nat hook prerouting priority dstnat; policy accept;
+ meta l4proto tcp dnat ip to ip saddr map @m
+ }
+
+ chain d {
+ type nat hook prerouting priority dstnat; policy accept;
+ }
+}
+EOF
+
+# separate transaction
+$NFT add rule 'ip t d meta l4proto tcp dnat ip addr . port to ip saddr map @m'
payload_expr_parse_udata() restores the pseudo transport header (th) proto desc from set userdata, but not payload.is_raw. The bison and json parsers both set is_raw for raw th expressions, which makes evaluation skip the transport protocol conflict check. Without it, re-evaluating a map declared with 'typeof ... th dport ...' from a later transaction fails with a bogus conflicting transport layer protocols specified: tcp vs. th Set is_raw when the restored desc is proto_th, just like the parsers do. Signed-off-by: Adrian Moisey <adrian@changeover.za.net> --- src/payload.c | 3 ++ .../testcases/maps/typeof_maps_restore_0 | 28 +++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100755 tests/shell/testcases/maps/typeof_maps_restore_0