📄 ipsec_tunnel.c
字号:
prv->mtu, physdev);#endif /* IPSEC_obey_DF */ } #ifdef MSS_HACK /* * If this is a transport mode TCP packet with * SYN set, determine an effective MSS based on * AH/ESP overheads determined above. */ if (iph->protocol == IPPROTO_TCP && outgoing_said.proto != IPPROTO_IPIP) { struct tcphdr *tcph = skb->h.th; if (tcph->syn && !tcph->ack) { if(!ipsec_adjust_mss(skb, tcph, prv->mtu)) { spin_unlock(&tdb_lock); printk(KERN_WARNING "klips_warning:ipsec_tunnel_start_xmit: " "ipsec_adjust_mss() failed\n"); stats->tx_errors++; goto cleanup; } } }#endif /* MSS_HACK */ if(!hard_header_stripped) { if((saved_header = kmalloc(hard_header_len, GFP_ATOMIC)) == NULL) { spin_unlock(&tdb_lock); printk(KERN_WARNING "klips_debug:ipsec_tunnel_start_xmit: " "Failed, tried to allocate %d bytes for temp hard_header.\n", hard_header_len); stats->tx_errors++; goto cleanup; } for (i = 0; i < hard_header_len; i++) { saved_header[i] = skb->data[i]; } if(skb->len < hard_header_len) { spin_unlock(&tdb_lock); printk(KERN_WARNING "klips_error:ipsec_tunnel_start_xmit: " "tried to skb_pull hhlen=%d, %d available. This should never happen, please report.\n", hard_header_len, (int)(skb->len)); stats->tx_errors++; goto cleanup; } //剥去硬件头,此时data指针指向IP头 skb_pull(skb, hard_header_len); hard_header_stripped = 1; /* iph = (struct iphdr *) (skb->data); */ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT, "klips_debug:ipsec_tunnel_start_xmit: " "head,tailroom: %d,%d after hard_header stripped.\n", skb_headroom(skb), skb_tailroom(skb)); KLIPS_IP_PRINT(debug_tunnel & DB_TN_CROUT, iph); } else { KLIPS_PRINT(debug_tunnel & DB_TN_CROUT, "klips_debug:ipsec_tunnel_start_xmit: " "hard header already stripped.\n"); } //此时hard_header_len=16,运算结果为16 //这是为增加两个IP头空间计算长度准备的 ll_headroom = (hard_header_len + 15) & ~15; if ((skb_headroom(skb) >= max_headroom + 2 * ll_headroom) && (skb_tailroom(skb) >= max_tailroom)#ifndef NET_21 && skb->free#endif /* !NET_21 */ ) { KLIPS_PRINT(debug_tunnel & DB_TN_CROUT, "klips_debug:ipsec_tunnel_start_xmit: " "data fits in existing skb\n"); } else { struct sk_buff* tskb = skb; if(!oskb) { oskb = skb; } //max_headroom+2*ll_headroom = 60 + 2*16 = 92 bytes //真正扩展skb的空间,使之头部增加长度为max_headroom+2*ll_headroom的空间 //此时头空间已经增加了相应的ipsec头和新、旧ip头空间了 //而尾部则增加长度为max_tailroom的空间 tskb = skb_copy_expand(skb, /* The reason for 2 * link layer length here still baffles me...RGB */ max_headroom + 2 * ll_headroom, max_tailroom, GFP_ATOMIC);#ifdef NET_21 if(tskb && skb->sk) { skb_set_owner_w(tskb, skb->sk); }#endif /* NET_21 */ if(!(skb == oskb) ) { dev_kfree_skb(skb, FREE_WRITE); } skb = tskb; if (!skb) { spin_unlock(&tdb_lock); printk(KERN_WARNING "klips_debug:ipsec_tunnel_start_xmit: " "Failed, tried to allocate %d head and %d tailroom\n", max_headroom, max_tailroom); stats->tx_errors++; goto cleanup; } KLIPS_PRINT(debug_tunnel & DB_TN_CROUT, "klips_debug:ipsec_tunnel_start_xmit: " "head,tailroom: %d,%d after allocation\n", skb_headroom(skb), skb_tailroom(skb)); } /* * Apply grouped transforms to packet */ while (tdbp) {#ifdef CONFIG_IPSEC_ESP struct esp *espp; __u32 iv[2]; unsigned char *idat, *pad; int authlen = 0, padlen = 0, i;#endif /* !CONFIG_IPSEC_ESP */#ifdef CONFIG_IPSEC_AH struct iphdr ipo; struct ah *ahp;#endif /* CONFIG_IPSEC_AH */#if defined(CONFIG_IPSEC_AUTH_HMAC_MD5) || defined(CONFIG_IPSEC_AUTH_HMAC_SHA1) union {#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5 MD5_CTX md5;#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1 SHA1_CTX sha1;#endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */ } tctx; __u8 hash[AH_AMAX];#endif /* defined(CONFIG_IPSEC_AUTH_HMAC_MD5) || defined(CONFIG_IPSEC_AUTH_HMAC_SHA1) */ int headroom = 0, tailroom = 0, ilen = 0, len = 0; unsigned char *dat; iphlen = iph->ihl << 2; pyldsz = ntohs(iph->tot_len) - iphlen; sa_len = satoa(tdbp->tdb_said, 0, sa, SATOA_BUF); KLIPS_PRINT(debug_tunnel & DB_TN_OXFS, "klips_debug:ipsec_tunnel_start_xmit: " "calling output for <%s%s%s>, SA:%s\n", IPS_XFORM_NAME(tdbp), sa_len ? sa : " (error)"); switch(tdbp->tdb_said.proto) {#ifdef CONFIG_IPSEC_AH case IPPROTO_AH: headroom += sizeof(struct ah); break;#endif /* CONFIG_IPSEC_AH */#ifdef CONFIG_IPSEC_ESP case IPPROTO_ESP: switch(tdbp->tdb_encalg) {#ifdef CONFIG_IPSEC_ENC_3DES case ESP_3DES: headroom += sizeof(struct esp); break;#endif /* CONFIG_IPSEC_ENC_3DES */ default: spin_unlock(&tdb_lock); stats->tx_errors++; goto cleanup; } switch(tdbp->tdb_authalg) {#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5 case AH_MD5: authlen = AHHMAC_HASHLEN; break;#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1 case AH_SHA: authlen = AHHMAC_HASHLEN; break;#endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */ case AH_NONE: break; default: spin_unlock(&tdb_lock); stats->tx_errors++; goto cleanup; } tailroom += ((8 - ((pyldsz + 2 * sizeof(unsigned char)) % 8)) % 8) + 2; tailroom += authlen; break;#endif /* !CONFIG_IPSEC_ESP */#ifdef CONFIG_IPSEC_IPIP case IPPROTO_IPIP: headroom += sizeof(struct iphdr); break;#endif /* !CONFIG_IPSEC_IPIP */#ifdef CONFIG_IPSEC_IPCOMP case IPPROTO_COMP: break;#endif /* CONFIG_IPSEC_IPCOMP */ default: spin_unlock(&tdb_lock); stats->tx_errors++; goto cleanup; } KLIPS_PRINT(debug_tunnel & DB_TN_CROUT, "klips_debug:ipsec_tunnel_start_xmit: " "pushing %d bytes, putting %d, proto %d.\n", headroom, tailroom, tdbp->tdb_said.proto); if(skb_headroom(skb) < headroom) { spin_unlock(&tdb_lock); printk(KERN_WARNING "klips_error:ipsec_tunnel_start_xmit: " "tried to skb_push headroom=%d, %d available. This should never happen, please report.\n", headroom, skb_headroom(skb)); stats->tx_errors++; goto cleanup; } //此前的data域已经包含了旧ip头 //添加ipsec头空间或tunnel的IPIP头空间 dat = skb_push(skb, headroom); ilen = skb->len - tailroom; //该长度为待处理(加密或认证)的数据的长度 if(skb_tailroom(skb) < tailroom) { spin_unlock(&tdb_lock); printk(KERN_WARNING "klips_error:ipsec_tunnel_start_xmit: " "tried to skb_put %d, %d available. This should never happen, please report.\n", tailroom, skb_tailroom(skb)); stats->tx_errors++; goto cleanup; } //添加ipsec尾空间 skb_put(skb, tailroom); KLIPS_PRINT(debug_tunnel & DB_TN_CROUT, "klips_debug:ipsec_tunnel_start_xmit: " "head,tailroom: %d,%d before xform.\n", skb_headroom(skb), skb_tailroom(skb)); //此长度已经包含了刚才添加的ipsec的头空间 len = skb->len; if(len > 0xfff0) { spin_unlock(&tdb_lock); printk(KERN_WARNING "klips_error:ipsec_tunnel_start_xmit: " "tot_len (%d) > 65520. This should never happen, please report.\n", len); stats->tx_errors++; goto cleanup; } //这步是关键!!!!!!!!!!!!!!!!!!!!!!!!!!! //对于transportMode,则将内部ip头往上移动至刚才添加的ipsec头的前面 //对于tunnelMode,则将IPIP头(外部IP头)往上移动至刚才添加的ipsec头的前面 memmove((void *)dat, (void *)(dat + headroom), iphlen); //最外部的IP头 iph = (struct iphdr *)dat; iph->tot_len = htons(skb->len); switch(tdbp->tdb_said.proto) {#ifdef CONFIG_IPSEC_ESP case IPPROTO_ESP: //IP头之后就是ESP头 //前面的memmove和这里的espp的操作就把IPIP(外部IP头)头给挤上去了 espp = (struct esp *)(dat + iphlen); espp->esp_spi = tdbp->tdb_said.spi; espp->esp_rpl = htonl(++(tdbp->tdb_replaywin_lastseq)); switch(tdbp->tdb_encalg) {#if defined(CONFIG_IPSEC_ENC_3DES)#ifdef CONFIG_IPSEC_ENC_3DES case ESP_3DES:#endif /* CONFIG_IPSEC_ENC_3DES */ iv[0] = *((__u32*)&(espp->esp_iv) ) = ((__u32*)(tdbp->tdb_iv))[0]; iv[1] = *((__u32*)&(espp->esp_iv) + 1) = ((__u32*)(tdbp->tdb_iv))[1]; break;#endif /* defined(CONFIG_IPSEC_ENC_3DES) */ default: spin_unlock(&tdb_lock); stats->tx_errors++; goto cleanup; } //idat指向ESP的payload idat = dat + iphlen + headroom; //ilen是要加密部分的长度(idat的长度)(不对authenticator进行加密) ilen = len - (iphlen + headroom + authlen); /* Self-describing padding */ pad = &dat[len - tailroom]; //-2,其中1个字节存pad length,另外1个字节存next header padlen = tailroom - 2 - authlen; for (i = 0; i < padlen; i++) { pad[i] = i + 1; //按照RFC2406的要求,从1开始单向增长进行填充 } //padLength域 dat[len - authlen - 2] = padlen; //nextHeader域,为原IP头的下一头类型 dat[len - authlen - 1] = iph->protocol; //修改外部IP头,使其nextHeader类型标明为此ESP头 iph->protocol = IPPROTO_ESP; 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; } 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; } 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));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -