ipsec_tunnel.c

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

C
2,178
字号
						ixt_e->ixt_ivlen/8);				} else#endif /* CONFIG_IPSEC_ALG */				switch(tdbp->tdb_encalg) {#ifdef CONFIG_IPSEC_ENC_3DES				case ESP_3DES:					des_ede3_cbc_encrypt((des_cblock *)idat,							     (des_cblock *)idat,							     ilen,							     ((struct des_eks *)(tdbp->tdb_key_e))[0].ks,							     ((struct des_eks *)(tdbp->tdb_key_e))[1].ks,							     ((struct des_eks *)(tdbp->tdb_key_e))[2].ks,							     (des_cblock *)iv, 1);					break;#endif /* CONFIG_IPSEC_ENC_3DES */				default:					spin_unlock(&tdb_lock);					stats->tx_errors++;					goto cleanup;				}#ifdef CONFIG_IPSEC_ALG				if (!ixt_e)#endif /* CONFIG_IPSEC_ALG */								switch(tdbp->tdb_encalg) {#if defined(CONFIG_IPSEC_ENC_3DES)#ifdef CONFIG_IPSEC_ENC_3DES				case ESP_3DES:#endif /* CONFIG_IPSEC_ENC_3DES */					/* XXX update IV with the last 8 octets of the encryption */					((__u32*)(tdbp->tdb_iv))[0] =						((__u32 *)(idat))[(ilen >> 2) - 2];					((__u32*)(tdbp->tdb_iv))[1] =						((__u32 *)(idat))[(ilen >> 2) - 1];					break;#endif /* defined(CONFIG_IPSEC_ENC_3DES) */				default:					spin_unlock(&tdb_lock);					stats->tx_errors++;					goto cleanup;				}#ifdef CONFIG_IPSEC_ALG				if (ixt_a) {					ipsec_alg_sa_esp_hash(tdbp,					(caddr_t)espp, len - iphlen - authlen,					&(dat[len - authlen]), authlen);				} else#endif /* CONFIG_IPSEC_ALG */								switch(tdbp->tdb_authalg) {#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5				case AH_MD5:					dmp("espp", (char*)espp, len - iphlen - authlen);					tctx.md5 = ((struct md5_ctx*)(tdbp->tdb_key_a))->ictx;					dmp("ictx", (char*)&tctx.md5, sizeof(tctx.md5));					MD5Update(&tctx.md5, (caddr_t)espp, len - iphlen - authlen);					dmp("ictx+dat", (char*)&tctx.md5, sizeof(tctx.md5));					MD5Final(hash, &tctx.md5);					dmp("ictx hash", (char*)&hash, sizeof(hash));					tctx.md5 = ((struct md5_ctx*)(tdbp->tdb_key_a))->octx;					dmp("octx", (char*)&tctx.md5, sizeof(tctx.md5));					MD5Update(&tctx.md5, hash, AHMD596_ALEN);					dmp("octx+hash", (char*)&tctx.md5, sizeof(tctx.md5));					MD5Final(hash, &tctx.md5);					dmp("octx hash", (char*)&hash, sizeof(hash));					memcpy(&(dat[len - authlen]), hash, authlen);					/* paranoid */					memset((caddr_t)&tctx.md5, 0, sizeof(tctx.md5));					memset((caddr_t)hash, 0, sizeof(*hash));					break;#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1				case AH_SHA:					tctx.sha1 = ((struct sha1_ctx*)(tdbp->tdb_key_a))->ictx;					SHA1Update(&tctx.sha1, (caddr_t)espp, len - iphlen - authlen);					SHA1Final(hash, &tctx.sha1);					tctx.sha1 = ((struct sha1_ctx*)(tdbp->tdb_key_a))->octx;					SHA1Update(&tctx.sha1, hash, AHSHA196_ALEN);					SHA1Final(hash, &tctx.sha1);					memcpy(&(dat[len - authlen]), hash, authlen);										/* paranoid */					memset((caddr_t)&tctx.sha1, 0, sizeof(tctx.sha1));					memset((caddr_t)hash, 0, sizeof(*hash));					break;#endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */				case AH_NONE:					break;				default:					spin_unlock(&tdb_lock);					stats->tx_errors++;					goto cleanup;				}#ifdef NET_21				skb->h.raw = (unsigned char*)espp;#endif /* NET_21 */				break;#endif /* !CONFIG_IPSEC_ESP */#ifdef CONFIG_IPSEC_AH			case IPPROTO_AH:				ahp = (struct ah *)(dat + iphlen);				ahp->ah_spi = tdbp->tdb_said.spi;				ahp->ah_rpl = htonl(++(tdbp->tdb_replaywin_lastseq));				ahp->ah_rv = 0;				ahp->ah_nh = iph->protocol;				ahp->ah_hl = (headroom >> 2) - sizeof(__u64)/sizeof(__u32);				iph->protocol = IPPROTO_AH;				dmp("ahp", (char*)ahp, sizeof(*ahp));								ipo = *iph;				ipo.tos = 0;				ipo.frag_off = 0;				ipo.ttl = 0;				ipo.check = 0;				dmp("ipo", (char*)&ipo, sizeof(ipo));								switch(tdbp->tdb_authalg) {#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5				case AH_MD5:					tctx.md5 = ((struct md5_ctx*)(tdbp->tdb_key_a))->ictx;					dmp("ictx", (char*)&tctx.md5, sizeof(tctx.md5));					MD5Update(&tctx.md5, (unsigned char *)&ipo, sizeof (struct iphdr));					dmp("ictx+ipo", (char*)&tctx.md5, sizeof(tctx.md5));					MD5Update(&tctx.md5, (unsigned char *)ahp, headroom - sizeof(ahp->ah_data));					dmp("ictx+ahp", (char*)&tctx.md5, sizeof(tctx.md5));					MD5Update(&tctx.md5, (unsigned char *)zeroes, AHHMAC_HASHLEN);					dmp("ictx+zeroes", (char*)&tctx.md5, sizeof(tctx.md5));					MD5Update(&tctx.md5,  dat + iphlen + headroom, len - iphlen - headroom);					dmp("ictx+dat", (char*)&tctx.md5, sizeof(tctx.md5));					MD5Final(hash, &tctx.md5);					dmp("ictx hash", (char*)&hash, sizeof(hash));					tctx.md5 = ((struct md5_ctx*)(tdbp->tdb_key_a))->octx;					dmp("octx", (char*)&tctx.md5, sizeof(tctx.md5));					MD5Update(&tctx.md5, hash, AHMD596_ALEN);					dmp("octx+hash", (char*)&tctx.md5, sizeof(tctx.md5));					MD5Final(hash, &tctx.md5);					dmp("octx hash", (char*)&hash, sizeof(hash));										memcpy(ahp->ah_data, hash, AHHMAC_HASHLEN);										/* paranoid */					memset((caddr_t)&tctx.md5, 0, sizeof(tctx.md5));					memset((caddr_t)hash, 0, sizeof(hash));					break;#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1				case AH_SHA:					tctx.sha1 = ((struct sha1_ctx*)(tdbp->tdb_key_a))->ictx;					SHA1Update(&tctx.sha1, (unsigned char *)&ipo, sizeof (struct iphdr));					SHA1Update(&tctx.sha1, (unsigned char *)ahp, headroom - sizeof(ahp->ah_data));					SHA1Update(&tctx.sha1, (unsigned char *)zeroes, AHHMAC_HASHLEN);					SHA1Update(&tctx.sha1,  dat + iphlen + headroom, len - iphlen - headroom);					SHA1Final(hash, &tctx.sha1);					tctx.sha1 = ((struct sha1_ctx*)(tdbp->tdb_key_a))->octx;					SHA1Update(&tctx.sha1, hash, AHSHA196_ALEN);					SHA1Final(hash, &tctx.sha1);										memcpy(ahp->ah_data, hash, AHHMAC_HASHLEN);										/* paranoid */					memset((caddr_t)&tctx.sha1, 0, sizeof(tctx.sha1));					memset((caddr_t)hash, 0, sizeof(hash));					break;#endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */				default:					spin_unlock(&tdb_lock);					stats->tx_errors++;					goto cleanup;				}#ifdef NET_21				skb->h.raw = (unsigned char*)ahp;#endif /* NET_21 */				break;#endif /* CONFIG_IPSEC_AH */#ifdef CONFIG_IPSEC_IPIP			case IPPROTO_IPIP:				iph->version  = 4;				switch(sysctl_ipsec_tos) {				case 0:#ifdef NET_21					iph->tos = skb->nh.iph->tos;#else /* NET_21 */					iph->tos = skb->ip_hdr->tos;#endif /* NET_21 */					break;				case 1:					iph->tos = 0;					break;				default:				}#ifdef NET_21#ifdef NETDEV_23				iph->ttl      = sysctl_ip_default_ttl;#else /* NETDEV_23 */				iph->ttl      = ip_statistics.IpDefaultTTL;#endif /* NETDEV_23 */#else /* NET_21 */				iph->ttl      = 64; /* ip_statistics.IpDefaultTTL; */#endif /* NET_21 */				iph->frag_off = 0;				iph->saddr    = ((struct sockaddr_in*)(tdbp->tdb_addr_s))->sin_addr.s_addr;				iph->daddr    = ((struct sockaddr_in*)(tdbp->tdb_addr_d))->sin_addr.s_addr;				iph->protocol = IPPROTO_IPIP;				iph->ihl      = sizeof(struct iphdr) >> 2 /* 5 */;#ifdef IP_SELECT_IDENT				/* XXX use of skb->dst below is a questionable				   substitute for &rt->u.dst which is only				   available later-on */#ifdef IP_SELECT_IDENT_NEW				ip_select_ident(iph, skb->dst, NULL);#else /* IP_SELECT_IDENT_NEW */                                ip_select_ident(iph, skb->dst);#endif /* IP_SELECT_IDENT_NEW */#else /* IP_SELECT_IDENT */				iph->id       = htons(ip_id_count++);   /* Race condition here? */#endif /* IP_SELECT_IDENT */				newdst = (__u32)iph->daddr;				newsrc = (__u32)iph->saddr;		#ifdef NET_21				skb->h.ipiph = skb->nh.iph;#endif /* NET_21 */				break;#endif /* !CONFIG_IPSEC_IPIP */#ifdef CONFIG_IPSEC_IPCOMP			case IPPROTO_COMP:				{					unsigned int flags = 0;#ifdef CONFIG_IPSEC_DEBUG					unsigned int old_tot_len = ntohs(iph->tot_len);#endif /* CONFIG_IPSEC_DEBUG */					tdbp->tdb_comp_ratio_dbytes += ntohs(iph->tot_len);					skb = skb_compress(skb, tdbp, &flags);#ifdef NET_21					iph = skb->nh.iph;#else /* NET_21 */					iph = skb->ip_hdr;#endif /* NET_21 */					tdbp->tdb_comp_ratio_cbytes += ntohs(iph->tot_len);#ifdef CONFIG_IPSEC_DEBUG					if (debug_tunnel & DB_TN_CROUT)					{						if (old_tot_len > ntohs(iph->tot_len))							KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,								    "klips_debug:ipsec_tunnel_start_xmit: "								    "packet shrunk from %d to %d bytes after compression, cpi=%04x (should be from spi=%08x, spi&0xffff=%04x.\n",								    old_tot_len, ntohs(iph->tot_len),								    ntohs(((struct ipcomphdr*)(((char*)iph) + ((iph->ihl) << 2)))->ipcomp_cpi),								    ntohl(tdbp->tdb_said.spi),								    (__u16)(ntohl(tdbp->tdb_said.spi) & 0x0000ffff));						else							KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,								    "klips_debug:ipsec_tunnel_start_xmit: "								    "packet did not compress (flags = %d).\n",								    flags);					}#endif /* CONFIG_IPSEC_DEBUG */				}				break;#endif /* CONFIG_IPSEC_IPCOMP */			default:				spin_unlock(&tdb_lock);				stats->tx_errors++;				goto cleanup;			}			#ifdef NET_21			skb->nh.raw = skb->data;#else /* NET_21 */			skb->ip_hdr = skb->h.iph = (struct iphdr *) skb->data;#endif /* NET_21 */			iph->check = 0;			iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);						KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,				    "klips_debug:ipsec_tunnel_start_xmit: "				    "after <%s%s%s>, SA:%s:\n",				    IPS_XFORM_NAME(tdbp),				    sa_len ? sa : " (error)");			KLIPS_IP_PRINT(debug_tunnel & DB_TN_XMIT, iph); 						tdbp->ips_life.ipl_bytes.ipl_count += len;			tdbp->ips_life.ipl_bytes.ipl_last = len;			if(!tdbp->ips_life.ipl_usetime.ipl_count) {				tdbp->ips_life.ipl_usetime.ipl_count = jiffies / HZ;			}			tdbp->ips_life.ipl_usetime.ipl_last = jiffies / HZ;			tdbp->ips_life.ipl_packets.ipl_count++; 			tdbprev = tdbp;			tdbp = tdbp->ips_onext;#ifdef CONFIG_IPSEC_ALG			ixt_e = NULL;	/* invalidate ipsec_alg */			ixt_a = NULL;#endif /* CONFIG_IPSEC_ALG */					}		/* end encapsulation loop here XXX */		spin_unlock(&tdb_lock);		matcher.sen_ip_src.s_addr = iph->saddr;		matcher.sen_ip_dst.s_addr = iph->daddr;		matcher.sen_proto = iph->protocol;		extract_ports(iph, &matcher);				spin_lock(&eroute_lock);		er = ipsec_findroute(&matcher);		if(er) {			outgoing_said = er->er_said;			eroute_pid = er->er_pid;			er->er_count++;			er->er_lasttime = jiffies/HZ;		}		spin_unlock(&eroute_lock);		KLIPS_PRINT((debug_tunnel & DB_TN_XMIT) &&			    /* ((orgdst != newdst) || (orgsrc != newsrc)) */			    (orgedst != outgoing_said.dst.s_addr) &&			    outgoing_said.dst.s_addr &&			    er,			    "klips_debug:ipsec_tunnel_start_xmit: "			    "We are recursing here.\n");	} while(/*((orgdst != newdst) || (orgsrc != newsrc))*/		(orgedst != outgoing_said.dst.s_addr) &&		outgoing_said.dst.s_addr &&		er);		KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,		    "klips_debug:ipsec_tunnel_start_xmit: "		    "After recursive xforms -- head,tailroom: %d,%d\n",		    skb_headroom(skb), skb_tailroom(skb));	if(saved_header) {		if(skb_headroom(skb) < hard_header_len) {			printk(KERN_WARNING			       "klips_error:ipsec_tunnel_start_xmit: "			       "tried to skb_push hhlen=%d, %d available.  This should never happen, please report.\n",			       hard_header_len, skb_headroom(skb));			stats->tx_errors++;			goto cleanup;		}		skb_push(skb, hard_header_len);		for (i = 0; i < hard_header_len; i++) {			skb->data[i] = saved_header[i];		}	}#ifdef CONFIG_IPSEC_NAT_TRAVERSAL	if (natt_type && natt_head) {		struct iphdr *ipp = skb->nh.iph;		struct udphdr *udp;		KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,			"klips_debug:ipsec_tunnel_start_xmit: "			"encapsuling packet into UDP (NAT-Traversal)\n");		iphlen = ipp->ihl << 2;		ipp->tot_len =			htons(ntohs(ipp->tot_len) + natt_head);		if(skb_tailroom(skb) < natt_head) {			printk(KERN_WARNING "klips_error:ipsec_tunnel_start_xmit: "				"tried to skb_put %d, %d available. "				"This should never happen, please report.\n",				natt_head,				skb_tailroom(skb));			stats->tx_errors++;			goto cleanup;		}		skb_put(skb, natt_head);		udp = (struct udphdr *)((char *)ipp + iphlen);		/* move ESP hdr after UDP hdr */		memmove((void *)((char *)udp + natt_head),			(void *)(udp),			ntohs(ipp->tot_len) - iphlen - natt_head);		/* clear UDP & Non-IKE Markers (if any) */		memset(udp, 0, natt_head);		/* fill UDP with usefull informations ;-) */		udp->source = htons(natt_sport);		udp->dest = htons(natt_dport);		udp->len = htons(ntohs(ipp->tot_len) - iphlen);		/* set protocol */		ipp->protocol = IPPROTO_UDP;		/* fix IP checksum */		ipp->check = 0;		ipp->check = ip_fast_csum((unsigned char *)ipp, ipp->ihl);	}#endif bypass:	KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,		    "klips_debug:ipsec_tunnel_start_xmit: "		    "With hard_header, final head,tailroom: %d,%d\n",		    skb_headroom(skb), skb_tailroom(skb));#ifdef NET_21	/* 2.2 and 2.4 kernels */	/* new route/dst cache code from James Morris */	skb->dev = physdev;	/*skb_orphan(skb);*/	if((error = ip_route_output(&rt,				    skb->nh.iph->daddr,				    pass ? 0 : skb->nh.iph->saddr,				    RT_TOS(skb->nh.iph->tos),				    physdev->iflink /* rgb: should this be 0? */))) {		stats->tx_errors++;		KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,			    "klips_debug:ipsec_tunnel_start_xmit: "			    "ip_route_output failed with error code %d, rt->u.dst.dev=%s, dropped\n",			    error,			    rt->u.dst.dev->name);		goto cleanup;	}	if(dev == rt->u.dst.dev) {		ip_rt_put(rt);		/* This is recursion, drop it. */		stats->tx_errors++;		KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,			    "klips_debug:ipsec_tunnel_start_xmit: "			    "suspect recursion, dev=rt->u.dst.dev=%s, dropped\n", dev->name);		goto cleanup;	}	dst_release(skb->dst);	skb->dst = &rt->u.dst;	stats->tx_bytes += skb->len;	if(skb->len < skb->nh.raw - skb->data) {		stats->tx_errors++;		printk(KERN_WARNING		       "klips_error:ipsec_tunnel_start_xmit: "		       "tried to __skb_pull nh-data=%d, %d available.  This should never happen, please report.\n",		       skb->nh.raw - skb->data, skb->len);		goto c

⌨️ 快捷键说明

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