A few keys in the ct expression are directional, i.e.
we need to tell kernel if it should fetch REPLY or ORIGINAL direction.
Split ct_keys into ct_keys & ct_keys_dir, the latter are those keys
that the kernel rejects unless also given a direction.
During postprocessing we also need to invoke ct_expr_update_type,
problem is that e.g. ct saddr can be any family (ip, ipv6) so we need
to update the expected data type based on the network base.
Signed-off-by: Florian Westphal <fw@strlen.de>
}
extern struct expr *ct_expr_alloc(const struct location *loc,
- enum nft_ct_keys key);
+ enum nft_ct_keys key, int8_t direction);
extern void ct_expr_update_type(struct proto_ctx *ctx, struct expr *expr);
+extern struct error_record *ct_dir_parse(const struct location *loc,
+ const char *str, int8_t *dir);
#endif /* NFTABLES_CT_H */
struct {
/* EXPR_CT */
enum nft_ct_keys key;
+ int8_t direction;
} ct;
};
};
static void ct_expr_print(const struct expr *expr)
{
+ const struct symbolic_constant *s;
+
printf("ct %s", ct_templates[expr->ct.key].token);
+
+ if (expr->ct.direction < 0)
+ return;
+
+ for (s = ct_dir_tbl.symbols; s->identifier != NULL; s++) {
+ if (expr->ct.direction == (int) s->value) {
+ printf(" %s", s->identifier);
+ return;
+ }
+ }
+
+ printf(" %d", expr->ct.direction);
}
static bool ct_expr_cmp(const struct expr *e1, const struct expr *e2)
{
- return e1->ct.key == e2->ct.key;
+ if (e1->ct.key != e2->ct.key)
+ return false;
+
+ return e1->ct.direction == e2->ct.direction;
}
static void ct_expr_clone(struct expr *new, const struct expr *expr)
{
- new->ct.key = expr->ct.key;
+ new->ct = expr->ct;
}
static void ct_expr_pctx_update(struct proto_ctx *ctx, const struct expr *expr)
.pctx_update = ct_expr_pctx_update,
};
-struct expr *ct_expr_alloc(const struct location *loc, enum nft_ct_keys key)
+struct error_record *ct_dir_parse(const struct location *loc, const char *str,
+ int8_t *direction)
+{
+ const struct symbolic_constant *s;
+
+ for (s = ct_dir_tbl.symbols; s->identifier != NULL; s++) {
+ if (!strcmp(str, s->identifier)) {
+ *direction = s->value;
+ return NULL;
+ }
+ }
+
+ return error(loc, "Could not parse direction %s", str);
+}
+
+struct expr *ct_expr_alloc(const struct location *loc, enum nft_ct_keys key,
+ int8_t direction)
{
const struct ct_template *tmpl = &ct_templates[key];
struct expr *expr;
expr = expr_alloc(loc, &ct_expr_ops, tmpl->dtype,
tmpl->byteorder, tmpl->len);
expr->ct.key = key;
+ expr->ct.direction = direction;
switch (key) {
case NFT_CT_PROTOCOL:
const struct location *loc,
const struct nftnl_expr *nle)
{
+ struct expr *expr = NULL;
enum nft_registers dreg;
+ int8_t dir = -1;
uint32_t key;
- struct expr *expr;
+
+ if (nftnl_expr_is_set(nle, NFTNL_EXPR_CT_DIR))
+ dir = nftnl_expr_get_u8(nle, NFTNL_EXPR_CT_DIR);
key = nftnl_expr_get_u32(nle, NFTNL_EXPR_CT_KEY);
- expr = ct_expr_alloc(loc, key);
+ expr = ct_expr_alloc(loc, key, dir);
dreg = netlink_parse_register(nle, NFTNL_EXPR_CT_DREG);
netlink_set_register(ctx, dreg, expr);
}
}
+static void ct_match_postprocess(struct rule_pp_ctx *ctx,
+ const struct expr *expr)
+{
+ return meta_match_postprocess(ctx, expr);
+}
+
/* Convert a bitmask to a prefix length */
static unsigned int expr_mask_to_prefix(const struct expr *expr)
{
expr_postprocess(ctx, &expr->right);
switch (expr->left->ops->type) {
+ case EXPR_CT:
+ ct_match_postprocess(ctx, expr);
+ break;
case EXPR_META:
meta_match_postprocess(ctx, expr);
break;
case EXPR_SET_REF:
case EXPR_EXTHDR:
case EXPR_META:
- case EXPR_CT:
case EXPR_VERDICT:
break;
+ case EXPR_CT:
+ ct_expr_update_type(&ctx->pctx, expr);
+ break;
default:
BUG("unknown expression type %s\n", expr->ops->name);
}
nle = alloc_nft_expr("ct");
netlink_put_register(nle, NFTNL_EXPR_CT_DREG, dreg);
nftnl_expr_set_u32(nle, NFTNL_EXPR_CT_KEY, expr->ct.key);
+ if (expr->ct.direction >= 0)
+ nftnl_expr_set_u8(nle, NFTNL_EXPR_CT_DIR,
+ expr->ct.direction);
+
nftnl_rule_add_expr(ctx->nlr, nle);
}
%type <expr> ct_expr
%destructor { expr_free($$); } ct_expr
-%type <val> ct_key
+%type <val> ct_key ct_key_dir
%type <val> export_format
%type <string> monitor_event
}
;
-ct_expr : CT ct_key
+ct_expr : CT ct_key
{
- $$ = ct_expr_alloc(&@$, $2);
+ $$ = ct_expr_alloc(&@$, $2, -1);
+ }
+ | CT ct_key_dir STRING
+ {
+ struct error_record *erec;
+ int8_t direction;
+
+ erec = ct_dir_parse(&@$, $3, &direction);
+ if (erec != NULL) {
+ erec_queue(erec, state->msgs);
+ YYERROR;
+ }
+
+ $$ = ct_expr_alloc(&@$, $2, direction);
}
;
| MARK { $$ = NFT_CT_MARK; }
| EXPIRATION { $$ = NFT_CT_EXPIRATION; }
| HELPER { $$ = NFT_CT_HELPER; }
- | L3PROTOCOL { $$ = NFT_CT_L3PROTOCOL; }
- | SADDR { $$ = NFT_CT_SRC; }
+ | LABEL { $$ = NFT_CT_LABELS; }
+ ;
+ct_key_dir : SADDR { $$ = NFT_CT_SRC; }
| DADDR { $$ = NFT_CT_DST; }
+ | L3PROTOCOL { $$ = NFT_CT_L3PROTOCOL; }
| PROTOCOL { $$ = NFT_CT_PROTOCOL; }
| PROTO_SRC { $$ = NFT_CT_PROTO_SRC; }
| PROTO_DST { $$ = NFT_CT_PROTO_DST; }
- | LABEL { $$ = NFT_CT_LABELS; }
;
ct_stmt : CT ct_key SET expr