📄 ipsec_xmit.c
字号:
ixs->stats->tx_dropped++; return IPSEC_XMIT_NOIPOPTIONS; }#endif /* IPSEC_DISALLOW_IPOPTIONS */ #ifndef NET_21 if (ixs->iph->ttl <= 0) { /* Tell the sender its packet died... */ ICMP_SEND(ixs->skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, 0, ixs->physdev); KLIPS_PRINT(debug_tunnel, "klips_debug:ipsec_xmit_sanity_check_skb: " "TTL=0, too many hops!\n"); ixs->stats->tx_dropped++; return IPSEC_XMIT_TTLEXPIRED; }#endif /* !NET_21 */ return IPSEC_XMIT_OK;}enum ipsec_xmit_valueipsec_xmit_encap_once(struct ipsec_xmit_state *ixs){#ifdef CONFIG_KLIPS_ESP struct esphdr *espp; unsigned char *idat, *pad; int authlen = 0, padlen = 0, i;#endif /* !CONFIG_KLIPS_ESP */#ifdef CONFIG_KLIPS_AH struct iphdr ipo; struct ahhdr *ahp;#endif /* CONFIG_KLIPS_AH */#if defined(CONFIG_KLIPS_AUTH_HMAC_MD5) || defined(CONFIG_KLIPS_AUTH_HMAC_SHA1) union {#ifdef CONFIG_KLIPS_AUTH_HMAC_MD5 MD5_CTX md5;#endif /* CONFIG_KLIPS_AUTH_HMAC_MD5 */#ifdef CONFIG_KLIPS_AUTH_HMAC_SHA1 SHA1_CTX sha1;#endif /* CONFIG_KLIPS_AUTH_HMAC_SHA1 */ } tctx; __u8 hash[AH_AMAX];#endif /* defined(CONFIG_KLIPS_AUTH_HMAC_MD5) || defined(CONFIG_KLIPS_AUTH_HMACn_SHA1) */ int headroom = 0, tailroom = 0, ilen = 0, len = 0; unsigned char *dat; int blocksize = 8; /* XXX: should be inside ixs --jjo */ struct ipsec_alg_enc *ixt_e = NULL; struct ipsec_alg_auth *ixt_a = NULL; ixs->iphlen = ixs->iph->ihl << 2; ixs->pyldsz = ntohs(ixs->iph->tot_len) - ixs->iphlen; ixs->sa_len = satot(&ixs->ipsp->ips_said, 0, ixs->sa_txt, SATOT_BUF); KLIPS_PRINT(debug_tunnel & DB_TN_OXFS, "klips_debug:ipsec_xmit_encap_once: " "calling output for <%s%s%s>, SA:%s\n", IPS_XFORM_NAME(ixs->ipsp), ixs->sa_len ? ixs->sa_txt : " (error)"); switch(ixs->ipsp->ips_said.proto) {#ifdef CONFIG_KLIPS_AH case IPPROTO_AH: headroom += sizeof(struct ahhdr); break;#endif /* CONFIG_KLIPS_AH */#ifdef CONFIG_KLIPS_ESP case IPPROTO_ESP: ixt_e=ixs->ipsp->ips_alg_enc; if (ixt_e) { blocksize = ixt_e->ixt_common.ixt_blocksize; headroom += ESP_HEADER_LEN + ixt_e->ixt_common.ixt_support.ias_ivlen/8; } else { ixs->stats->tx_errors++; return IPSEC_XMIT_ESP_BADALG; } ixt_a=ixs->ipsp->ips_alg_auth; if (ixt_a) { tailroom += AHHMAC_HASHLEN; } else switch(ixs->ipsp->ips_authalg) {#ifdef CONFIG_KLIPS_AUTH_HMAC_MD5 case AH_MD5: authlen = AHHMAC_HASHLEN; break;#endif /* CONFIG_KLIPS_AUTH_HMAC_MD5 */#ifdef CONFIG_KLIPS_AUTH_HMAC_SHA1 case AH_SHA: authlen = AHHMAC_HASHLEN; break;#endif /* CONFIG_KLIPS_AUTH_HMAC_SHA1 */ case AH_NONE: break; default: ixs->stats->tx_errors++; return IPSEC_XMIT_ESP_BADALG; } tailroom += blocksize != 1 ? ((blocksize - ((ixs->pyldsz + 2) % blocksize)) % blocksize) + 2 : ((4 - ((ixs->pyldsz + 2) % 4)) % 4) + 2; tailroom += authlen; break;#endif /* CONFIG_KLIPS_ESP */#ifdef CONFIG_KLIPS_IPIP case IPPROTO_IPIP: headroom += sizeof(struct iphdr); ixs->iphlen = sizeof(struct iphdr); break;#endif /* !CONFIG_KLIPS_IPIP */#ifdef CONFIG_KLIPS_IPCOMP case IPPROTO_COMP: break;#endif /* CONFIG_KLIPS_IPCOMP */ default: ixs->stats->tx_errors++; return IPSEC_XMIT_BADPROTO; } KLIPS_PRINT(debug_tunnel & DB_TN_CROUT, "klips_debug:ipsec_xmit_encap_once: " "pushing %d bytes, putting %d, proto %d.\n", headroom, tailroom, ixs->ipsp->ips_said.proto); if(skb_headroom(ixs->skb) < headroom) { printk(KERN_WARNING "klips_error:ipsec_xmit_encap_once: " "tried to skb_push headroom=%d, %d available. This should never happen, please report.\n", headroom, skb_headroom(ixs->skb)); ixs->stats->tx_errors++; return IPSEC_XMIT_ESP_PUSHPULLERR; } dat = skb_push(ixs->skb, headroom); ilen = ixs->skb->len - tailroom; if(skb_tailroom(ixs->skb) < tailroom) { printk(KERN_WARNING "klips_error:ipsec_xmit_encap_once: " "tried to skb_put %d, %d available. This should never happen, please report.\n", tailroom, skb_tailroom(ixs->skb)); ixs->stats->tx_errors++; return IPSEC_XMIT_ESP_PUSHPULLERR; } skb_put(ixs->skb, tailroom); KLIPS_PRINT(debug_tunnel & DB_TN_CROUT, "klips_debug:ipsec_xmit_encap_once: " "head,tailroom: %d,%d before xform.\n", skb_headroom(ixs->skb), skb_tailroom(ixs->skb)); len = ixs->skb->len; if(len > 0xfff0) { printk(KERN_WARNING "klips_error:ipsec_xmit_encap_once: " "tot_len (%d) > 65520. This should never happen, please report.\n", len); ixs->stats->tx_errors++; return IPSEC_XMIT_BADLEN; } memmove((void *)dat, (void *)(dat + headroom), ixs->iphlen); ixs->iph = (struct iphdr *)dat; ixs->iph->tot_len = htons(ixs->skb->len); switch(ixs->ipsp->ips_said.proto) {#ifdef CONFIG_KLIPS_ESP case IPPROTO_ESP: espp = (struct esphdr *)(dat + ixs->iphlen); espp->esp_spi = ixs->ipsp->ips_said.spi; espp->esp_rpl = htonl(++(ixs->ipsp->ips_replaywin_lastseq)); if (!ixt_e) { ixs->stats->tx_errors++; return IPSEC_XMIT_ESP_BADALG; } idat = dat + ixs->iphlen + headroom; ilen = len - (ixs->iphlen + headroom + authlen); /* Self-describing padding */ pad = &dat[len - tailroom]; padlen = tailroom - 2 - authlen; for (i = 0; i < padlen; i++) { pad[i] = i + 1; } dat[len - authlen - 2] = padlen; dat[len - authlen - 1] = ixs->iph->protocol; ixs->iph->protocol = IPPROTO_ESP; if(debug_tunnel & DB_TN_ENCAP) { dmp("pre-encrypt", dat, len); } /* * Do all operations here: * copy IV->ESP, encrypt, update ips IV * */ { int ret; memcpy(espp->esp_iv, ixs->ipsp->ips_iv, ixs->ipsp->ips_iv_size); ret=ipsec_alg_esp_encrypt(ixs->ipsp, idat, ilen, espp->esp_iv, IPSEC_ALG_ENCRYPT); prng_bytes(&ipsec_prng, (char *)ixs->ipsp->ips_iv, ixs->ipsp->ips_iv_size); } if (ixt_a) { ipsec_alg_sa_esp_hash(ixs->ipsp, (caddr_t)espp, len - ixs->iphlen - authlen, &(dat[len - authlen]), authlen); } else switch(ixs->ipsp->ips_authalg) {#ifdef CONFIG_KLIPS_AUTH_HMAC_MD5 case AH_MD5: dmp("espp", (char*)espp, len - ixs->iphlen - authlen); tctx.md5 = ((struct md5_ctx*)(ixs->ipsp->ips_key_a))->ictx; dmp("ictx", (char*)&tctx.md5, sizeof(tctx.md5)); osMD5Update(&tctx.md5, (caddr_t)espp, len - ixs->iphlen - authlen); dmp("ictx+dat", (char*)&tctx.md5, sizeof(tctx.md5)); osMD5Final(hash, &tctx.md5); dmp("ictx hash", (char*)&hash, sizeof(hash)); tctx.md5 = ((struct md5_ctx*)(ixs->ipsp->ips_key_a))->octx; dmp("octx", (char*)&tctx.md5, sizeof(tctx.md5)); osMD5Update(&tctx.md5, hash, AHMD596_ALEN); dmp("octx+hash", (char*)&tctx.md5, sizeof(tctx.md5)); osMD5Final(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_KLIPS_AUTH_HMAC_MD5 */#ifdef CONFIG_KLIPS_AUTH_HMAC_SHA1 case AH_SHA: tctx.sha1 = ((struct sha1_ctx*)(ixs->ipsp->ips_key_a))->ictx; SHA1Update(&tctx.sha1, (caddr_t)espp, len - ixs->iphlen - authlen); SHA1Final(hash, &tctx.sha1); tctx.sha1 = ((struct sha1_ctx*)(ixs->ipsp->ips_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_KLIPS_AUTH_HMAC_SHA1 */ case AH_NONE: break; default: ixs->stats->tx_errors++; return IPSEC_XMIT_AH_BADALG; }#ifdef NET_21 ixs->skb->h.raw = (unsigned char*)espp;#endif /* NET_21 */ break;#endif /* !CONFIG_KLIPS_ESP */#ifdef CONFIG_KLIPS_AH case IPPROTO_AH: ahp = (struct ahhdr *)(dat + ixs->iphlen); ahp->ah_spi = ixs->ipsp->ips_said.spi; ahp->ah_rpl = htonl(++(ixs->ipsp->ips_replaywin_lastseq)); ahp->ah_rv = 0; ahp->ah_nh = ixs->iph->protocol; ahp->ah_hl = (headroom >> 2) - sizeof(__u64)/sizeof(__u32); ixs->iph->protocol = IPPROTO_AH; dmp("ahp", (char*)ahp, sizeof(*ahp)); ipo = *ixs->iph; ipo.tos = 0; ipo.frag_off = 0; ipo.ttl = 0; ipo.check = 0; dmp("ipo", (char*)&ipo, sizeof(ipo)); switch(ixs->ipsp->ips_authalg) {#ifdef CONFIG_KLIPS_AUTH_HMAC_MD5 case AH_MD5: tctx.md5 = ((struct md5_ctx*)(ixs->ipsp->ips_key_a))->ictx; dmp("ictx", (char*)&tctx.md5, sizeof(tctx.md5)); osMD5Update(&tctx.md5, (unsigned char *)&ipo, sizeof (struct iphdr)); dmp("ictx+ipo", (char*)&tctx.md5, sizeof(tctx.md5)); osMD5Update(&tctx.md5, (unsigned char *)ahp, headroom - sizeof(ahp->ah_data)); dmp("ictx+ahp", (char*)&tctx.md5, sizeof(tctx.md5)); osMD5Update(&tctx.md5, (unsigned char *)zeroes, AHHMAC_HASHLEN); dmp("ictx+zeroes", (char*)&tctx.md5, sizeof(tctx.md5)); osMD5Update(&tctx.md5, dat + ixs->iphlen + headroom, len - ixs->iphlen - headroom); dmp("ictx+dat", (char*)&tctx.md5, sizeof(tctx.md5)); osMD5Final(hash, &tctx.md5); dmp("ictx hash", (char*)&hash, sizeof(hash)); tctx.md5 = ((struct md5_ctx*)(ixs->ipsp->ips_key_a))->octx; dmp("octx", (char*)&tctx.md5, sizeof(tctx.md5)); osMD5Update(&tctx.md5, hash, AHMD596_ALEN); dmp("octx+hash", (char*)&tctx.md5, sizeof(tctx.md5)); osMD5Final(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_KLIPS_AUTH_HMAC_MD5 */#ifdef CONFIG_KLIPS_AUTH_HMAC_SHA1 case AH_SHA: tctx.sha1 = ((struct sha1_ctx*)(ixs->ipsp->ips_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 + ixs->iphlen + headroom, len - ixs->iphlen - headroom); SHA1Final(hash, &tctx.sha1); tctx.sha1 = ((struct sha1_ctx*)(ixs->ipsp->ips_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_KLIPS_AUTH_HMAC_SHA1 */ default: ixs->stats->tx_errors++; return IPSEC_XMIT_AH_BADALG; }#ifdef NET_21 ixs->skb->h.raw = (unsigned char*)ahp;#endif /* NET_21 */ break;#endif /* CONFIG_KLIPS_AH */#ifdef CONFIG_KLIPS_IPIP case IPPROTO_IPIP: ixs->iph->version = 4; switch(sysctl_ipsec_tos) { case 0:#ifdef NET_21 ixs->iph->tos = ixs->skb->nh.iph->tos;#else /* NET_21 */ ixs->iph->tos = ixs->skb->ip_hdr->tos;#endif /* NET_21 */ break; case 1: ixs->iph->tos = 0; break; default: break; } ixs->iph->ttl = SYSCTL_IPSEC_DEFAULT_TTL; ixs->iph->frag_off = 0; ixs->iph->saddr = ((struct sockaddr_in*)(ixs->ipsp->ips_addr_s))->sin_addr.s_addr; ixs->iph->daddr = ((struct sockaddr_in*)(ixs->ipsp->ips_addr_d))->sin_addr.s_addr; ixs->iph->protocol = IPPROTO_IPIP; ixs->iph->ihl = sizeof(struct iphdr) >> 2; KLIPS_IP_SELECT_IDENT(ixs->iph, ixs->skb); ixs->newdst = (__u32)ixs->iph->daddr; ixs->newsrc = (__u32)ixs->iph->saddr; #ifdef NET_21 ixs->skb->h.ipiph = ixs->skb->nh.iph;#endif /* NET_21 */ break;#endif /* !CONFIG_KLIPS_IPIP */#ifdef CONFIG_KLIPS_IPCOMP case IPPROTO_COMP: { unsigned int flags = 0;#ifdef CONFIG_KLIPS_DEBUG unsigned int old_tot_len = ntohs(ixs->iph->tot_len);#endif /* CONFIG_KLIPS_DEBUG */ ixs->ipsp->ips_comp_ratio_dbytes += ntohs(ixs->iph->tot_len); ixs->skb = skb_compress(ixs->skb, ixs->ipsp, &flags);#ifdef NET_21 ixs->iph = ixs->skb->nh.iph;#else /* NET_21 */ ixs->iph = ixs->skb->ip_hdr;#endif /* NET_21 */ ixs->ipsp->ips_comp_ratio_cbytes += ntohs(ixs->iph->tot_len);#ifdef CONFIG_KLIPS_DEBUG if (debug_tunnel & DB_TN_CROUT) { if (old_tot_len > ntohs(ixs->iph->tot_len)) KLIPS_PRINT(debug_tunnel & DB_TN_CROUT, "klips_debug:ipsec_xmit_encap_once: " "packet shrunk from %d to %d bytes after compression, cpi=%04x (should be from spi=%08x, spi&0xffff=%04x.\n", old_tot_len, ntohs(ixs->iph->tot_len), ntohs(((struct ipcomphdr*)(((char*)ixs->iph) + ((ixs->iph->ihl) << 2)))->ipcomp_cpi), ntohl(ixs->ipsp->ips_said.spi), (__u16)(ntohl(ixs->ipsp->ips_said.spi) & 0x0000ffff)); else KLIPS_PRINT(debug_tunnel & DB_TN_CROUT, "klips_debug:ipsec_xmit_encap_once: " "packet did not compress (flags = %d).\n", flags); }#endif /* CONFIG_KLIPS_DEBUG */ } break;#endif /* CONFIG_KLIPS_IPCOMP */ default: ixs->stats->tx_errors++; return IPSEC_XMIT_BADPROTO; } #ifdef NET_21 ixs->skb->nh.raw = ixs->skb->data;#else /* NET_21 */ ixs->skb->ip_hdr = ixs->skb->h.iph = (struct iphdr *) ixs->skb->data;#endif /* NET_21 */ ixs->iph->check = 0; ixs->iph->check = ip_fast_csum((unsigned char *)ixs->iph, ixs->iph->ihl); KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_xmit_encap_once: " "after <%s%s%s>, SA:%s:\n", IPS_XFORM_NAME(ixs->ipsp), ixs->sa_len ? ixs->sa_txt : " (error)"); KLIPS_IP_PRINT(debug_tunnel & DB_TN_XMIT, ixs->iph); ixs->ipsp->ips_life.ipl_bytes.ipl_count += len; ixs->ipsp->ips_life.ipl_bytes.ipl_last = len; if(!ixs->ipsp->ips_life.ipl_usetime.ipl_count) { ixs->ipsp->ips_life.ipl_usetime.ipl_count = jiffies / HZ; } ixs->ipsp->ips_life.ipl_usetime.ipl_last = jiffies / HZ; ixs->ipsp->ips_life.ipl_packets.ipl_count++; ixs->ipsp = ixs->ipsp->ips_onext; return IPSEC_XMIT_OK;}/* * If the IP packet (iph) is a carrying TCP/UDP, then set the encaps * source and destination ports to those from the TCP/UDP header. */void ipsec_extract_ports(struct iphdr * iph, struct sockaddr_encap * er){ struct udphdr *udp; switch (iph->protocol) { case IPPROTO_UDP: case IPPROTO_TCP: /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -