ipsec_rcv.c

来自「FREESWAN VPN源代码包」· C语言 代码 · 共 2,240 行 · 第 1/5 页

C
2,240
字号
			goto rcvleave;		}		memmove(skb->data + natt_len, skb->data, iphlen);		skb_pull(skb, natt_len);		/* update nh.iph */		ipp = skb->nh.iph = (struct iphdr *)skb->data;		/* modify protocol */		ipp->protocol = IPPROTO_ESP;		skb->sk = NULL;		KLIPS_IP_PRINT(debug_rcv, skb->nh.iph);	}#endif	KLIPS_PRINT(debug_rcv, 		    "klips_debug:ipsec_rcv: "		    "<<< Info -- ");	KLIPS_PRINTMORE(debug_rcv && skb->dev, "skb->dev=%s ",		    skb->dev->name ? skb->dev->name : "NULL");	KLIPS_PRINTMORE(debug_rcv && dev, "dev=%s ",		    dev->name ? dev->name : "NULL");	KLIPS_PRINTMORE(debug_rcv, "\n");	KLIPS_PRINT(debug_rcv && !(skb->dev && dev && (skb->dev == dev)),		    "klips_debug:ipsec_rcv: "		    "Informational -- **if this happens, find out why** skb->dev:%s is not equal to dev:%s\n",		    skb->dev ? (skb->dev->name ? skb->dev->name : "NULL") : "NULL",		    dev ? (dev->name ? dev->name : "NULL") : "NULL");	protoc = ipp->protocol;#ifndef NET_21	if((!protocol) || (protocol->protocol != protoc)) {		KLIPS_PRINT(debug_rcv & DB_RX_TDB,			    "klips_debug:ipsec_rcv: "			    "protocol arg is NULL or unequal to the packet contents, this is odd, using value in packet.\n");	}#endif /* !NET_21 */	if( (protoc != IPPROTO_AH) &&#ifdef CONFIG_IPSEC_IPCOMP_disabled_until_we_register_IPCOMP_HANDLER	    (protoc != IPPROTO_COMP) &&#endif /* CONFIG_IPSEC_IPCOMP */	    (protoc != IPPROTO_ESP) ) {		KLIPS_PRINT(debug_rcv & DB_RX_TDB,			    "klips_debug:ipsec_rcv: Why the hell is someone "			    "passing me a non-ipsec protocol = %d packet? -- dropped.\n",			    protoc);		goto rcvleave;	}	if(skb->dev) {		for(i = 0; i < IPSEC_NUM_IF; i++) {			sprintf(name, "ipsec%d", i);			if(!strcmp(name, skb->dev->name)) {				prv = (struct ipsecpriv *)(skb->dev->priv);				if(prv) {					stats = (struct net_device_stats *) &(prv->mystats);				}				ipsecdev = skb->dev;				KLIPS_PRINT(debug_rcv,					    "klips_debug:ipsec_rcv: "					    "Info -- pkt already proc'ed a group of ipsec headers, processing next group of ipsec headers.\n");				break;			}			if((ipsecdev = ipsec_dev_get(name)) == NULL) {				KLIPS_PRINT(debug_rcv,					    "klips_error:ipsec_rcv: "					    "device %s does not exist\n",					    name);			}			prv = ipsecdev ? (struct ipsecpriv *)(ipsecdev->priv) : NULL;			prvdev = prv ? (struct device *)(prv->dev) : NULL;			#if 0			KLIPS_PRINT(debug_rcv && prvdev, 				    "klips_debug:ipsec_rcv: "				    "physical device for device %s is %s\n",				    name,				    prvdev->name);#endif			if(prvdev && skb->dev &&			   !strcmp(prvdev->name, skb->dev->name)) {				stats = prv ? ((struct net_device_stats *) &(prv->mystats)) : NULL;				skb->dev = ipsecdev;				KLIPS_PRINT(debug_rcv && prvdev, 					    "klips_debug:ipsec_rcv: "					    "assigning packet ownership to virtual device %s from physical device %s.\n",					    name, prvdev->name);				if(stats) {					stats->rx_packets++;				}				break;			}		}	} else {		KLIPS_PRINT(debug_rcv, 			    "klips_debug:ipsec_rcv: "			    "device supplied with skb is NULL\n");	}				if(!stats) {		ipsecdev = NULL;	}	KLIPS_PRINT((debug_rcv && !stats),		    "klips_error:ipsec_rcv: "		    "packet received from physical I/F (%s) not connected to ipsec I/F.  Cannot record stats.  May not have SA for decoding.  Is IPSEC traffic expected on this I/F?  Check routing.\n",		    skb->dev ? (skb->dev->name ? skb->dev->name : "NULL") : "NULL");	KLIPS_IP_PRINT(debug_rcv, ipp);	/* begin decapsulating loop here */	do {		authlen = 0;#ifdef CONFIG_IPSEC_ESP		espp = NULL;		esphlen = 0;#endif /* !CONFIG_IPSEC_ESP */#ifdef CONFIG_IPSEC_AH		ahp = NULL;		ahhlen = 0;#endif /* CONFIG_IPSEC_AH */#ifdef CONFIG_IPSEC_IPCOMP		compp = NULL;#endif /* CONFIG_IPSEC_IPCOMP */		len = skb->len;		dat = skb->data;		ipp = (struct iphdr *)skb->data;		proto = ipp->protocol;		ipaddr.s_addr = ipp->saddr;		addrtoa(ipaddr, 0, ipaddr_txt, sizeof(ipaddr_txt));				iphlen = ipp->ihl << 2;		ipp->check = 0;			/* we know the sum is good */		#ifdef CONFIG_IPSEC_ESP		/* XXX this will need to be 8 for IPv6 */		if ((proto == IPPROTO_ESP) && ((len - iphlen) % 4)) {			printk("klips_error:ipsec_rcv: "			       "got packet with content length = %d from %s -- should be on 4 octet boundary, packet dropped\n",			       len - iphlen,			       ipaddr_txt);			if(stats) {				stats->rx_errors++;			}			goto rcvleave;		}#endif /* !CONFIG_IPSEC_ESP */				/*		 * 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.		 */				said.dst.s_addr = ipp->daddr;		switch(proto) {#ifdef CONFIG_IPSEC_ESP		case IPPROTO_ESP:			if(skb->len < (hard_header_len + sizeof(struct iphdr) + sizeof(struct esp))) {				KLIPS_PRINT(debug_rcv & DB_RX_INAU,					    "klips_debug:ipsec_rcv: "					    "runt esp packet of skb->len=%d received from %s, dropped.\n",					    skb->len,					    ipaddr_txt);				if(stats) {					stats->rx_errors++;				}				goto rcvleave;			}		       			espp = (struct esp *)(skb->data + iphlen);			said.spi = espp->esp_spi;			break;#endif /* !CONFIG_IPSEC_ESP */#ifdef CONFIG_IPSEC_AH		case IPPROTO_AH:			if((skb->len 			    < (hard_header_len + sizeof(struct iphdr) + sizeof(struct ah)))			   || (skb->len 			       < (hard_header_len + sizeof(struct iphdr) 				  + ((ahp = (struct ah *) (skb->data + iphlen))->ah_hl << 2)))) {				KLIPS_PRINT(debug_rcv & DB_RX_INAU,					    "klips_debug:ipsec_rcv: "					    "runt ah packet of skb->len=%d received from %s, dropped.\n",					    skb->len,					    ipaddr_txt);				if(stats) {					stats->rx_errors++;				}				goto rcvleave;			}		       			said.spi = ahp->ah_spi;			break;#endif /* CONFIG_IPSEC_AH */#ifdef CONFIG_IPSEC_IPCOMP		case IPPROTO_COMP:			if(skb->len < (hard_header_len + sizeof(struct iphdr) + sizeof(struct ipcomphdr))) {				KLIPS_PRINT(debug_rcv & DB_RX_INAU,					    "klips_debug:ipsec_rcv: "					    "runt comp packet of skb->len=%d received from %s, dropped.\n",					    skb->len,					    ipaddr_txt);				if(stats) {					stats->rx_errors++;				}				goto rcvleave;			}		       			compp = (struct ipcomphdr *)(skb->data + iphlen);			said.spi = htonl((__u32)ntohs(compp->ipcomp_cpi));			break;#endif /* CONFIG_IPSEC_IPCOMP */		default:			if(stats) {				stats->rx_errors++;			}			goto rcvleave;		}		said.proto = proto;		sa_len = satoa(said, 0, sa, SATOA_BUF);		if(sa_len == 0) {		  strcpy(sa, "(error)");		}		#ifdef CONFIG_IPSEC_AH		if(proto == IPPROTO_AH) {			ahhlen = (ahp->ah_hl << 2) +				((caddr_t)&(ahp->ah_rpl) - (caddr_t)ahp);			next_header = ahp->ah_nh;			if (ahhlen != sizeof(struct ah)) {				KLIPS_PRINT(debug_rcv & DB_RX_INAU,					    "klips_debug:ipsec_rcv: "					    "bad authenticator length %d, expected %d from %s.\n",					    ahhlen - ((caddr_t)(ahp->ah_data) - (caddr_t)ahp),					    AHHMAC_HASHLEN,					    ipaddr_txt);				if(stats) {					stats->rx_errors++;				}				goto rcvleave;			}					}#endif /* CONFIG_IPSEC_AH */				/*		  The spinlock is to prevent any other process from		  accessing or deleting the TDB hash table or any of the		  TDBs while we are using and updating them.		  		  This is not optimal, but was relatively straightforward		  at the time.  A better way to do it has been planned for		  more than a year, to lock the hash table and put reference		  counts on each TDB instead.  This is not likely to happen		  in KLIPS1 unless a volunteer contributes it, but will be		  designed into KLIPS2.		*/		if(tdbprev == NULL) {			spin_lock(&tdb_lock);		}		#ifdef CONFIG_IPSEC_IPCOMP		if (proto == IPPROTO_COMP) {			unsigned int flags = 0;			if (tdbp == NULL) {				spin_unlock(&tdb_lock);				KLIPS_PRINT(debug_rcv,					    "klips_debug:ipsec_rcv: "					    "Incoming packet with outer IPCOMP header SA:%s: not yet supported by KLIPS, dropped\n",					    sa_len ? sa : " (error)");				if(stats) {					stats->rx_dropped++;				}				goto rcvleave;			}			tdbprev = tdbp;			tdbp = tdbnext;			if(sysctl_ipsec_inbound_policy_check			   && ((tdbp == NULL)			       || (((ntohl(tdbp->tdb_said.spi) & 0x0000ffff)				    != ntohl(said.spi))				/* next line is a workaround for peer				   non-compliance with rfc2393 */				   && (tdbp->tdb_encalg != ntohl(said.spi)) 				       ))) {				char sa2[SATOA_BUF];				size_t sa_len2 = 0;				if(tdbp) {					sa_len2 = satoa(tdbp->tdb_said, 0, sa2, SATOA_BUF);				}				KLIPS_PRINT(debug_rcv,					    "klips_debug:ipsec_rcv: "					    "Incoming packet with SA(IPCA):%s does not match policy SA(IPCA):%s cpi=%04x cpi->spi=%08x spi=%08x, spi->cpi=%04x for SA grouping, dropped.\n",					    sa_len ? sa : " (error)",					    tdbp ? (sa_len2 ? sa2 : " (error)") : "NULL",					    ntohs(compp->ipcomp_cpi),					    (__u32)ntohl(said.spi),					    tdbp ? (__u32)ntohl((tdbp->tdb_said.spi)) : 0,					    tdbp ? (__u16)(ntohl(tdbp->tdb_said.spi) & 0x0000ffff) : 0);				spin_unlock(&tdb_lock);				if(stats) {					stats->rx_dropped++;				}				goto rcvleave;			}			if (tdbp) {				tdbp->tdb_comp_ratio_cbytes += ntohs(ipp->tot_len);				tdbnext = tdbp->tdb_inext;			}			next_header = compp->ipcomp_nh;			skb = skb_decompress(skb, tdbp, &flags);			if (!skb || flags) {				spin_unlock(&tdb_lock);				KLIPS_PRINT(debug_rcv,					    "klips_debug:ipsec_rcv: "					    "skb_decompress() returned error flags=%x, dropped.\n",					    flags);				if (stats) {				    if (flags)					stats->rx_errors++;				    else					stats->rx_dropped++;				}				goto rcvleave;			}#ifdef NET_21			ipp = skb->nh.iph;#else /* NET_21 */			ipp = skb->ip_hdr;#endif /* NET_21 */			if (tdbp) {				tdbp->tdb_comp_ratio_dbytes += ntohs(ipp->tot_len);			}			KLIPS_PRINT(debug_rcv,				    "klips_debug:ipsec_rcv: "				    "packet decompressed SA(IPCA):%s cpi->spi=%08x spi=%08x, spi->cpi=%04x, nh=%d.\n",				    sa_len ? sa : " (error)",				    (__u32)ntohl(said.spi),				    tdbp ? (__u32)ntohl((tdbp->tdb_said.spi)) : 0,				    tdbp ? (__u16)(ntohl(tdbp->tdb_said.spi) & 0x0000ffff) : 0,				    next_header);			KLIPS_IP_PRINT(debug_rcv & DB_RX_PKTRX, ipp);			continue;			/* Skip rest of stuff and decapsulate next inner			   packet, if any */		}#endif /* CONFIG_IPSEC_IPCOMP */				tdbp = ipsec_sa_getbyid(&said);		if (tdbp == NULL) {			spin_unlock(&tdb_lock);			KLIPS_PRINT(debug_rcv,				    "klips_debug:ipsec_rcv: "				    "no Tunnel Descriptor Block for SA:%s: incoming packet with no SA dropped\n",				    sa_len ? sa : " (error)");			if(stats) {				stats->rx_dropped++;			}			goto rcvleave;		}#ifdef CONFIG_IPSEC_NAT_TRAVERSAL		if ((natt_type) &&			( (ipp->saddr != (((struct sockaddr_in*)(tdbp->tdb_addr_s))->sin_addr.s_addr)) ||			  (natt_sport != tdbp->ips_natt_sport)			)) {			struct sockaddr sipaddr;			/** Advertise NAT-T addr change to pluto **/			sipaddr.sa_family = AF_INET;			((struct sockaddr_in*)&sipaddr)->sin_addr.s_addr = ipp->saddr;			((struct sockaddr_in*)&sipaddr)->sin_port = htons(natt_sport);			pfkey_nat_t_new_mapping(tdbp, &sipaddr, natt_sport);			/**			 * Then allow or block packet depending on			 * sysctl_ipsec_inbound_policy_check.			 *			 * In all cases, pluto will update SA if new mapping is			 * accepted.			 */			if (sysctl_ipsec_inbound_policy_check) {				spin_unlock(&tdb_lock);				ipaddr.s_addr = ipp->saddr;				addrtoa(ipaddr, 0, ipaddr_txt, sizeof(ipaddr_txt));				KLIPS_PRINT(debug_rcv,					"klips_debug:ipsec_rcv: "					"SA:%s, src=%s:%u of pkt does not agree with expected "					"SA source address policy (pluto has been informed).\n",					sa_len ? sa : " (error)",					ipaddr_txt, natt_sport);				if(stats) {					stats->rx_dropped++;				}				goto rcvleave;			}		}#endif		if(sysctl_ipsec_inbound_policy_check) {			if(ipp->saddr != ((struct sockaddr_in*)(tdbp->tdb_addr_s))->sin_addr.s_addr) {				spin_unlock(&tdb_lock);				ipaddr.s_addr = ipp->saddr;				addrtoa(ipaddr, 0, ipaddr_txt, sizeof(ipaddr_txt));				KLIPS_PRINT(debug_rcv,					    "klips_debug:ipsec_rcv: "					    "SA:%s, src=%s of pkt does not agree with expected SA source address policy.\n",					    sa_len ? sa : " (error)",					    ipaddr_txt);				if(stats) {					stats->rx_dropped++;				}				goto rcvleave;			}			ipaddr.s_addr = ipp->saddr;			addrtoa(ipaddr, 0, ipaddr_txt, sizeof(ipaddr_txt));			KLIPS_PRINT(debug_rcv,				    "klips_debug:ipsec_rcv: "				    "SA:%s, src=%s of pkt agrees with expected SA source address policy.\n",				    sa_len ? sa : " (error)",				    ipaddr_txt);			if(tdbnext) {				if(tdbnext != tdbp) {					spin_unlock(&tdb_lock);					KLIPS_PRINT(debug_rcv,						    "klips_debug:ipsec_rcv: "						    "unexpected SA:%s: does not agree with tdb->inext policy, dropped\n",						    sa_len ? sa : " (error)");					if(stats) {						stats->rx_dropped++;					}					goto rcvleave;				}				KLIPS_PRINT(debug_rcv,					    "klips_debug:ipsec_rcv: "					    "SA:%s grouping from previous SA is OK.\n",

⌨️ 快捷键说明

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