summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/meta.h2
-rw-r--r--src/evaluate.c47
-rw-r--r--src/meta.c24
-rw-r--r--src/payload.c8
4 files changed, 72 insertions, 9 deletions
diff --git a/include/meta.h b/include/meta.h
index abe74ec0..f25b147a 100644
--- a/include/meta.h
+++ b/include/meta.h
@@ -26,6 +26,8 @@ struct meta_template {
extern struct expr *meta_expr_alloc(const struct location *loc,
enum nft_meta_keys key);
+struct stmt *meta_stmt_meta_iiftype(const struct location *loc, uint16_t type);
+
const struct datatype ifindex_type;
#endif /* NFTABLES_META_H */
diff --git a/src/evaluate.c b/src/evaluate.c
index e1299075..78424715 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -332,6 +332,34 @@ conflict_resolution_gen_dependency(struct eval_ctx *ctx, int protocol,
return 0;
}
+/* dependency supersede.
+ *
+ * 'inet' is a 'phony' l2 dependeny used by NFPROTO_INET to fulfill network
+ * header dependency, i.e. ensure that 'ip saddr 1.2.3.4' only sees ip headers.
+ *
+ * If a match expression that depends on a particular L2 header, e.g. ethernet,
+ * is used, we thus get a conflict since we already have a l2 header dependency.
+ *
+ * But in the inet case we can just ignore the conflict since only another
+ * restriction is added, and these are not mutually exclusive.
+ *
+ * Example: inet filter in ip saddr 1.2.3.4 ether saddr a:b:c:d:e:f
+ *
+ * ip saddr adds meta dependency on ipv4 packets
+ * ether saddr adds another dependeny on ethernet frames.
+ */
+static bool supersede_dep(const struct proto_desc *have,
+ struct expr *payload)
+{
+ if (payload->payload.base != PROTO_BASE_LL_HDR || have->length)
+ return false;
+
+ if (have != &proto_inet)
+ return false;
+
+ return true;
+}
+
static bool resolve_protocol_conflict(struct eval_ctx *ctx,
struct expr *payload)
{
@@ -351,7 +379,24 @@ static bool resolve_protocol_conflict(struct eval_ctx *ctx,
if (payload->payload.base != h->base)
return false;
- assert(desc->length);
+ if (supersede_dep(desc, payload)) {
+ uint16_t type;
+
+ if (proto_dev_type(payload->payload.desc, &type) < 0)
+ return expr_error(ctx->msgs, payload,
+ "protocol specification is invalid "
+ "for this family");
+
+ nstmt = meta_stmt_meta_iiftype(&payload->location, type);
+ if (stmt_evaluate(ctx, nstmt) < 0)
+ return expr_error(ctx->msgs, payload,
+ "dependency statement is invalid");
+
+ list_add_tail(&nstmt->list, &ctx->stmt->list);
+ ctx->pctx.protocol[base].desc = payload->payload.desc;
+ return true;
+ }
+
if (base < PROTO_BASE_MAX) {
const struct proto_desc *next = ctx->pctx.protocol[base + 1].desc;
diff --git a/src/meta.c b/src/meta.c
index 6f79c401..d31d2922 100644
--- a/src/meta.c
+++ b/src/meta.c
@@ -19,6 +19,8 @@
#include <net/if_arp.h>
#include <pwd.h>
#include <grp.h>
+#include <arpa/inet.h>
+#include <linux/netfilter.h>
#include <linux/pkt_sched.h>
#include <linux/if_packet.h>
@@ -468,7 +470,7 @@ static void meta_expr_pctx_update(struct proto_ctx *ctx,
switch (left->meta.key) {
case NFT_META_IIFTYPE:
- if (h->base < PROTO_BASE_NETWORK_HDR)
+ if (h->base < PROTO_BASE_NETWORK_HDR && ctx->family != NFPROTO_INET)
return;
desc = proto_dev_desc(mpz_get_uint16(right->value));
@@ -572,3 +574,23 @@ static void __init meta_init(void)
datatype_register(&devgroup_type);
datatype_register(&pkttype_type);
}
+
+/*
+ * @expr: payload expression
+ * @res: dependency expression
+ *
+ * Generate a NFT_META_IIFTYPE expression to check for ethernet frames.
+ * Only works on input path.
+ */
+struct stmt *meta_stmt_meta_iiftype(const struct location *loc, uint16_t type)
+{
+ struct expr *dep, *left, *right;
+
+ left = meta_expr_alloc(loc, NFT_META_IIFTYPE);
+ right = constant_expr_alloc(loc, &arphrd_type,
+ BYTEORDER_HOST_ENDIAN,
+ 2 * BITS_PER_BYTE, &type);
+
+ dep = relational_expr_alloc(loc, OP_EQ, left, right);
+ return expr_stmt_alloc(&dep->location, dep);
+}
diff --git a/src/payload.c b/src/payload.c
index 23afa2f2..b75527a1 100644
--- a/src/payload.c
+++ b/src/payload.c
@@ -183,13 +183,7 @@ int payload_gen_dependency(struct eval_ctx *ctx, const struct expr *expr,
"protocol specification is invalid "
"for this family");
- left = meta_expr_alloc(&expr->location, NFT_META_IIFTYPE);
- right = constant_expr_alloc(&expr->location, &arphrd_type,
- BYTEORDER_HOST_ENDIAN,
- 2 * BITS_PER_BYTE, &type);
-
- dep = relational_expr_alloc(&expr->location, OP_EQ, left, right);
- stmt = expr_stmt_alloc(&dep->location, dep);
+ stmt = meta_stmt_meta_iiftype(&expr->location, type);
if (stmt_evaluate(ctx, stmt) < 0) {
return expr_error(ctx->msgs, expr,
"dependency statement is invalid");