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

Commit 14e50e57 authored by David S. Miller's avatar David S. Miller
Browse files

[XFRM]: Allow packet drops during larval state resolution.



The current IPSEC rule resolution behavior we have does not work for a
lot of people, even though technically it's an improvement from the
-EAGAIN buisness we had before.

Right now we'll block until the key manager resolves the route.  That
works for simple cases, but many folks would rather packets get
silently dropped until the key manager resolves the IPSEC rules.

We can't tell these folks to "set the socket non-blocking" because
they don't have control over the non-block setting of things like the
sockets used to resolve DNS deep inside of the resolver libraries in
libc.

With that in mind I coded up the patch below with some help from
Herbert Xu which provides packet-drop behavior during larval state
resolution, controllable via sysctl and off by default.

This lays the framework to either:

1) Make this default at some point or...

2) Move this logic into xfrm{4,6}_policy.c and implement the
   ARP-like resolution queue we've all been dreaming of.
   The idea would be to queue packets to the policy, then
   once the larval state is resolved by the key manager we
   re-resolve the route and push the packets out.  The
   packets would timeout if the rule didn't get resolved
   in a certain amount of time.

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 04efb878
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -265,9 +265,16 @@ static inline int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl,
{
	return 0;
} 
static inline int __xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl,
				struct sock *sk, int flags)
{
	return 0;
}
#else
extern int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl,
		       struct sock *sk, int flags);
extern int __xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl,
			 struct sock *sk, int flags);
#endif
#endif

+3 −0
Original line number Diff line number Diff line
@@ -469,6 +469,9 @@ extern void ip6_flush_pending_frames(struct sock *sk);
extern int			ip6_dst_lookup(struct sock *sk,
					       struct dst_entry **dst,
					       struct flowi *fl);
extern int			ip6_dst_blackhole(struct sock *sk,
						  struct dst_entry **dst,
						  struct flowi *fl);
extern int			ip6_sk_dst_lookup(struct sock *sk,
						  struct dst_entry **dst,
						  struct flowi *fl);
+9 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ extern int sysctl_core_destroy_delay;
#ifdef CONFIG_XFRM
extern u32 sysctl_xfrm_aevent_etime;
extern u32 sysctl_xfrm_aevent_rseqth;
extern int sysctl_xfrm_larval_drop;
#endif

ctl_table core_table[] = {
@@ -118,6 +119,14 @@ ctl_table core_table[] = {
		.mode		= 0644,
		.proc_handler	= &proc_dointvec
	},
	{
		.ctl_name	= CTL_UNNUMBERED,
		.procname	= "xfrm_larval_drop",
		.data		= &sysctl_xfrm_larval_drop,
		.maxlen		= sizeof(int),
		.mode		= 0644,
		.proc_handler	= &proc_dointvec
	},
#endif /* CONFIG_XFRM */
#endif /* CONFIG_NET */
	{
+7 −3
Original line number Diff line number Diff line
@@ -1043,9 +1043,13 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
	if (final_p)
		ipv6_addr_copy(&fl.fl6_dst, final_p);

	err = xfrm_lookup(&dst, &fl, sk, 1);
	err = __xfrm_lookup(&dst, &fl, sk, 1);
	if (err < 0) {
		if (err == -EREMOTE)
			err = ip6_dst_blackhole(sk, &dst, &fl);
		if (err < 0)
			goto failure;
	}

	if (saddr == NULL) {
		saddr = &fl.fl6_src;
+70 −1
Original line number Diff line number Diff line
@@ -2598,6 +2598,69 @@ int __ip_route_output_key(struct rtable **rp, const struct flowi *flp)

EXPORT_SYMBOL_GPL(__ip_route_output_key);

static void ipv4_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu)
{
}

static struct dst_ops ipv4_dst_blackhole_ops = {
	.family			=	AF_INET,
	.protocol		=	__constant_htons(ETH_P_IP),
	.destroy		=	ipv4_dst_destroy,
	.check			=	ipv4_dst_check,
	.update_pmtu		=	ipv4_rt_blackhole_update_pmtu,
	.entry_size		=	sizeof(struct rtable),
};


static int ipv4_blackhole_output(struct sk_buff *skb)
{
	kfree_skb(skb);
	return 0;
}

static int ipv4_dst_blackhole(struct rtable **rp, struct flowi *flp, struct sock *sk)
{
	struct rtable *ort = *rp;
	struct rtable *rt = (struct rtable *)
		dst_alloc(&ipv4_dst_blackhole_ops);

	if (rt) {
		struct dst_entry *new = &rt->u.dst;

		atomic_set(&new->__refcnt, 1);
		new->__use = 1;
		new->input = ipv4_blackhole_output;
		new->output = ipv4_blackhole_output;
		memcpy(new->metrics, ort->u.dst.metrics, RTAX_MAX*sizeof(u32));

		new->dev = ort->u.dst.dev;
		if (new->dev)
			dev_hold(new->dev);

		rt->fl = ort->fl;

		rt->idev = ort->idev;
		if (rt->idev)
			in_dev_hold(rt->idev);
		rt->rt_flags = ort->rt_flags;
		rt->rt_type = ort->rt_type;
		rt->rt_dst = ort->rt_dst;
		rt->rt_src = ort->rt_src;
		rt->rt_iif = ort->rt_iif;
		rt->rt_gateway = ort->rt_gateway;
		rt->rt_spec_dst = ort->rt_spec_dst;
		rt->peer = ort->peer;
		if (rt->peer)
			atomic_inc(&rt->peer->refcnt);

		dst_free(new);
	}

	dst_release(&(*rp)->u.dst);
	*rp = rt;
	return (rt ? 0 : -ENOMEM);
}

int ip_route_output_flow(struct rtable **rp, struct flowi *flp, struct sock *sk, int flags)
{
	int err;
@@ -2610,7 +2673,11 @@ int ip_route_output_flow(struct rtable **rp, struct flowi *flp, struct sock *sk,
			flp->fl4_src = (*rp)->rt_src;
		if (!flp->fl4_dst)
			flp->fl4_dst = (*rp)->rt_dst;
		return xfrm_lookup((struct dst_entry **)rp, flp, sk, flags);
		err = __xfrm_lookup((struct dst_entry **)rp, flp, sk, flags);
		if (err == -EREMOTE)
			err = ipv4_dst_blackhole(rp, flp, sk);

		return err;
	}

	return 0;
@@ -3139,6 +3206,8 @@ int __init ip_rt_init(void)
		kmem_cache_create("ip_dst_cache", sizeof(struct rtable), 0,
				  SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);

	ipv4_dst_blackhole_ops.kmem_cachep = ipv4_dst_ops.kmem_cachep;

	rt_hash_table = (struct rt_hash_bucket *)
		alloc_large_system_hash("IP route cache",
					sizeof(struct rt_hash_bucket),
Loading