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

Commit bd077937 authored by Pablo Neira Ayuso's avatar Pablo Neira Ayuso
Browse files

netfilter: nfnetlink_queue: allow to attach expectations to conntracks



This patch adds the capability to attach expectations via nfnetlink_queue.
This is required by conntrack helpers that trigger expectations based on
the first packet seen like the TFTP and the DHCPv6 user-space helpers.

Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent 0ef71ee1
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -325,6 +325,8 @@ struct nfq_ct_hook {
	size_t (*build_size)(const struct nf_conn *ct);
	int (*build)(struct sk_buff *skb, struct nf_conn *ct);
	int (*parse)(const struct nlattr *attr, struct nf_conn *ct);
	int (*attach_expect)(const struct nlattr *attr, struct nf_conn *ct,
			     u32 portid, u32 report);
};
extern struct nfq_ct_hook __rcu *nfq_ct_hook;

+8 −0
Original line number Diff line number Diff line
@@ -15,6 +15,8 @@ int nfqnl_ct_put(struct sk_buff *skb, struct nf_conn *ct,
		 enum ip_conntrack_info ctinfo);
void nfqnl_ct_seq_adjust(struct sk_buff *skb, struct nf_conn *ct,
			 enum ip_conntrack_info ctinfo, int diff);
int nfqnl_attach_expect(struct nf_conn *ct, const struct nlattr *attr,
			u32 portid, u32 report);
#else
inline struct nf_conn *
nfqnl_ct_get(struct sk_buff *entskb, size_t *size, enum ip_conntrack_info *ctinfo)
@@ -39,5 +41,11 @@ inline void nfqnl_ct_seq_adjust(struct sk_buff *skb, struct nf_conn *ct,
				enum ip_conntrack_info ctinfo, int diff)
{
}

inline int nfqnl_attach_expect(struct nf_conn *ct, const struct nlattr *attr,
			       u32 portid, u32 report)
{
	return 0;
}
#endif /* NF_CONNTRACK */
#endif
+1 −0
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ enum nfqnl_attr_type {
	NFQA_CT_INFO,			/* enum ip_conntrack_info */
	NFQA_CAP_LEN,			/* __u32 length of captured packet */
	NFQA_SKB_INFO,			/* __u32 skb meta information */
	NFQA_EXP,			/* nf_conntrack_netlink.h */

	__NFQA_MAX
};
+80 −15
Original line number Diff line number Diff line
@@ -1987,6 +1987,27 @@ ctnetlink_stat_ct(struct sock *ctnl, struct sk_buff *skb,
	return err == -EAGAIN ? -ENOBUFS : err;
}

static const struct nla_policy exp_nla_policy[CTA_EXPECT_MAX+1] = {
	[CTA_EXPECT_MASTER]	= { .type = NLA_NESTED },
	[CTA_EXPECT_TUPLE]	= { .type = NLA_NESTED },
	[CTA_EXPECT_MASK]	= { .type = NLA_NESTED },
	[CTA_EXPECT_TIMEOUT]	= { .type = NLA_U32 },
	[CTA_EXPECT_ID]		= { .type = NLA_U32 },
	[CTA_EXPECT_HELP_NAME]	= { .type = NLA_NUL_STRING,
				    .len = NF_CT_HELPER_NAME_LEN - 1 },
	[CTA_EXPECT_ZONE]	= { .type = NLA_U16 },
	[CTA_EXPECT_FLAGS]	= { .type = NLA_U32 },
	[CTA_EXPECT_CLASS]	= { .type = NLA_U32 },
	[CTA_EXPECT_NAT]	= { .type = NLA_NESTED },
	[CTA_EXPECT_FN]		= { .type = NLA_NUL_STRING },
};

static struct nf_conntrack_expect *
ctnetlink_alloc_expect(const struct nlattr *const cda[], struct nf_conn *ct,
		       struct nf_conntrack_helper *helper,
		       struct nf_conntrack_tuple *tuple,
		       struct nf_conntrack_tuple *mask);

#ifdef CONFIG_NETFILTER_NETLINK_QUEUE_CT
static size_t
ctnetlink_nfqueue_build_size(const struct nf_conn *ct)
@@ -2127,10 +2148,69 @@ ctnetlink_nfqueue_parse(const struct nlattr *attr, struct nf_conn *ct)
	return ret;
}

static int ctnetlink_nfqueue_exp_parse(const struct nlattr * const *cda,
				       const struct nf_conn *ct,
				       struct nf_conntrack_tuple *tuple,
				       struct nf_conntrack_tuple *mask)
{
	int err;

