summaryrefslogtreecommitdiffstats
path: root/src/evaluate.c
diff options
context:
space:
mode:
authorFlorian Westphal <fw@strlen.de>2015-09-24 22:38:06 +0200
committerFlorian Westphal <fw@strlen.de>2015-11-06 14:51:36 +0100
commit775e7ff1f5ddaa3208ea2c9178d9e5d8890d9739 (patch)
treea599cc7782458e684cfd01f88b57b863c2128ea6 /src/evaluate.c
parentb851ba4731d9f7c5e38889875a83173fcc4d3f16 (diff)
src: allow filtering on L2 header in inet family
Error: conflicting protocols specified: inet vs. ether tcp dport 22 iiftype ether ether saddr 00:0f:54:0c:11:4 ^^^^^^^^^^^ This allows the implicit inet proto dependency to get replaced by an ethernet one. This is possible since by the time we detect the conflict the meta dependency for the network protocol has already been added. So we only need to add another dependency on the Linklayer frame type. Closes: http://bugzilla.netfilter.org/show_bug.cgi?id=981 Acked-by: Pablo Neira Ayuso <pablo@netfilter.org> Signed-off-by: Florian Westphal <fw@strlen.de>
Diffstat (limited to 'src/evaluate.c')
-rw-r--r--src/evaluate.c47
1 files changed, 46 insertions, 1 deletions
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;