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

Commit 752c1f4c authored by Herbert Xu's avatar Herbert Xu Committed by David S. Miller
Browse files

[IPSEC]: Kill post_input hook and do NAT-T in esp_input directly



The only reason post_input exists at all is that it gives us the
potential to adjust the checksums incrementally in future which
we ought to do.

However, after thinking about it for a bit we can adjust the
checksums without using this post_input stuff at all.  The crucial
point is that only the inner-most NAT-T SA needs to be considered
when adjusting checksums.  What's more, the checksum adjustment
comes down to a single u32 due to the linearity of IP checksums.

We just happen to have a spare u32 lying around in our skb structure :)
When ip_summed is set to CHECKSUM_NONE on input, the value of skb->csum
is currently unused.  All we have to do is to make that the checksum
adjustment and voila, there goes all the post_input and decap structures!

I've left in the decap data structures for now since it's intricately
woven into the sec_path stuff.  We can kill them later too.

Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 4bf05ece
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -233,7 +233,6 @@ struct xfrm_type
	int			(*init_state)(struct xfrm_state *x);
	void			(*destructor)(struct xfrm_state *);
	int			(*input)(struct xfrm_state *, struct xfrm_decap_state *, struct sk_buff *skb);
	int			(*post_input)(struct xfrm_state *, struct xfrm_decap_state *, struct sk_buff *skb);
	int			(*output)(struct xfrm_state *, struct sk_buff *pskb);
	/* Estimate maximal size of result of transformation of a dgram */
	u32			(*get_max_size)(struct xfrm_state *, int size);
+38 −90
Original line number Diff line number Diff line
@@ -12,13 +12,6 @@
#include <net/protocol.h>
#include <net/udp.h>

/* decapsulation data for use when post-processing */
struct esp_decap_data {
	xfrm_address_t	saddr;
	__u16		sport;
	__u8		proto;
};

static int esp_output(struct xfrm_state *x, struct sk_buff *skb)
{
	int err;
@@ -210,72 +203,28 @@ static int esp_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struc

	/* ... check padding bits here. Silly. :-) */ 

	if (x->encap && decap && decap->decap_type) {
		struct esp_decap_data *encap_data;
		struct udphdr *uh = (struct udphdr *) (iph+1);

		encap_data = (struct esp_decap_data *) (decap->decap_data);
		encap_data->proto = 0;

		switch (decap->decap_type) {
		case UDP_ENCAP_ESPINUDP:
		case UDP_ENCAP_ESPINUDP_NON_IKE:
			encap_data->proto = AF_INET;
			encap_data->saddr.a4 = iph->saddr;
			encap_data->sport = uh->source;
			encap_len = (void*)esph - (void*)uh;
			break;

		default:
			goto out;
		}
	}

	iph->protocol = nexthdr[1];
	pskb_trim(skb, skb->len - alen - padlen - 2);
	memcpy(workbuf, skb->nh.raw, iph->ihl*4);
	skb->h.raw = skb_pull(skb, sizeof(struct ip_esp_hdr) + esp->conf.ivlen);
	skb->nh.raw += encap_len + sizeof(struct ip_esp_hdr) + esp->conf.ivlen;
	memcpy(skb->nh.raw, workbuf, iph->ihl*4);
	skb->nh.iph->tot_len = htons(skb->len);

	return 0;

out:
	return -EINVAL;
}

static int esp_post_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_buff *skb)
{
  
	if (x->encap) {
		struct xfrm_encap_tmpl *encap;
		struct esp_decap_data *decap_data;

		encap = x->encap;
		decap_data = (struct esp_decap_data *)(decap->decap_data);
		struct xfrm_encap_tmpl *encap = x->encap;
		struct udphdr *uh;

		/* first, make sure that the decap type == the encap type */
		if (encap->encap_type != decap->decap_type)
			return -EINVAL;
			goto out;

		uh = (struct udphdr *)(iph + 1);
		encap_len = (void*)esph - (void*)uh;

		switch (encap->encap_type) {
		default:
		case UDP_ENCAP_ESPINUDP:
		case UDP_ENCAP_ESPINUDP_NON_IKE:
		/*
		 * 1) if the NAT-T peer's IP or port changed then
		 *    advertize the change to the keying daemon.
		 *    This is an inbound SA, so just compare
		 *    SRC ports.
		 */
			if (decap_data->proto == AF_INET &&
			    (decap_data->saddr.a4 != x->props.saddr.a4 ||
			     decap_data->sport != encap->encap_sport)) {
		if (iph->saddr != x->props.saddr.a4 ||
		    uh->source != encap->encap_sport) {
			xfrm_address_t ipaddr;

				ipaddr.a4 = decap_data->saddr.a4;
				km_new_mapping(x, &ipaddr, decap_data->sport);
			ipaddr.a4 = iph->saddr;
			km_new_mapping(x, &ipaddr, uh->source);
				
			/* XXX: perhaps add an extra
			 * policy check here, to see
@@ -290,16 +239,25 @@ static int esp_post_input(struct xfrm_state *x, struct xfrm_decap_state *decap,
		 * 2) ignore UDP/TCP checksums in case
		 *    of NAT-T in Transport Mode, or
		 *    perform other post-processing fixes
			 *    as per * draft-ietf-ipsec-udp-encaps-06,
		 *    as per draft-ietf-ipsec-udp-encaps-06,
		 *    section 3.1.2
		 */
		if (!x->props.mode)
			skb->ip_summed = CHECKSUM_UNNECESSARY;

			break;
		}
	}

	iph->protocol = nexthdr[1];
	pskb_trim(skb, skb->len - alen - padlen - 2);
	memcpy(workbuf, skb->nh.raw, iph->ihl*4);
	skb->h.raw = skb_pull(skb, sizeof(struct ip_esp_hdr) + esp->conf.ivlen);
	skb->nh.raw += encap_len + sizeof(struct ip_esp_hdr) + esp->conf.ivlen;
	memcpy(skb->nh.raw, workbuf, iph->ihl*4);
	skb->nh.iph->tot_len = htons(skb->len);

	return 0;

out:
	return -EINVAL;
}

static u32 esp4_get_max_size(struct xfrm_state *x, int mtu)
@@ -457,7 +415,6 @@ static struct xfrm_type esp_type =
	.destructor	= esp_destroy,
	.get_max_size	= esp4_get_max_size,
	.input		= esp_input,
	.post_input	= esp_post_input,
	.output		= esp_output
};

@@ -469,15 +426,6 @@ static struct net_protocol esp4_protocol = {

static int __init esp4_init(void)
{
	struct xfrm_decap_state decap;

	if (sizeof(struct esp_decap_data)  >
	    sizeof(decap.decap_data)) {
		extern void decap_data_too_small(void);

		decap_data_too_small();
	}

	if (xfrm_register_type(&esp_type, AF_INET) < 0) {
		printk(KERN_INFO "ip esp init: can't add xfrm type\n");
		return -EAGAIN;
+0 −7
Original line number Diff line number Diff line
@@ -996,13 +996,6 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
			struct sec_decap_state *xvec = &(skb->sp->x[i]);
			if (!xfrm_selector_match(&xvec->xvec->sel, &fl, family))
				return 0;

			/* If there is a post_input processor, try running it */
			if (xvec->xvec->type->post_input &&
			    (xvec->xvec->type->post_input)(xvec->xvec,
							   &(xvec->decap),
							   skb) != 0)
				return 0;
		}
	}