	err = ctnetlink_parse_tuple(cda, tuple, CTA_EXPECT_TUPLE,
				    nf_ct_l3num(ct));
	if (err < 0)
		return err;

	return ctnetlink_parse_tuple(cda, mask, CTA_EXPECT_MASK,
				     nf_ct_l3num(ct));
}

static int
ctnetlink_nfqueue_attach_expect(const struct nlattr *attr, struct nf_conn *ct,
				u32 portid, u32 report)
{
	struct nlattr *cda[CTA_EXPECT_MAX+1];
	struct nf_conntrack_tuple tuple, mask;
	struct nf_conntrack_helper *helper;
	struct nf_conntrack_expect *exp;
	int err;

	err = nla_parse_nested(cda, CTA_EXPECT_MAX, attr, exp_nla_policy);
	if (err < 0)
		return err;

	err = ctnetlink_nfqueue_exp_parse((const struct nlattr * const *)cda,
					  ct, &tuple, &mask);
	if (err < 0)
		return err;

	if (cda[CTA_EXPECT_HELP_NAME]) {
		const char *helpname = nla_data(cda[CTA_EXPECT_HELP_NAME]);

		helper = __nf_conntrack_helper_find(helpname, nf_ct_l3num(ct),
						    nf_ct_protonum(ct));
		if (helper == NULL)
			return -EOPNOTSUPP;
	}

	exp = ctnetlink_alloc_expect((const struct nlattr * const *)cda, ct,
				     helper, &tuple, &mask);
	if (IS_ERR(exp))
		return PTR_ERR(exp);

	err = nf_ct_expect_related_report(exp, portid, report);
	if (err < 0) {
		nf_ct_expect_put(exp);
		return err;
	}

	return 0;
}

static struct nfq_ct_hook ctnetlink_nfqueue_hook = {
	.build_size	= ctnetlink_nfqueue_build_size,
	.build		= ctnetlink_nfqueue_build,
	.parse		= ctnetlink_nfqueue_parse,
	.attach_expect	= ctnetlink_nfqueue_attach_expect,
};
#endif /* CONFIG_NETFILTER_NETLINK_QUEUE_CT */

@@ -2498,21 +2578,6 @@ static int ctnetlink_dump_exp_ct(struct sock *ctnl, struct sk_buff *skb,
	return err;
}

static const struct nla_policy exp_nla_policy[CTA_EXPECT_MAX+1] = {
	[CTA_EXPECT_MASTER]	= { .type = NLA_NESTED },
	[CTA_EXPECT_TUPLE]	= { .type = NLA_NESTED },
	[CTA_EXPECT_MASK]	= { .type = NLA_NESTED },
	[CTA_EXPECT_TIMEOUT]	= { .type = NLA_U32 },
	[CTA_EXPECT_ID]		= { .type = NLA_U32 },
	[CTA_EXPECT_HELP_NAME]	= { .type = NLA_NUL_STRING,
				    .len = NF_CT_HELPER_NAME_LEN - 1 },
	[CTA_EXPECT_ZONE]	= { .type = NLA_U16 },
	[CTA_EXPECT_FLAGS]	= { .type = NLA_U32 },
	[CTA_EXPECT_CLASS]	= { .type = NLA_U32 },
	[CTA_EXPECT_NAT]	= { .type = NLA_NESTED },
	[CTA_EXPECT_FN]		= { .type = NLA_NUL_STRING },
};

static int
ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb,
		     const struct nlmsghdr *nlh,
+8 −1
Original line number Diff line number Diff line
@@ -859,6 +859,7 @@ static const struct nla_policy nfqa_verdict_policy[NFQA_MAX+1] = {
	[NFQA_MARK]		= { .type = NLA_U32 },
	[NFQA_PAYLOAD]		= { .type = NLA_UNSPEC },
	[NFQA_CT]		= { .type = NLA_UNSPEC },
	[NFQA_EXP]		= { .type = NLA_UNSPEC },
};

static const struct nla_policy nfqa_verdict_batch_policy[NFQA_MAX+1] = {
@@ -987,8 +988,14 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
	if (entry == NULL)
		return -ENOENT;

	if (nfqa[NFQA_CT])
	if (nfqa[NFQA_CT]) {
		ct = nfqnl_ct_parse(entry->skb, nfqa[NFQA_CT], &ctinfo);
		if (ct && nfqa[NFQA_EXP]) {
			nfqnl_attach_expect(ct, nfqa[NFQA_EXP],
					    NETLINK_CB(skb).portid,
					    nlmsg_report(nlh));
		}
	}

	if (nfqa[NFQA_PAYLOAD]) {
		u16 payload_len = nla_len(nfqa[NFQA_PAYLOAD]);
Loading