diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/payload.c | 80 | ||||
-rw-r--r-- | src/proto.c | 6 |
2 files changed, 68 insertions, 18 deletions
diff --git a/src/payload.c b/src/payload.c index 55128fee..11b6df37 100644 --- a/src/payload.c +++ b/src/payload.c @@ -117,6 +117,28 @@ static const struct expr_ops payload_expr_ops = { .pctx_update = payload_expr_pctx_update, }; +/* + * We normally use 'meta l4proto' to fetch the last l4 header of the + * ipv6 extension header chain so we will also match + * tcp after a fragmentation header, for instance. + * For consistency we also use meta l4proto for ipv4. + * + * If user specifically asks for nexthdr x, don't add another (useless) + * meta dependency. + */ +static bool proto_key_is_protocol(const struct proto_desc *desc, unsigned int type) +{ + if (type == desc->protocol_key) + return true; + + if (desc == &proto_ip6 && type == IP6HDR_NEXTHDR) + return true; + if (desc == &proto_ip && type == IPHDR_PROTOCOL) + return true; + + return false; +} + struct expr *payload_expr_alloc(const struct location *loc, const struct proto_desc *desc, unsigned int type) @@ -129,7 +151,7 @@ struct expr *payload_expr_alloc(const struct location *loc, if (desc != NULL) { tmpl = &desc->templates[type]; base = desc->base; - if (type == desc->protocol_key) + if (proto_key_is_protocol(desc, type)) flags = EXPR_F_PROTOCOL; } else { tmpl = &proto_unknown_template; @@ -224,26 +246,52 @@ static int payload_add_dependency(struct eval_ctx *ctx, } static const struct proto_desc * +payload_get_get_ll_hdr(const struct eval_ctx *ctx) +{ + switch (ctx->pctx.family) { + case NFPROTO_INET: + return &proto_inet; + case NFPROTO_BRIDGE: + return &proto_eth; + case NFPROTO_NETDEV: + return &proto_netdev; + default: + break; + } + + return NULL; +} + +static const struct proto_desc * payload_gen_special_dependency(struct eval_ctx *ctx, const struct expr *expr) { switch (expr->payload.base) { case PROTO_BASE_LL_HDR: - switch (ctx->pctx.family) { - case NFPROTO_INET: - return &proto_inet; - case NFPROTO_BRIDGE: - return &proto_eth; - case NFPROTO_NETDEV: - return &proto_netdev; - default: - break; - } - break; + return payload_get_get_ll_hdr(ctx); case PROTO_BASE_TRANSPORT_HDR: - if (expr->payload.desc == &proto_icmp) - return &proto_ip; - if (expr->payload.desc == &proto_icmp6) - return &proto_ip6; + if (expr->payload.desc == &proto_icmp || + expr->payload.desc == &proto_icmp6) { + const struct proto_desc *desc, *desc_upper; + struct stmt *nstmt; + + desc = ctx->pctx.protocol[PROTO_BASE_LL_HDR].desc; + if (!desc) { + desc = payload_get_get_ll_hdr(ctx); + if (!desc) + break; + } + + desc_upper = &proto_ip6; + if (expr->payload.desc == &proto_icmp) + desc_upper = &proto_ip; + + if (payload_add_dependency(ctx, desc, desc_upper, + expr, &nstmt) < 0) + return NULL; + + list_add_tail(&nstmt->list, &ctx->stmt->list); + return desc_upper; + } return &proto_inet_service; default: break; diff --git a/src/proto.c b/src/proto.c index 79e9dbf2..2afedf77 100644 --- a/src/proto.c +++ b/src/proto.c @@ -587,7 +587,6 @@ const struct proto_desc proto_ip = { .name = "ip", .base = PROTO_BASE_NETWORK_HDR, .checksum_key = IPHDR_CHECKSUM, - .protocol_key = IPHDR_PROTOCOL, .protocols = { PROTO_LINK(IPPROTO_ICMP, &proto_icmp), PROTO_LINK(IPPROTO_ESP, &proto_esp), @@ -600,6 +599,7 @@ const struct proto_desc proto_ip = { PROTO_LINK(IPPROTO_SCTP, &proto_sctp), }, .templates = { + [0] = PROTO_META_TEMPLATE("l4proto", &inet_protocol_type, NFT_META_L4PROTO, 8), [IPHDR_VERSION] = HDR_BITFIELD("version", &integer_type, 0, 4), [IPHDR_HDRLENGTH] = HDR_BITFIELD("hdrlength", &integer_type, 4, 4), [IPHDR_DSCP] = HDR_BITFIELD("dscp", &dscp_type, 8, 6), @@ -707,7 +707,6 @@ const struct proto_desc proto_icmp6 = { const struct proto_desc proto_ip6 = { .name = "ip6", .base = PROTO_BASE_NETWORK_HDR, - .protocol_key = IP6HDR_NEXTHDR, .protocols = { PROTO_LINK(IPPROTO_ESP, &proto_esp), PROTO_LINK(IPPROTO_AH, &proto_ah), @@ -720,6 +719,7 @@ const struct proto_desc proto_ip6 = { PROTO_LINK(IPPROTO_ICMPV6, &proto_icmp6), }, .templates = { + [0] = PROTO_META_TEMPLATE("l4proto", &inet_protocol_type, NFT_META_L4PROTO, 8), [IP6HDR_VERSION] = HDR_BITFIELD("version", &integer_type, 0, 4), [IP6HDR_DSCP] = HDR_BITFIELD("dscp", &dscp_type, 4, 6), [IP6HDR_ECN] = HDR_BITFIELD("ecn", &ecn_type, 10, 2), @@ -779,6 +779,8 @@ const struct proto_desc proto_inet_service = { PROTO_LINK(IPPROTO_TCP, &proto_tcp), PROTO_LINK(IPPROTO_DCCP, &proto_dccp), PROTO_LINK(IPPROTO_SCTP, &proto_sctp), + PROTO_LINK(IPPROTO_ICMP, &proto_icmp), + PROTO_LINK(IPPROTO_ICMPV6, &proto_icmp6), }, .templates = { [0] = PROTO_META_TEMPLATE("l4proto", &inet_protocol_type, NFT_META_L4PROTO, 8), |