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

Commit 93e66024 authored by Florian Westphal's avatar Florian Westphal Committed by Pablo Neira Ayuso
Browse files

netfilter: conntrack: pass nf_hook_state to packet and error handlers



nf_hook_state contains all the hook meta-information: netns, protocol family,
hook location, and so on.

Instead of only passing selected information, pass a pointer to entire
structure.

This will allow to merge the error and the packet handlers and remove
the ->new() function in followup patches.

Signed-off-by: default avatarFlorian Westphal <fw@strlen.de>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent c8204cab
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -20,8 +20,7 @@
/* This header is used to share core functionality between the
   standalone connection tracking module, and the compatibility layer's use
   of connection tracking. */
unsigned int nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum,
			     struct sk_buff *skb);
unsigned int nf_conntrack_in(struct sk_buff *skb, const struct nf_hook_state *state);

int nf_conntrack_init_net(struct net *net);
void nf_conntrack_cleanup_net(struct net *net);
+4 −3
Original line number Diff line number Diff line
@@ -45,7 +45,8 @@ struct nf_conntrack_l4proto {
	int (*packet)(struct nf_conn *ct,
		      const struct sk_buff *skb,
		      unsigned int dataoff,
		      enum ip_conntrack_info ctinfo);
		      enum ip_conntrack_info ctinfo,
		      const struct nf_hook_state *state);

	/* Called when a new connection for this protocol found;
	 * returns TRUE if it's OK.  If so, packet() called next. */
