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

Commit 5c901daa authored by Patrick McHardy's avatar Patrick McHardy Committed by David S. Miller
Browse files

[NETFILTER]: Redo policy lookups after NAT when neccessary



When NAT changes the key used for the xfrm lookup it needs to be done
again. If a new policy is returned in POST_ROUTING the packet needs
to be passed to xfrm4_output_one manually after all hooks were called
because POST_ROUTING is called with fixed okfn (ip_finish_output).

Signed-off-by: default avatarPatrick McHardy <kaber@trash.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 4e8e9de7
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -866,6 +866,7 @@ extern int xfrm_state_mtu(struct xfrm_state *x, int mtu);
extern int xfrm_init_state(struct xfrm_state *x);
extern int xfrm4_rcv(struct sk_buff *skb);
extern int xfrm4_output(struct sk_buff *skb);
extern int xfrm4_output_finish(struct sk_buff *skb);
extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler);
extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler);
extern int xfrm6_rcv_spi(struct sk_buff **pskb, u32 spi);
+5 −0
Original line number Diff line number Diff line
@@ -202,6 +202,11 @@ static inline int ip_finish_output2(struct sk_buff *skb)

static inline int ip_finish_output(struct sk_buff *skb)
{
#if defined(CONFIG_NETFILTER) && defined(CONFIG_XFRM)
	/* Policy lookup after SNAT yielded a new policy */
	if (skb->dst->xfrm != NULL)
		return xfrm4_output_finish(skb);
#endif
	if (skb->len > dst_mtu(skb->dst) &&
	    !(skb_shinfo(skb)->ufo_size || skb_shinfo(skb)->tso_size))
		return ip_fragment(skb, ip_finish_output2);
+25 −2
Original line number Diff line number Diff line
@@ -187,12 +187,30 @@ ip_nat_out(unsigned int hooknum,
	   const struct net_device *out,
	   int (*okfn)(struct sk_buff *))
{
	struct ip_conntrack *ct;
	enum ip_conntrack_info ctinfo;
	unsigned int ret;

	/* root is playing with raw sockets. */
	if ((*pskb)->len < sizeof(struct iphdr)
	    || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr))
		return NF_ACCEPT;

	return ip_nat_fn(hooknum, pskb, in, out, okfn);
	ret = ip_nat_fn(hooknum, pskb, in, out, okfn);
	if (ret != NF_DROP && ret != NF_STOLEN
	    && (ct = ip_conntrack_get(*pskb, &ctinfo)) != NULL) {
		enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);

		if (ct->tuplehash[dir].tuple.src.ip !=
		    ct->tuplehash[!dir].tuple.dst.ip
#ifdef CONFIG_XFRM
		    || ct->tuplehash[dir].tuple.src.u.all !=
		       ct->tuplehash[!dir].tuple.dst.u.all
#endif
		    )
			return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP;
	}
	return ret;
}

static unsigned int
@@ -217,7 +235,12 @@ ip_nat_local_fn(unsigned int hooknum,
		enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);

		if (ct->tuplehash[dir].tuple.dst.ip !=
		    ct->tuplehash[!dir].tuple.src.ip)
		    ct->tuplehash[!dir].tuple.src.ip
#ifdef CONFIG_XFRM
		    || ct->tuplehash[dir].tuple.dst.u.all !=
		       ct->tuplehash[dir].tuple.src.u.all
#endif
		    )
			return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP;
	}
	return ret;
+1 −1
Original line number Diff line number Diff line
@@ -152,7 +152,7 @@ static int xfrm4_output_one(struct sk_buff *skb)
	goto out_exit;
}

static int xfrm4_output_finish(struct sk_buff *skb)
int xfrm4_output_finish(struct sk_buff *skb)
{
	int err;