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 Original line Diff line number Diff line
@@ -20,8 +20,7 @@
/* This header is used to share core functionality between the
/* This header is used to share core functionality between the
   standalone connection tracking module, and the compatibility layer's use
   standalone connection tracking module, and the compatibility layer's use
   of connection tracking. */
   of connection tracking. */
unsigned int nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum,
unsigned int nf_conntrack_in(struct sk_buff *skb, const struct nf_hook_state *state);
			     struct sk_buff *skb);


int nf_conntrack_init_net(struct net *net);
int nf_conntrack_init_net(struct net *net);
void nf_conntrack_cleanup_net(struct net *net);
void nf_conntrack_cleanup_net(struct net *net);
+4 −3
Original line number Original line Diff line number Diff line
@@ -45,7 +45,8 @@ struct nf_conntrack_l4proto {
	int (*packet)(struct nf_conn *ct,
	int (*packet)(struct nf_conn *ct,
		      const struct sk_buff *skb,
		      const struct sk_buff *skb,
		      unsigned int dataoff,
		      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;
	/* Called when a new connection for this protocol found;
	 * returns TRUE if it's OK.  If so, packet() called next. */
	 * 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 */
	/* Called when a conntrack entry is destroyed */
	void (*destroy)(struct nf_conn *ct);
	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,
		     unsigned int dataoff,
		     u_int8_t pf, unsigned int hooknum);
		     const struct nf_hook_state *state);


	/* called by gc worker if table is full */
	/* called by gc worker if table is full */
	bool (*can_early_drop)(const struct nf_conn *ct);
	bool (*can_early_drop)(const struct nf_conn *ct);
+25 −24
Original line number Original line 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 */
/* On success, returns 0, sets skb->_nfct | ctinfo */
static int
static int
resolve_normal_ct(struct net *net, struct nf_conn *tmpl,
resolve_normal_ct(struct nf_conn *tmpl,
		  struct sk_buff *skb,
		  struct sk_buff *skb,
		  unsigned int dataoff,
		  unsigned int dataoff,
		  u_int16_t l3num,
		  u_int8_t protonum,
		  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;
	const struct nf_conntrack_zone *zone;
	struct nf_conntrack_tuple tuple;
	struct nf_conntrack_tuple tuple;
@@ -1452,17 +1452,18 @@ resolve_normal_ct(struct net *net, struct nf_conn *tmpl,
	u32 hash;
	u32 hash;


	if (!nf_ct_get_tuple(skb, skb_network_offset(skb),
	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");
		pr_debug("Can't get tuple\n");
		return 0;
		return 0;
	}
	}


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


unsigned int
unsigned int
nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum,
nf_conntrack_in(struct sk_buff *skb, const struct nf_hook_state *state)
		struct sk_buff *skb)
{
{
	const struct nf_conntrack_l4proto *l4proto;
	const struct nf_conntrack_l4proto *l4proto;
	struct nf_conn *ct, *tmpl;
	enum ip_conntrack_info ctinfo;
	enum ip_conntrack_info ctinfo;
	struct nf_conn *ct, *tmpl;
	u_int8_t protonum;
	u_int8_t protonum;
	int dataoff, ret;
	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. */
		/* Previously seen (loopback or untracked)?  Ignore. */
		if ((tmpl && !nf_ct_is_template(tmpl)) ||
		if ((tmpl && !nf_ct_is_template(tmpl)) ||
		     ctinfo == IP_CT_UNTRACKED) {
		     ctinfo == IP_CT_UNTRACKED) {
			NF_CT_STAT_INC_ATOMIC(net, ignore);
			NF_CT_STAT_INC_ATOMIC(state->net, ignore);
			return NF_ACCEPT;
			return NF_ACCEPT;
		}
		}
		skb->_nfct = 0;
		skb->_nfct = 0;
	}
	}


	/* rcu_read_lock()ed by nf_hook_thresh */
	/* 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) {
	if (dataoff <= 0) {
		pr_debug("not prepared to track yet or error occurred\n");
		pr_debug("not prepared to track yet or error occurred\n");
		NF_CT_STAT_INC_ATOMIC(net, error);
		NF_CT_STAT_INC_ATOMIC(state->net, error);
		NF_CT_STAT_INC_ATOMIC(net, invalid);
		NF_CT_STAT_INC_ATOMIC(state->net, invalid);
		ret = NF_ACCEPT;
		ret = NF_ACCEPT;
		goto out;
		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...
	/* It may be an special packet, error, unclean...
	 * inverse of the return code tells to the netfilter
	 * inverse of the return code tells to the netfilter
	 * core what to do with the packet. */
	 * core what to do with the packet. */
	if (l4proto->error != NULL) {
	if (l4proto->error != NULL) {
		ret = l4proto->error(net, tmpl, skb, dataoff, pf, hooknum);
		ret = l4proto->error(tmpl, skb, dataoff, state);
		if (ret <= 0) {
		if (ret <= 0) {
			NF_CT_STAT_INC_ATOMIC(net, error);
			NF_CT_STAT_INC_ATOMIC(state->net, error);
			NF_CT_STAT_INC_ATOMIC(net, invalid);
			NF_CT_STAT_INC_ATOMIC(state->net, invalid);
			ret = -ret;
			ret = -ret;
			goto out;
			goto out;
		}
		}
@@ -1540,10 +1540,11 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum,
			goto out;
			goto out;
	}
	}
repeat:
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) {
	if (ret < 0) {
		/* Too stressed to deal. */
		/* Too stressed to deal. */
		NF_CT_STAT_INC_ATOMIC(net, drop);
		NF_CT_STAT_INC_ATOMIC(state->net, drop);
		ret = NF_DROP;
		ret = NF_DROP;
		goto out;
		goto out;
	}
	}
@@ -1551,21 +1552,21 @@ repeat:
	ct = nf_ct_get(skb, &ctinfo);
	ct = nf_ct_get(skb, &ctinfo);
	if (!ct) {
	if (!ct) {
		/* Not valid part of a connection */
		/* Not valid part of a connection */
		NF_CT_STAT_INC_ATOMIC(net, invalid);
		NF_CT_STAT_INC_ATOMIC(state->net, invalid);
		ret = NF_ACCEPT;
		ret = NF_ACCEPT;
		goto out;
		goto out;
	}
	}


	ret = l4proto->packet(ct, skb, dataoff, ctinfo);
	ret = l4proto->packet(ct, skb, dataoff, ctinfo, state);
	if (ret <= 0) {
	if (ret <= 0) {
		/* Invalid: inverse of the return code tells
		/* Invalid: inverse of the return code tells
		 * the netfilter core what to do */
		 * the netfilter core what to do */
		pr_debug("nf_conntrack_in: Can't track with proto module\n");
		pr_debug("nf_conntrack_in: Can't track with proto module\n");
		nf_conntrack_put(&ct->ct_general);
		nf_conntrack_put(&ct->ct_general);
		skb->_nfct = 0;
		skb->_nfct = 0;
		NF_CT_STAT_INC_ATOMIC(net, invalid);
		NF_CT_STAT_INC_ATOMIC(state->net, invalid);
		if (ret == -NF_DROP)
		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
		/* Special case: TCP tracker reports an attempt to reopen a
		 * closed/aborted connection. We have to go back and create a
		 * closed/aborted connection. We have to go back and create a
		 * fresh conntrack.
		 * fresh conntrack.
+4 −4
Original line number Original line Diff line number Diff line
@@ -455,7 +455,7 @@ static unsigned int ipv4_conntrack_in(void *priv,
				      struct sk_buff *skb,
				      struct sk_buff *skb,
				      const struct nf_hook_state *state)
				      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,
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_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
/* 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,
				      struct sk_buff *skb,
				      const struct nf_hook_state *state)
				      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,
static unsigned int ipv6_conntrack_local(void *priv,
					 struct sk_buff *skb,
					 struct sk_buff *skb,
					 const struct nf_hook_state *state)
					 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,
static unsigned int ipv6_helper(void *priv,
+10 −7
Original line number Original line 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,
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);
	enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
	struct dccp_hdr _dh, *dh;
	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;
	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,
		      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;
	struct dccp_hdr _dh, *dh;
	unsigned int dccp_len = skb->len - dataoff;
	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 &&
	if (state->hook == NF_INET_PRE_ROUTING &&
	    nf_checksum_partial(skb, hooknum, dataoff, cscov, IPPROTO_DCCP,
	    state->net->ct.sysctl_checksum &&
				pf)) {
	    nf_checksum_partial(skb, state->hook, dataoff, cscov,
				IPPROTO_DCCP, state->pf)) {
		msg = "nf_ct_dccp: bad checksum ";
		msg = "nf_ct_dccp: bad checksum ";
		goto out_invalid;
		goto out_invalid;
	}
	}
@@ -572,7 +574,8 @@ static int dccp_error(struct net *net, struct nf_conn *tmpl,
	return NF_ACCEPT;
	return NF_ACCEPT;


out_invalid:
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;
	return -NF_ACCEPT;
}
}


Loading