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 <fw@strlen.de>
/* 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;
*/
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;
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;
}
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;
}
#define NFTNL_UDATA_EXTHDR_DESC 0
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;
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)
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;
}
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));
| 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; }
[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)
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;
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;
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;
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;
}
}
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
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
[ 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 ]
[ 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
[ 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 ]
[ 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 ]