return false;
}
+static bool ct_may_dependency_kill(unsigned int meta_nfproto,
+ const struct expr *ct)
+{
+ assert(ct->etype == EXPR_CT);
+
+ switch (ct->ct.key) {
+ case NFT_CT_DST:
+ case NFT_CT_SRC:
+ switch (ct->len) {
+ case 32:
+ return meta_nfproto == NFPROTO_IPV4;
+ case 128:
+ return meta_nfproto == NFPROTO_IPV6;
+ default:
+ break;
+ }
+ return false;
+ case NFT_CT_DST_IP:
+ case NFT_CT_SRC_IP:
+ return meta_nfproto == NFPROTO_IPV4;
+ case NFT_CT_DST_IP6:
+ case NFT_CT_SRC_IP6:
+ return meta_nfproto == NFPROTO_IPV6;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+static bool meta_may_dependency_kill(uint8_t nfproto, const struct expr *meta, const struct expr *v)
+{
+ uint8_t l4proto;
+
+ if (meta->meta.key != NFT_META_L4PROTO)
+ return true;
+
+ if (v->etype != EXPR_VALUE || v->len != 8)
+ return false;
+
+ l4proto = mpz_get_uint8(v->value);
+
+ switch (l4proto) {
+ case IPPROTO_ICMP:
+ return nfproto == NFPROTO_IPV4;
+ case IPPROTO_ICMPV6:
+ return nfproto == NFPROTO_IPV6;
+ default:
+ break;
+ }
+
+ return false;
+}
+
/* We have seen a protocol key expression that restricts matching at the network
* base, leave it in place since this is meaningful in bridge, inet and netdev
* families. Exceptions are ICMP and ICMPv6 where this code assumes that can
* only happen with IPv4 and IPv6.
*/
-static bool meta_may_dependency_kill(struct payload_dep_ctx *ctx,
+static bool ct_meta_may_dependency_kill(struct payload_dep_ctx *ctx,
unsigned int family,
const struct expr *expr)
{
- uint8_t l4proto, nfproto = NFPROTO_UNSPEC;
struct expr *dep = payload_dependency_get(ctx, PROTO_BASE_NETWORK_HDR);
+ uint8_t nfproto = NFPROTO_UNSPEC;
if (!dep)
return true;
return true;
}
- if (expr->left->meta.key != NFT_META_L4PROTO)
- return true;
-
- l4proto = mpz_get_uint8(expr->right->value);
-
- switch (l4proto) {
- case IPPROTO_ICMP:
- case IPPROTO_ICMPV6:
- break;
+ switch (expr->left->etype) {
+ case EXPR_META:
+ return meta_may_dependency_kill(nfproto, expr->left, expr->right);
+ case EXPR_CT:
+ return ct_may_dependency_kill(nfproto, expr->left);
default:
- return false;
+ break;
}
- if ((nfproto == NFPROTO_IPV4 && l4proto == IPPROTO_ICMPV6) ||
- (nfproto == NFPROTO_IPV6 && l4proto == IPPROTO_ICMP))
- return false;
-
return true;
}
if (base < PROTO_BASE_TRANSPORT_HDR) {
if (payload_dependency_exists(&dl->pdctx, base) &&
- meta_may_dependency_kill(&dl->pdctx,
- dl->pctx.family, expr))
+ ct_meta_may_dependency_kill(&dl->pdctx,
+ dl->pctx.family, expr))
payload_dependency_release(&dl->pdctx, base);
if (left->flags & EXPR_F_PROTOCOL)
*inet;test-inet;input
+# dependency should be removed
meta nfproto ipv4 ct original saddr 1.2.3.4;ok;ct original ip saddr 1.2.3.4
ct original ip6 saddr ::1;ok
ct original ip daddr 1.2.3.4 accept;ok
+# dependency must not be removed
+meta nfproto ipv4 ct mark 0x00000001;ok
+meta nfproto ipv6 ct protocol 6;ok
+
# missing protocol context
ct original saddr ::1;fail
[ ct load dst_ip => reg 1 , dir original ]
[ cmp eq reg 1 0x04030201 ]
[ immediate reg 0 accept ]
+
+# meta nfproto ipv4 ct mark 0x00000001
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ ct load mark => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# meta nfproto ipv6 ct protocol 6
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ ct load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]