@@ -55,9 +56,9 @@ struct nf_conntrack_l4proto {
	/* Called when a conntrack entry is destroyed */
	void (*destroy)(struct nf_conn *ct);

	int (*error)(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb,
	int (*error)(struct nf_conn *tmpl, struct sk_buff *skb,
		     unsigned int dataoff,
		     u_int8_t pf, unsigned int hooknum);
		     const struct nf_hook_state *state);

	/* called by gc worker if table is full */
	bool (*can_early_drop)(const struct nf_conn *ct);
+25 −24
Original line number Diff line number Diff line
@@ -1436,12 +1436,12 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,

/* On success, returns 0, sets skb->_nfct | ctinfo */
static int
resolve_normal_ct(struct net *net, struct nf_conn *tmpl,
resolve_normal_ct(struct nf_conn *tmpl,
		  struct sk_buff *skb,
		  unsigned int dataoff,
		  u_int16_t l3num,
		  u_int8_t protonum,
		  const struct nf_conntrack_l4proto *l4proto)
		  const struct nf_conntrack_l4proto *l4proto,
		  const struct nf_hook_state *state)
{
	const struct nf_conntrack_zone *zone;
	struct nf_conntrack_tuple tuple;
@@ -1452,17 +1452,18 @@ resolve_normal_ct(struct net *net, struct nf_conn *tmpl,
	u32 hash;

	if (!nf_ct_get_tuple(skb, skb_network_offset(skb),
			     dataoff, l3num, protonum, net, &tuple, l4proto)) {
			     dataoff, state->pf, protonum, state->net,
			     &tuple, l4proto)) {
		pr_debug("Can't get tuple\n");
		return 0;
	}

	/* look for tuple match */
	zone = nf_ct_zone_tmpl(tmpl, skb, &tmp);
	hash = hash_conntrack_raw(&tuple, net);
	h = __nf_conntrack_find_get(net, zone, &tuple, hash);
	hash = hash_conntrack_raw(&tuple, state->net);
	h = __nf_conntrack_find_get(state->net, zone, &tuple, hash);
	if (!h) {
		h = init_conntrack(net, tmpl, &tuple, l4proto,
		h = init_conntrack(state->net, tmpl, &tuple, l4proto,
				   skb, dataoff, hash);
		if (!h)
			return 0;
@@ -1492,12 +1493,11 @@ resolve_normal_ct(struct net *net, struct nf_conn *tmpl,
}

unsigned int
nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum,
		struct sk_buff *skb)
nf_conntrack_in(struct sk_buff *skb, const struct nf_hook_state *state)
{
	const struct nf_conntrack_l4proto *l4proto;
	struct nf_conn *ct, *tmpl;
	enum ip_conntrack_info ctinfo;
	struct nf_conn *ct, *tmpl;
	u_int8_t protonum;
	int dataoff, ret;

@@ -1506,32 +1506,32 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum,
		/* Previously seen (loopback or untracked)?  Ignore. */
		if ((tmpl && !nf_ct_is_template(tmpl)) ||
		     ctinfo == IP_CT_UNTRACKED) {
			NF_CT_STAT_INC_ATOMIC(net, ignore);
			NF_CT_STAT_INC_ATOMIC(state->net, ignore);
			return NF_ACCEPT;
		}
		skb->_nfct = 0;
	}

	/* rcu_read_lock()ed by nf_hook_thresh */
	dataoff = get_l4proto(skb, skb_network_offset(skb), pf, &protonum);
	dataoff = get_l4proto(skb, skb_network_offset(skb), state->pf, &protonum);
	if (dataoff <= 0) {
		pr_debug("not prepared to track yet or error occurred\n");
		NF_CT_STAT_INC_ATOMIC(net, error);
		NF_CT_STAT_INC_ATOMIC(net, invalid);
		NF_CT_STAT_INC_ATOMIC(state->net, error);
		NF_CT_STAT_INC_ATOMIC(state->net, invalid);
		ret = NF_ACCEPT;
		goto out;
	}

	l4proto = __nf_ct_l4proto_find(pf, protonum);
	l4proto = __nf_ct_l4proto_find(state->pf, protonum);

	/* It may be an special packet, error, unclean...
	 * inverse of the return code tells to the netfilter
	 * core what to do with the packet. */
	if (l4proto->error != NULL) {
		ret = l4proto->error(net, tmpl, skb, dataoff, pf, hooknum);
		ret = l4proto->error(tmpl, skb, dataoff, state);
		if (ret <= 0) {
			NF_CT_STAT_INC_ATOMIC(net, error);
			NF_CT_STAT_INC_ATOMIC(net, invalid);
			NF_CT_STAT_INC_ATOMIC(state->net, error);
			NF_CT_STAT_INC_ATOMIC(state->net, invalid);
			ret = -ret;
			goto out;
		}
@@ -1540,10 +1540,11 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum,
			goto out;
	}
repeat:
	ret = resolve_normal_ct(net, tmpl, skb, dataoff, pf, protonum, l4proto);
	ret = resolve_normal_ct(tmpl, skb, dataoff,
				protonum, l4proto, state);
	if (ret < 0) {
		/* Too stressed to deal. */
		NF_CT_STAT_INC_ATOMIC(net, drop);
		NF_CT_STAT_INC_ATOMIC(state->net, drop);
		ret = NF_DROP;
		goto out;
	}
@@ -1551,21 +1552,21 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum,
	ct = nf_ct_get(skb, &ctinfo);
	if (!ct) {
		/* Not valid part of a connection */
		NF_CT_STAT_INC_ATOMIC(net, invalid);
		NF_CT_STAT_INC_ATOMIC(state->net, invalid);
		ret = NF_ACCEPT;
		goto out;
	}

	ret = l4proto->packet(ct, skb, dataoff, ctinfo);
	ret = l4proto->packet(ct, skb, dataoff, ctinfo, state);
	if (ret <= 0) {
		/* Invalid: inverse of the return code tells
		 * the netfilter core what to do */
		pr_debug("nf_conntrack_in: Can't track with proto module\n");
		nf_conntrack_put(&ct->ct_general);
		skb->_nfct = 0;
		NF_CT_STAT_INC_ATOMIC(net, invalid);
		NF_CT_STAT_INC_ATOMIC(state->net, invalid);
		if (ret == -NF_DROP)
			NF_CT_STAT_INC_ATOMIC(net, drop);
			NF_CT_STAT_INC_ATOMIC(state->net, drop);
		/* Special case: TCP tracker reports an attempt to reopen a
		 * closed/aborted connection. We have to go back and create a
		 * fresh conntrack.
+4 −4
Original line number Diff line number Diff line
@@ -455,7 +455,7 @@ static unsigned int ipv4_conntrack_in(void *priv,
				      struct sk_buff *skb,
				      const struct nf_hook_state *state)
{
	return nf_conntrack_in(state->net, PF_INET, state->hook, skb);
	return nf_conntrack_in(skb, state);
}

static unsigned int ipv4_conntrack_local(void *priv,
@@ -477,7 +477,7 @@ static unsigned int ipv4_conntrack_local(void *priv,
		return NF_ACCEPT;
	}

	return nf_conntrack_in(state->net, PF_INET, state->hook, skb);
	return nf_conntrack_in(skb, state);
}

/* Connection tracking may drop packets, but never alters them, so
@@ -690,14 +690,14 @@ static unsigned int ipv6_conntrack_in(void *priv,
				      struct sk_buff *skb,
				      const struct nf_hook_state *state)
{
	return nf_conntrack_in(state->net, PF_INET6, state->hook, skb);
	return nf_conntrack_in(skb, state);
}

static unsigned int ipv6_conntrack_local(void *priv,
					 struct sk_buff *skb,
					 const struct nf_hook_state *state)
{
	return nf_conntrack_in(state->net, PF_INET6, state->hook, skb);
	return nf_conntrack_in(skb, state);
}

static unsigned int ipv6_helper(void *priv,
+10 −7
Original line number Diff line number Diff line
@@ -439,7 +439,8 @@ static u64 dccp_ack_seq(const struct dccp_hdr *dh)
}

static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb,
		       unsigned int dataoff, enum ip_conntrack_info ctinfo)
		       unsigned int dataoff, enum ip_conntrack_info ctinfo,
		       const struct nf_hook_state *state)
{
	enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
	struct dccp_hdr _dh, *dh;
@@ -527,9 +528,9 @@ static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb,
	return NF_ACCEPT;
}

static int dccp_error(struct net *net, struct nf_conn *tmpl,
static int dccp_error(struct nf_conn *tmpl,
		      struct sk_buff *skb, unsigned int dataoff,
		      u_int8_t pf, unsigned int hooknum)
		      const struct nf_hook_state *state)
{
	struct dccp_hdr _dh, *dh;
	unsigned int dccp_len = skb->len - dataoff;
@@ -557,9 +558,10 @@ static int dccp_error(struct net *net, struct nf_conn *tmpl,
		}
	}

	if (net->ct.sysctl_checksum && hooknum == NF_INET_PRE_ROUTING &&
	    nf_checksum_partial(skb, hooknum, dataoff, cscov, IPPROTO_DCCP,
				pf)) {
	if (state->hook == NF_INET_PRE_ROUTING &&
	    state->net->ct.sysctl_checksum &&
	    nf_checksum_partial(skb, state->hook, dataoff, cscov,
				IPPROTO_DCCP, state->pf)) {
		msg = "nf_ct_dccp: bad checksum ";
		goto out_invalid;
	}
@@ -572,7 +574,8 @@ static int dccp_error(struct net *net, struct nf_conn *tmpl,
	return NF_ACCEPT;

out_invalid:
	nf_l4proto_log_invalid(skb, net, pf, IPPROTO_DCCP, "%s", msg);
	nf_l4proto_log_invalid(skb, state->net, state->pf,
			       IPPROTO_DCCP, "%s", msg);
	return -NF_ACCEPT;
}

Loading