Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 694a0055 authored by Florian Westphal's avatar Florian Westphal Committed by Pablo Neira Ayuso
Browse files

netfilter: nft_ct: allow to set ctnetlink event types of a connection



By default the kernel emits all ctnetlink events for a connection.
This allows to select the types of events to generate.

This can be used to e.g. only send DESTROY events but no NEW/UPDATE ones
and will work even if sysctl net.netfilter.nf_conntrack_events is set to 0.

This was already possible via iptables' CT target, but the nft version has
the advantage that it can also be used with already-established conntracks.

The added nf_ct_is_template() check isn't a bug fix as we only support
mark and labels (and unlike ecache the conntrack core doesn't copy those).

Signed-off-by: default avatarFlorian Westphal <fw@strlen.de>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent ab8bc7ed
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -901,6 +901,7 @@ enum nft_rt_attributes {
 * @NFT_CT_BYTES: conntrack bytes
 * @NFT_CT_AVGPKT: conntrack average bytes per packet
 * @NFT_CT_ZONE: conntrack zone
 * @NFT_CT_EVENTMASK: ctnetlink events to be generated for this conntrack
 */
enum nft_ct_keys {
	NFT_CT_STATE,
@@ -921,6 +922,7 @@ enum nft_ct_keys {
	NFT_CT_BYTES,
	NFT_CT_AVGPKT,
	NFT_CT_ZONE,
	NFT_CT_EVENTMASK,
};

/**
+24 −1
Original line number Diff line number Diff line
@@ -264,7 +264,7 @@ static void nft_ct_set_eval(const struct nft_expr *expr,
	struct nf_conn *ct;

	ct = nf_ct_get(skb, &ctinfo);
	if (ct == NULL)
	if (ct == NULL || nf_ct_is_template(ct))
		return;

	switch (priv->key) {
@@ -283,6 +283,22 @@ static void nft_ct_set_eval(const struct nft_expr *expr,
				      &regs->data[priv->sreg],
				      NF_CT_LABELS_MAX_SIZE / sizeof(u32));
		break;
#endif
#ifdef CONFIG_NF_CONNTRACK_EVENTS
	case NFT_CT_EVENTMASK: {
		struct nf_conntrack_ecache *e = nf_ct_ecache_find(ct);
		u32 ctmask = regs->data[priv->sreg];

		if (e) {
			if (e->ctmask != ctmask)
				e->ctmask = ctmask;
			break;
		}

		if (ctmask && !nf_ct_is_confirmed(ct))
			nf_ct_ecache_ext_add(ct, ctmask, 0, GFP_ATOMIC);
		break;
	}
#endif
	default:
		break;
@@ -538,6 +554,13 @@ static int nft_ct_set_init(const struct nft_ctx *ctx,
		nft_ct_pcpu_template_refcnt++;
		len = sizeof(u16);
		break;
#endif
#ifdef CONFIG_NF_CONNTRACK_EVENTS
	case NFT_CT_EVENTMASK:
		if (tb[NFTA_CT_DIRECTION])
			return -EINVAL;
		len = sizeof(u32);
		break;
#endif
	default:
		return -EOPNOTSUPP;