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

📄 ipsec_rcv.c

📁 openswan
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * receive code * Copyright (C) 1996, 1997  John Ioannidis. * Copyright (C) 1998-2003   Richard Guy Briggs. * Copyright (C) 2004        Michael Richardson <mcr@xelerance.com> * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * for more details. */char ipsec_rcv_c_version[] = "RCSID $Id: ipsec_rcv.c,v 1.171.2.9 2006/07/30 02:09:33 paul Exp $";#include <linux/config.h>#include <linux/version.h>#define __NO_VERSION__#include <linux/module.h>#include <linux/kernel.h> /* printk() */#include "openswan/ipsec_param.h"#ifdef MALLOC_SLAB# include <linux/slab.h> /* kmalloc() */#else /* MALLOC_SLAB */# include <linux/malloc.h> /* kmalloc() */#endif /* MALLOC_SLAB */#include <linux/errno.h>  /* error codes */#include <linux/types.h>  /* size_t */#include <linux/interrupt.h> /* mark_bh */#include <linux/netdevice.h>	/* struct device, and other headers */#include <linux/etherdevice.h>	/* eth_type_trans */#include <linux/ip.h>		/* struct iphdr */#include <net/tcp.h>#include <net/udp.h>#include <linux/skbuff.h>#include <openswan.h>#ifdef SPINLOCK# ifdef SPINLOCK_23#  include <linux/spinlock.h> /* *lock* */# else /* SPINLOCK_23 */#  include <asm/spinlock.h> /* *lock* */# endif /* SPINLOCK_23 */#endif /* SPINLOCK */#include <net/ip.h>#include "openswan/ipsec_kern24.h"#include "openswan/radij.h"#include "openswan/ipsec_encap.h"#include "openswan/ipsec_sa.h"#include "openswan/ipsec_radij.h"#include "openswan/ipsec_xform.h"#include "openswan/ipsec_tunnel.h"#include "openswan/ipsec_rcv.h"#include "openswan/ipsec_auth.h"#include "openswan/ipsec_esp.h"#ifdef CONFIG_KLIPS_AH#include "openswan/ipsec_ah.h"#endif /* CONFIG_KLIPS_AH */#ifdef CONFIG_KLIPS_IPCOMP#include "openswan/ipsec_ipcomp.h"#endif /* CONFIG_KLIPS_COMP */#include <pfkeyv2.h>#include <pfkey.h>#include "openswan/ipsec_proto.h"#include "openswan/ipsec_alg.h"#include "openswan/ipsec_kern24.h"#ifdef CONFIG_KLIPS_DEBUGint debug_rcv = 0;#endif /* CONFIG_KLIPS_DEBUG */int sysctl_ipsec_inbound_policy_check = 1;#ifdef CONFIG_IPSEC_NAT_TRAVERSAL#include <linux/udp.h>#endif/* This is a private use protocol, and AT&T should be ashamed. They should have * used protocol # 59, which is "no next header" instead of 0xFE. */#ifndef IPPROTO_ATT_HEARTBEAT#define IPPROTO_ATT_HEARTBEAT 0xFE#endif/* * Check-replay-window routine, adapted from the original * by J. Hughes, from draft-ietf-ipsec-esp-des-md5-03.txt * *  This is a routine that implements a 64 packet window. This is intend- *  ed on being an implementation sample. */DEBUG_NO_STATIC intipsec_checkreplaywindow(struct ipsec_sa*ipsp, __u32 seq){	__u32 diff;	if (ipsp->ips_replaywin == 0)	/* replay shut off */		return 1;	if (seq == 0)		return 0;		/* first == 0 or wrapped */	/* new larger sequence number */	if (seq > ipsp->ips_replaywin_lastseq) {		return 1;		/* larger is good */	}	diff = ipsp->ips_replaywin_lastseq - seq;	/* too old or wrapped */ /* if wrapped, kill off SA? */	if (diff >= ipsp->ips_replaywin) {		return 0;	}	/* this packet already seen */	if (ipsp->ips_replaywin_bitmap & (1 << diff))		return 0;	return 1;			/* out of order but good */}DEBUG_NO_STATIC intipsec_updatereplaywindow(struct ipsec_sa*ipsp, __u32 seq){	__u32 diff;	if (ipsp->ips_replaywin == 0)	/* replay shut off */		return 1;	if (seq == 0)		return 0;		/* first == 0 or wrapped */	/* new larger sequence number */	if (seq > ipsp->ips_replaywin_lastseq) {		diff = seq - ipsp->ips_replaywin_lastseq;		/* In win, set bit for this pkt */		if (diff < ipsp->ips_replaywin)			ipsp->ips_replaywin_bitmap =				(ipsp->ips_replaywin_bitmap << diff) | 1;		else			/* This packet has way larger seq num */			ipsp->ips_replaywin_bitmap = 1;		if(seq - ipsp->ips_replaywin_lastseq - 1 > ipsp->ips_replaywin_maxdiff) {			ipsp->ips_replaywin_maxdiff = seq - ipsp->ips_replaywin_lastseq - 1;		}		ipsp->ips_replaywin_lastseq = seq;		return 1;		/* larger is good */	}	diff = ipsp->ips_replaywin_lastseq - seq;	/* too old or wrapped */ /* if wrapped, kill off SA? */	if (diff >= ipsp->ips_replaywin) {/*		if(seq < 0.25*max && ipsp->ips_replaywin_lastseq > 0.75*max) {			ipsec_sa_delchain(ipsp);		}*/		return 0;	}	/* this packet already seen */	if (ipsp->ips_replaywin_bitmap & (1 << diff))		return 0;	ipsp->ips_replaywin_bitmap |= (1 << diff);	/* mark as seen */	return 1;			/* out of order but good */}#ifdef CONFIG_KLIPS_AUTH_HMAC_MD5struct auth_alg ipsec_rcv_md5[]={	{osMD5Init, osMD5Update, osMD5Final, AHMD596_ALEN}};#endif /* CONFIG_KLIPS_AUTH_HMAC_MD5 */#ifdef CONFIG_KLIPS_AUTH_HMAC_SHA1struct auth_alg ipsec_rcv_sha1[]={	{SHA1Init, SHA1Update, SHA1Final, AHSHA196_ALEN}};#endif /* CONFIG_KLIPS_AUTH_HMAC_MD5 *//* * decapsulate a single layer of the system * * the following things should be setup to enter this function. * * irs->stats  == stats structure (or NULL) * irs->ipp    = IP header. * irs->len    = total length of packet * skb->nh.iph = ipp; * skb->h.raw  = start of payload * irs->ipsp   = NULL. * irs->iphlen = N/A = is recalculated. * irs->ilen   = 0; * irs->authlen = 0; * irs->authfuncs = NULL; * irs->skb    = the skb; * * proto_funcs should be from ipsec_esp.c, ipsec_ah.c or ipsec_ipcomp.c. * */enum ipsec_rcv_valueipsec_rcv_decap_once(struct ipsec_rcv_state *irs		     , struct xform_functions *proto_funcs){	int iphlen;	__u8 proto;	struct in_addr ipsaddr;	struct in_addr ipdaddr;	int replay = 0;	/* replay value in AH or ESP packet */	struct ipsec_sa* ipsnext = NULL;	/* next SA towards inside of packet */	struct ipsec_sa *newipsp;	struct iphdr *ipp;	struct sk_buff *skb;	struct ipsec_alg_auth *ixt_a=NULL;	skb = irs->skb;	irs->len = skb->len;	ipp = irs->ipp;	proto = ipp->protocol;	ipsaddr.s_addr = ipp->saddr;	addrtoa(ipsaddr, 0, irs->ipsaddr_txt, sizeof(irs->ipsaddr_txt));	ipdaddr.s_addr = ipp->daddr;	addrtoa(ipdaddr, 0, irs->ipdaddr_txt, sizeof(irs->ipdaddr_txt));	iphlen = ipp->ihl << 2;	irs->iphlen=iphlen;	ipp->check = 0;			/* we know the sum is good */		KLIPS_PRINT(debug_rcv,		    "klips_debug:ipsec_rcv_decap_once: "		    "decap (%d) from %s -> %s\n",		    proto, irs->ipsaddr_txt, irs->ipdaddr_txt);	/*	 * Find tunnel control block and (indirectly) call the	 * appropriate tranform routine. The resulting sk_buf	 * is a valid IP packet ready to go through input processing.	 */	irs->said.dst.u.v4.sin_addr.s_addr = ipp->daddr;	irs->said.dst.u.v4.sin_family = AF_INET;	/* note: rcv_checks set up the said.spi value, if appropriate */	if(proto_funcs->rcv_checks) {		enum ipsec_rcv_value retval =		  (*proto_funcs->rcv_checks)(irs, skb);		if(retval < 0) {			return retval;		}	}	irs->said.proto = proto;	irs->sa_len = satot(&irs->said, 0, irs->sa, sizeof(irs->sa));	if(irs->sa_len == 0) {		strcpy(irs->sa, "(error)");	}	newipsp = ipsec_sa_getbyid(&irs->said);	if (newipsp == NULL) {		KLIPS_PRINT(debug_rcv,			    "klips_debug:ipsec_rcv: "			    "no ipsec_sa for SA:%s: incoming packet with no SA dropped\n",			    irs->sa_len ? irs->sa : " (error)");		if(irs->stats) {			irs->stats->rx_dropped++;		}		return IPSEC_RCV_SAIDNOTFOUND;	}	/* MCR - XXX this is bizarre. ipsec_sa_getbyid returned it, having	 * incremented the refcount, why in the world would we decrement it	 * here? */	/* ipsec_sa_put(irs->ipsp);*/ /* incomplete */	/* If it is in larval state, drop the packet, we cannot process yet. */	if(newipsp->ips_state == SADB_SASTATE_LARVAL) {		KLIPS_PRINT(debug_rcv,			    "klips_debug:ipsec_rcv: "			    "ipsec_sa in larval state, cannot be used yet, dropping packet.\n");		if(irs->stats) {			irs->stats->rx_dropped++;		}		ipsec_sa_put(newipsp);		return IPSEC_RCV_SAIDNOTLIVE;	}	if(newipsp->ips_state == SADB_SASTATE_DEAD) {		KLIPS_PRINT(debug_rcv,			    "klips_debug:ipsec_rcv: "			    "ipsec_sa in dead state, cannot be used any more, dropping packet.\n");		if(irs->stats) {			irs->stats->rx_dropped++;		}		ipsec_sa_put(newipsp);		return IPSEC_RCV_SAIDNOTLIVE;	}	if(sysctl_ipsec_inbound_policy_check) {		if(irs->ipp->saddr != ((struct sockaddr_in*)(newipsp->ips_addr_s))->sin_addr.s_addr) {			KLIPS_PRINT(debug_rcv,				    "klips_debug:ipsec_rcv: "				    "SA:%s, src=%s of pkt does not agree with expected SA source address policy.\n",				    irs->sa_len ? irs->sa : " (error)",				    irs->ipsaddr_txt);			if(irs->stats) {				irs->stats->rx_dropped++;			}			ipsec_sa_put(newipsp);			return IPSEC_RCV_FAILEDINBOUND;		}		KLIPS_PRINT(debug_rcv,			    "klips_debug:ipsec_rcv: "			    "SA:%s, src=%s of pkt agrees with expected SA source address policy.\n",			    irs->sa_len ? irs->sa : " (error)",			    irs->ipsaddr_txt);		/*		 * at this point, we have looked up a new SA, and we want to make sure that if this		 * isn't the first SA in the list, that the previous SA actually points at this one.		 */		if(irs->ipsp) {			if(irs->ipsp->ips_inext != newipsp) {				KLIPS_PRINT(debug_rcv,					    "klips_debug:ipsec_rcv: "					    "unexpected SA:%s: does not agree with ips->inext policy, dropped\n",					    irs->sa_len ? irs->sa : " (error)");				if(irs->stats) {					irs->stats->rx_dropped++;				}				ipsec_sa_put(newipsp);				return IPSEC_RCV_FAILEDINBOUND;			}			KLIPS_PRINT(debug_rcv,				    "klips_debug:ipsec_rcv: "				    "SA:%s grouping from previous SA is OK.\n",				    irs->sa_len ? irs->sa : " (error)");		} else {			KLIPS_PRINT(debug_rcv,				    "klips_debug:ipsec_rcv: "				    "SA:%s First SA in group.\n",				    irs->sa_len ? irs->sa : " (error)");		}#ifdef CONFIG_IPSEC_NAT_TRAVERSAL		if (proto == IPPROTO_ESP) {			KLIPS_PRINT(debug_rcv,				"klips_debug:ipsec_rcv: "				"natt_type=%u tdbp->ips_natt_type=%u : %s\n",				irs->natt_type, newipsp->ips_natt_type,				(irs->natt_type==newipsp->ips_natt_type)?"ok":"bad");			if (irs->natt_type != newipsp->ips_natt_type) {				KLIPS_PRINT(debug_rcv,					    "klips_debug:ipsec_rcv: "					    "SA:%s does not agree with expected NAT-T policy.\n",					    irs->sa_len ? irs->sa : " (error)");				if(irs->stats) {					irs->stats->rx_dropped++;				}				ipsec_sa_put(newipsp);				return IPSEC_RCV_FAILEDINBOUND;			}		}#endif		 	}	/* okay, SA checks out, so free any previous SA, and record a new one*/	if(irs->ipsp) {		ipsec_sa_put(irs->ipsp);	}	irs->ipsp=newipsp;	/* note that the outer code will free the irs->ipsp	   if there is an error */	/* now check the lifetimes */	if(ipsec_lifetime_check(&irs->ipsp->ips_life.ipl_bytes,   "bytes",				irs->sa, ipsec_life_countbased, ipsec_incoming,				irs->ipsp) == ipsec_life_harddied ||	   ipsec_lifetime_check(&irs->ipsp->ips_life.ipl_addtime, "addtime",				irs->sa, ipsec_life_timebased,  ipsec_incoming,				irs->ipsp) == ipsec_life_harddied ||	   ipsec_lifetime_check(&irs->ipsp->ips_life.ipl_addtime, "usetime",				irs->sa, ipsec_life_timebased,  ipsec_incoming,				irs->ipsp) == ipsec_life_harddied ||	   ipsec_lifetime_check(&irs->ipsp->ips_life.ipl_packets, "packets",				irs->sa, ipsec_life_countbased, ipsec_incoming,				irs->ipsp) == ipsec_life_harddied) {		ipsec_sa_delchain(irs->ipsp);		if(irs->stats) {			irs->stats->rx_dropped++;		}				KLIPS_PRINT(debug_rcv,			    "klips_debug:ipsec_rcv_decap_once: "			    "decap (%d) failed lifetime check\n",			    proto);		return IPSEC_RCV_LIFETIMEFAILED;	}#if 0	/*	 * This is removed for some reasons:	 *   1) it needs to happen *after* authentication.	 *   2) do we really care, if it authenticates, if it came	 *      from the wrong location?         *   3) the NAT_KA messages in IKE will also get to pluto	 *      and it will figure out that stuff has moved.	 *   4) the 2.6 udp-esp encap function does not pass us	 *      the originating port number, and I can't tell	 *      if skb->sk is guaranteed to be valid here.	 *  2005-04-16: mcr@xelerance.com	 */#ifdef CONFIG_IPSEC_NAT_TRAVERSAL	/*	 *	 * XXX we should ONLY update pluto if the SA passes all checks,	 *     which we clearly do not now.	 */	if ((irs->natt_type) &&

⌨️ 快捷键说明

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