summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/expression.h4
-rw-r--r--include/proto.h11
-rw-r--r--src/ct.c8
-rw-r--r--src/evaluate.c14
-rw-r--r--src/expression.c16
-rw-r--r--src/meta.c13
-rw-r--r--src/payload.c7
-rw-r--r--src/proto.c57
-rw-r--r--tests/py/inet/dnat.t5
-rw-r--r--tests/py/inet/dnat.t.payload25
10 files changed, 142 insertions, 18 deletions
diff --git a/include/expression.h b/include/expression.h
index 130912a8..b039882c 100644
--- a/include/expression.h
+++ b/include/expression.h
@@ -167,7 +167,9 @@ struct expr_ops {
bool (*cmp)(const struct expr *e1,
const struct expr *e2);
void (*pctx_update)(struct proto_ctx *ctx,
- const struct expr *expr);
+ const struct location *loc,
+ const struct expr *left,
+ const struct expr *right);
int (*build_udata)(struct nftnl_udata_buf *udbuf,
const struct expr *expr);
struct expr * (*parse_udata)(const struct nftnl_udata *ud);
diff --git a/include/proto.h b/include/proto.h
index 1771ba8e..304b048e 100644
--- a/include/proto.h
+++ b/include/proto.h
@@ -152,6 +152,8 @@ struct dev_proto_desc {
extern int proto_dev_type(const struct proto_desc *desc, uint16_t *res);
extern const struct proto_desc *proto_dev_desc(uint16_t type);
+#define PROTO_CTX_NUM_PROTOS 16
+
/**
* struct proto_ctx - protocol context
*
@@ -172,6 +174,11 @@ struct proto_ctx {
struct location location;
const struct proto_desc *desc;
unsigned int offset;
+ struct {
+ struct location location;
+ const struct proto_desc *desc;
+ } protos[PROTO_CTX_NUM_PROTOS];
+ unsigned int num_protos;
} protocol[PROTO_BASE_MAX + 1];
};
@@ -180,6 +187,10 @@ extern void proto_ctx_init(struct proto_ctx *ctx, unsigned int family,
extern void proto_ctx_update(struct proto_ctx *ctx, enum proto_bases base,
const struct location *loc,
const struct proto_desc *desc);
+bool proto_ctx_is_ambiguous(struct proto_ctx *ctx, enum proto_bases bases);
+const struct proto_desc *proto_ctx_find_conflict(struct proto_ctx *ctx,
+ enum proto_bases base,
+ const struct proto_desc *desc);
extern const struct proto_desc *proto_find_upper(const struct proto_desc *base,
unsigned int num);
extern int proto_find_num(const struct proto_desc *base,
diff --git a/src/ct.c b/src/ct.c
index 0842c838..2218ecc7 100644
--- a/src/ct.c
+++ b/src/ct.c
@@ -351,9 +351,11 @@ static void ct_expr_clone(struct expr *new, const struct expr *expr)
new->ct = expr->ct;
}
-static void ct_expr_pctx_update(struct proto_ctx *ctx, const struct expr *expr)
+static void ct_expr_pctx_update(struct proto_ctx *ctx,
+ const struct location *loc,
+ const struct expr *left,
+ const struct expr *right)
{
- const struct expr *left = expr->left, *right = expr->right;
const struct proto_desc *base = NULL, *desc;
uint32_t nhproto;
@@ -366,7 +368,7 @@ static void ct_expr_pctx_update(struct proto_ctx *ctx, const struct expr *expr)
if (!desc)
return;
- proto_ctx_update(ctx, left->ct.base + 1, &expr->location, desc);
+ proto_ctx_update(ctx, left->ct.base + 1, loc, desc);
}
#define NFTNL_UDATA_CT_KEY 0
diff --git a/src/evaluate.c b/src/evaluate.c
index e3fe7062..c8045e5d 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -710,6 +710,17 @@ static int __expr_evaluate_payload(struct eval_ctx *ctx, struct expr *expr)
return 0;
}
+ if (payload->payload.base == desc->base &&
+ proto_ctx_is_ambiguous(&ctx->pctx, base)) {
+ desc = proto_ctx_find_conflict(&ctx->pctx, base, payload->payload.desc);
+ assert(desc);
+
+ return expr_error(ctx->msgs, payload,
+ "conflicting protocols specified: %s vs. %s",
+ desc->name,
+ payload->payload.desc->name);
+ }
+
/* No conflict: Same payload protocol as context, adjust offset
* if needed.
*/
@@ -1874,8 +1885,7 @@ static int expr_evaluate_relational(struct eval_ctx *ctx, struct expr **expr)
* Update protocol context for payload and meta iiftype
* equality expressions.
*/
- if (expr_is_singleton(right))
- relational_expr_pctx_update(&ctx->pctx, rel);
+ relational_expr_pctx_update(&ctx->pctx, rel);
/* fall through */
case OP_NEQ:
diff --git a/src/expression.c b/src/expression.c
index fe529f98..87bd4d01 100644
--- a/src/expression.c
+++ b/src/expression.c
@@ -708,16 +708,26 @@ struct expr *relational_expr_alloc(const struct location *loc, enum ops op,
void relational_expr_pctx_update(struct proto_ctx *ctx,
const struct expr *expr)
{
- const struct expr *left = expr->left;
+ const struct expr *left = expr->left, *right = expr->right;
const struct expr_ops *ops;
+ const struct expr *i;
assert(expr->etype == EXPR_RELATIONAL);
assert(expr->op == OP_EQ || expr->op == OP_IMPLICIT);
ops = expr_ops(left);
if (ops->pctx_update &&
- (left->flags & EXPR_F_PROTOCOL))
- ops->pctx_update(ctx, expr);
+ (left->flags & EXPR_F_PROTOCOL)) {
+ if (expr_is_singleton(right))
+ ops->pctx_update(ctx, &expr->location, left, right);
+ else if (right->etype == EXPR_SET) {
+ list_for_each_entry(i, &right->expressions, list) {
+ if (i->etype == EXPR_SET_ELEM &&
+ i->key->etype == EXPR_VALUE)
+ ops->pctx_update(ctx, &expr->location, left, i->key);
+ }
+ }
+ }
}
static void range_expr_print(const struct expr *expr, struct output_ctx *octx)
diff --git a/src/meta.c b/src/meta.c
index d92d0d32..73d58b1f 100644
--- a/src/meta.c
+++ b/src/meta.c
@@ -753,10 +753,11 @@ static void meta_expr_clone(struct expr *new, const struct expr *expr)
* Update LL protocol context based on IIFTYPE meta match in non-LL hooks.
*/
static void meta_expr_pctx_update(struct proto_ctx *ctx,
- const struct expr *expr)
+ const struct location *loc,
+ const struct expr *left,
+ const struct expr *right)
{
const struct hook_proto_desc *h = &hook_proto_desc[ctx->family];
- const struct expr *left = expr->left, *right = expr->right;
const struct proto_desc *desc;
uint8_t protonum;
@@ -771,7 +772,7 @@ static void meta_expr_pctx_update(struct proto_ctx *ctx,
if (desc == NULL)
desc = &proto_unknown;
- proto_ctx_update(ctx, PROTO_BASE_LL_HDR, &expr->location, desc);
+ proto_ctx_update(ctx, PROTO_BASE_LL_HDR, loc, desc);
break;
case NFT_META_NFPROTO:
protonum = mpz_get_uint8(right->value);
@@ -784,7 +785,7 @@ static void meta_expr_pctx_update(struct proto_ctx *ctx,
desc = h->desc;
}
- proto_ctx_update(ctx, PROTO_BASE_NETWORK_HDR, &expr->location, desc);
+ proto_ctx_update(ctx, PROTO_BASE_NETWORK_HDR, loc, desc);
break;
case NFT_META_L4PROTO:
desc = proto_find_upper(&proto_inet_service,
@@ -792,7 +793,7 @@ static void meta_expr_pctx_update(struct proto_ctx *ctx,
if (desc == NULL)
desc = &proto_unknown;
- proto_ctx_update(ctx, PROTO_BASE_TRANSPORT_HDR, &expr->location, desc);
+ proto_ctx_update(ctx, PROTO_BASE_TRANSPORT_HDR, loc, desc);
break;
case NFT_META_PROTOCOL:
if (h->base != PROTO_BASE_LL_HDR)
@@ -806,7 +807,7 @@ static void meta_expr_pctx_update(struct proto_ctx *ctx,
if (desc == NULL)
desc = &proto_unknown;
- proto_ctx_update(ctx, PROTO_BASE_NETWORK_HDR, &expr->location, desc);
+ proto_ctx_update(ctx, PROTO_BASE_NETWORK_HDR, loc, desc);
break;
default:
break;
diff --git a/src/payload.c b/src/payload.c
index 29242537..ca422d5b 100644
--- a/src/payload.c
+++ b/src/payload.c
@@ -80,9 +80,10 @@ static void payload_expr_clone(struct expr *new, const struct expr *expr)
* Update protocol context for relational payload expressions.
*/
static void payload_expr_pctx_update(struct proto_ctx *ctx,
- const struct expr *expr)
+ const struct location *loc,
+ const struct expr *left,
+ const struct expr *right)
{
- const struct expr *left = expr->left, *right = expr->right;
const struct proto_desc *base, *desc;
unsigned int proto = 0;
@@ -102,7 +103,7 @@ static void payload_expr_pctx_update(struct proto_ctx *ctx,
assert(base->length > 0);
ctx->protocol[base->base].offset += base->length;
}
- proto_ctx_update(ctx, desc->base, &expr->location, desc);
+ proto_ctx_update(ctx, desc->base, loc, desc);
}
#define NFTNL_UDATA_SET_KEY_PAYLOAD_DESC 0
diff --git a/src/proto.c b/src/proto.c
index 7d001501..7de2bbf9 100644
--- a/src/proto.c
+++ b/src/proto.c
@@ -193,12 +193,69 @@ void proto_ctx_update(struct proto_ctx *ctx, enum proto_bases base,
const struct location *loc,
const struct proto_desc *desc)
{
+ bool found = false;
+ unsigned int i;
+
+ switch (base) {
+ case PROTO_BASE_LL_HDR:
+ case PROTO_BASE_NETWORK_HDR:
+ break;
+ case PROTO_BASE_TRANSPORT_HDR:
+ if (ctx->protocol[base].num_protos >= PROTO_CTX_NUM_PROTOS)
+ break;
+
+ for (i = 0; i < ctx->protocol[base].num_protos; i++) {
+ if (ctx->protocol[base].protos[i].desc == desc) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ i = ctx->protocol[base].num_protos++;
+ ctx->protocol[base].protos[i].desc = desc;
+ ctx->protocol[base].protos[i].location = *loc;
+ }
+ break;
+ default:
+ BUG("unknown protocol base %d", base);
+ }
+
ctx->protocol[base].location = *loc;
ctx->protocol[base].desc = desc;
proto_ctx_debug(ctx, base, ctx->debug_mask);
}
+bool proto_ctx_is_ambiguous(struct proto_ctx *ctx, enum proto_bases base)
+{
+ return ctx->protocol[base].num_protos > 1;
+}
+
+const struct proto_desc *proto_ctx_find_conflict(struct proto_ctx *ctx,
+ enum proto_bases base,
+ const struct proto_desc *desc)
+{
+ unsigned int i;
+
+ switch (base) {
+ case PROTO_BASE_LL_HDR:
+ case PROTO_BASE_NETWORK_HDR:
+ if (desc != ctx->protocol[base].desc)
+ return ctx->protocol[base].desc;
+ break;
+ case PROTO_BASE_TRANSPORT_HDR:
+ for (i = 0; i < ctx->protocol[base].num_protos; i++) {
+ if (desc != ctx->protocol[base].protos[i].desc)
+ return ctx->protocol[base].protos[i].desc;
+ }
+ break;
+ default:
+ BUG("unknown protocol base %d", base);
+ }
+
+ return NULL;
+}
+
#define HDR_TEMPLATE(__name, __dtype, __type, __member) \
PROTO_HDR_TEMPLATE(__name, __dtype, \
BYTEORDER_BIG_ENDIAN, \
diff --git a/tests/py/inet/dnat.t b/tests/py/inet/dnat.t
index fcdf9436..a2661008 100644
--- a/tests/py/inet/dnat.t
+++ b/tests/py/inet/dnat.t
@@ -14,3 +14,8 @@ dnat ip6 to 1.2.3.4;fail
dnat to 1.2.3.4;fail
dnat ip6 to ct mark . ip daddr map { 0x00000014 . 1.1.1.1 : 1.2.3.4};fail
ip6 daddr dead::beef dnat to 10.1.2.3;fail
+
+meta l4proto { tcp, udp } dnat ip to 1.1.1.1:80;ok
+ip protocol { tcp, udp } dnat ip to 1.1.1.1:80;ok
+meta l4proto { tcp, udp } tcp dport 20 dnat to 1.1.1.1:80;fail
+ip protocol { tcp, udp } tcp dport 20 dnat to 1.1.1.1:80;fail
diff --git a/tests/py/inet/dnat.t.payload b/tests/py/inet/dnat.t.payload
index 75cf1b77..a741b9cb 100644
--- a/tests/py/inet/dnat.t.payload
+++ b/tests/py/inet/dnat.t.payload
@@ -52,3 +52,28 @@ inet test-inet prerouting
[ payload load 4b @ network header + 16 => reg 9 ]
[ lookup reg 1 set __map%d dreg 1 ]
[ nat dnat ip addr_min reg 1 addr_max reg 0 ]
+
+# meta l4proto { tcp, udp } dnat ip to 1.1.1.1:80
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000006 : 0 [end] element 00000011 : 0 [end]
+inet
+ [ meta load l4proto => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ immediate reg 1 0x01010101 ]
+ [ immediate reg 2 0x00005000 ]
+ [ nat dnat ip addr_min reg 1 addr_max reg 0 proto_min reg 2 proto_max reg 0 flags 0x2 ]
+
+# ip protocol { tcp, udp } dnat ip to 1.1.1.1:80
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000006 : 0 [end] element 00000011 : 0 [end]
+inet
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ immediate reg 1 0x01010101 ]
+ [ immediate reg 2 0x00005000 ]
+ [ nat dnat ip addr_min reg 1 addr_max reg 0 proto_min reg 2 proto_max reg 0 flags 0x2 ]
+