⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xfrm4_input.c

📁 linux 内核源代码
💻 C
字号:
/* * xfrm4_input.c * * Changes: *	YOSHIFUJI Hideaki @USAGI *		Split up af-specific portion *	Derek Atkins <derek@ihtfp.com> *		Add Encapsulation support * */#include <linux/module.h>#include <linux/string.h>#include <linux/netfilter.h>#include <linux/netfilter_ipv4.h>#include <net/ip.h>#include <net/xfrm.h>#ifdef CONFIG_NETFILTERstatic inline int xfrm4_rcv_encap_finish(struct sk_buff *skb){	if (skb->dst == NULL) {		const struct iphdr *iph = ip_hdr(skb);		if (ip_route_input(skb, iph->daddr, iph->saddr, iph->tos,				   skb->dev))			goto drop;	}	return dst_input(skb);drop:	kfree_skb(skb);	return NET_RX_DROP;}#endifint xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi,		    int encap_type){	int err;	__be32 seq;	struct xfrm_state *xfrm_vec[XFRM_MAX_DEPTH];	struct xfrm_state *x;	int xfrm_nr = 0;	int decaps = 0;	unsigned int nhoff = offsetof(struct iphdr, protocol);	seq = 0;	if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0)		goto drop;	do {		const struct iphdr *iph = ip_hdr(skb);		if (xfrm_nr == XFRM_MAX_DEPTH)			goto drop;		x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi,				      nexthdr, AF_INET);		if (x == NULL)			goto drop;		spin_lock(&x->lock);		if (unlikely(x->km.state != XFRM_STATE_VALID))			goto drop_unlock;		if ((x->encap ? x->encap->encap_type : 0) != encap_type)			goto drop_unlock;		if (x->props.replay_window && xfrm_replay_check(x, seq))			goto drop_unlock;		if (xfrm_state_check_expire(x))			goto drop_unlock;		nexthdr = x->type->input(x, skb);		if (nexthdr <= 0)			goto drop_unlock;		skb_network_header(skb)[nhoff] = nexthdr;		/* only the first xfrm gets the encap type */		encap_type = 0;		if (x->props.replay_window)			xfrm_replay_advance(x, seq);		x->curlft.bytes += skb->len;		x->curlft.packets++;		spin_unlock(&x->lock);		xfrm_vec[xfrm_nr++] = x;		if (x->outer_mode->input(x, skb))			goto drop;		if (x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL) {			decaps = 1;			break;		}		err = xfrm_parse_spi(skb, nexthdr, &spi, &seq);		if (err < 0)			goto drop;	} while (!err);	/* Allocate new secpath or COW existing one. */	if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) {		struct sec_path *sp;		sp = secpath_dup(skb->sp);		if (!sp)			goto drop;		if (skb->sp)			secpath_put(skb->sp);		skb->sp = sp;	}	if (xfrm_nr + skb->sp->len > XFRM_MAX_DEPTH)		goto drop;	memcpy(skb->sp->xvec + skb->sp->len, xfrm_vec,	       xfrm_nr * sizeof(xfrm_vec[0]));	skb->sp->len += xfrm_nr;	nf_reset(skb);	if (decaps) {		dst_release(skb->dst);		skb->dst = NULL;		netif_rx(skb);		return 0;	} else {#ifdef CONFIG_NETFILTER		__skb_push(skb, skb->data - skb_network_header(skb));		ip_hdr(skb)->tot_len = htons(skb->len);		ip_send_check(ip_hdr(skb));		NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, skb->dev, NULL,			xfrm4_rcv_encap_finish);		return 0;#else		return -ip_hdr(skb)->protocol;#endif	}drop_unlock:	spin_unlock(&x->lock);	xfrm_state_put(x);drop:	while (--xfrm_nr >= 0)		xfrm_state_put(xfrm_vec[xfrm_nr]);	kfree_skb(skb);	return 0;}EXPORT_SYMBOL(xfrm4_rcv_encap);/* If it's a keepalive packet, then just eat it. * If it's an encapsulated packet, then pass it to the * IPsec xfrm input. * Returns 0 if skb passed to xfrm or was dropped. * Returns >0 if skb should be passed to UDP. * Returns <0 if skb should be resubmitted (-ret is protocol) */int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb){	struct udp_sock *up = udp_sk(sk);	struct udphdr *uh;	struct iphdr *iph;	int iphlen, len;	int ret;	__u8 *udpdata;	__be32 *udpdata32;	__u16 encap_type = up->encap_type;	/* if this is not encapsulated socket, then just return now */	if (!encap_type)		return 1;	/* If this is a paged skb, make sure we pull up	 * whatever data we need to look at. */	len = skb->len - sizeof(struct udphdr);	if (!pskb_may_pull(skb, sizeof(struct udphdr) + min(len, 8)))		return 1;	/* Now we can get the pointers */	uh = udp_hdr(skb);	udpdata = (__u8 *)uh + sizeof(struct udphdr);	udpdata32 = (__be32 *)udpdata;	switch (encap_type) {	default:	case UDP_ENCAP_ESPINUDP:		/* Check if this is a keepalive packet.  If so, eat it. */		if (len == 1 && udpdata[0] == 0xff) {			goto drop;		} else if (len > sizeof(struct ip_esp_hdr) && udpdata32[0] != 0) {			/* ESP Packet without Non-ESP header */			len = sizeof(struct udphdr);		} else			/* Must be an IKE packet.. pass it through */			return 1;		break;	case UDP_ENCAP_ESPINUDP_NON_IKE:		/* Check if this is a keepalive packet.  If so, eat it. */		if (len == 1 && udpdata[0] == 0xff) {			goto drop;		} else if (len > 2 * sizeof(u32) + sizeof(struct ip_esp_hdr) &&			   udpdata32[0] == 0 && udpdata32[1] == 0) {			/* ESP Packet with Non-IKE marker */			len = sizeof(struct udphdr) + 2 * sizeof(u32);		} else			/* Must be an IKE packet.. pass it through */			return 1;		break;	}	/* At this point we are sure that this is an ESPinUDP packet,	 * so we need to remove 'len' bytes from the packet (the UDP	 * header and optional ESP marker bytes) and then modify the	 * protocol to ESP, and then call into the transform receiver.	 */	if (skb_cloned(skb) && pskb_expand_head(skb, 0, 0, GFP_ATOMIC))		goto drop;	/* Now we can update and verify the packet length... */	iph = ip_hdr(skb);	iphlen = iph->ihl << 2;	iph->tot_len = htons(ntohs(iph->tot_len) - len);	if (skb->len < iphlen + len) {		/* packet is too small!?! */		goto drop;	}	/* pull the data buffer up to the ESP header and set the	 * transport header to point to ESP.  Keep UDP on the stack	 * for later.	 */	__skb_pull(skb, len);	skb_reset_transport_header(skb);	/* process ESP */	ret = xfrm4_rcv_encap(skb, IPPROTO_ESP, 0, encap_type);	return ret;drop:	kfree_skb(skb);	return 0;}int xfrm4_rcv(struct sk_buff *skb){	return xfrm4_rcv_spi(skb, ip_hdr(skb)->protocol, 0);}EXPORT_SYMBOL(xfrm4_rcv);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -