📄 ipsec_xmit.c
字号:
ixs->headroom = ixs->tailroom = 0; KLIPS_PRINT(debug_tunnel & DB_TN_CROUT, "klips_debug:ipsec_xmit_encap_bundle: " "calling room 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: ixs->headroom += sizeof(struct ahhdr); break;#endif /* CONFIG_KLIPS_AH */#ifdef CONFIG_KLIPS_ESP case IPPROTO_ESP:#ifdef CONFIG_KLIPS_ALG if ((ixt_e=ixs->ipsp->ips_alg_enc)) { blocksize = ixt_e->ixt_blocksize; ixs->headroom += ESP_HEADER_LEN + ixt_e->ixt_ivlen/8; } else#endif /* CONFIG_KLIPS_ALG */ switch(ixs->ipsp->ips_encalg) {#ifdef CONFIG_KLIPS_ENC_3DES case ESP_3DES: ixs->headroom += sizeof(struct esphdr); break;#endif /* CONFIG_KLIPS_ENC_3DES */ default: ixs->stats->tx_errors++; bundle_stat = IPSEC_XMIT_ESP_BADALG; goto cleanup; }#ifdef CONFIG_KLIPS_ALG if ((ixt_a=ixs->ipsp->ips_alg_auth)) { ixs->tailroom += AHHMAC_HASHLEN; } else#endif /* CONFIG_KLIPS_ALG */ switch(ixs->ipsp->ips_authalg) {#ifdef CONFIG_KLIPS_AUTH_HMAC_MD5 case AH_MD5: ixs->tailroom += AHHMAC_HASHLEN; break;#endif /* CONFIG_KLIPS_AUTH_HMAC_MD5 */#ifdef CONFIG_KLIPS_AUTH_HMAC_SHA1 case AH_SHA: ixs->tailroom += AHHMAC_HASHLEN; break;#endif /* CONFIG_KLIPS_AUTH_HMAC_SHA1 */ case AH_NONE: break; default: ixs->stats->tx_errors++; bundle_stat = IPSEC_XMIT_AH_BADALG; goto cleanup; } #ifdef CONFIG_KLIPS_ALG ixs->tailroom += blocksize != 1 ? ((blocksize - ((ixs->pyldsz + 2) % blocksize)) % blocksize) + 2 : ((4 - ((ixs->pyldsz + 2) % 4)) % 4) + 2;#else ixs->tailroom += ((8 - ((ixs->pyldsz + 2 * sizeof(unsigned char)) % 8)) % 8) + 2;#endif /* CONFIG_KLIPS_ALG */#ifdef CONFIG_KLIPS_NAT_TRAVERSAL if ((ixs->ipsp->ips_natt_type) && (!ixs->natt_type)) { ixs->natt_type = ixs->ipsp->ips_natt_type; ixs->natt_sport = ixs->ipsp->ips_natt_sport; ixs->natt_dport = ixs->ipsp->ips_natt_dport; switch (ixs->natt_type) { case ESPINUDP_WITH_NON_IKE: ixs->natt_head = sizeof(struct udphdr)+(2*sizeof(__u32)); break; case ESPINUDP_WITH_NON_ESP: ixs->natt_head = sizeof(struct udphdr); break; default: KLIPS_PRINT(debug_tunnel & DB_TN_CROUT , "klips_xmit: invalid nat-t type %d" , ixs->natt_type); bundle_stat = IPSEC_XMIT_ESPUDP_BADTYPE; goto cleanup; break; } ixs->tailroom += ixs->natt_head; }#endif break;#endif /* !CONFIG_KLIPS_ESP */#ifdef CONFIG_KLIPS_IPIP case IPPROTO_IPIP: ixs->headroom += sizeof(struct iphdr); break;#endif /* !CONFIG_KLIPS_IPIP */ case IPPROTO_COMP:#ifdef CONFIG_KLIPS_IPCOMP /* We can't predict how much the packet will shrink without doing the actual compression. We could do it here, if we were the first encapsulation in the chain. That might save us a skb_copy_expand, since we might fit into the existing skb then. However, this would be a bit unclean (and this hack has bit us once), so we better not do it. After all, the skb_copy_expand is cheap in comparison to the actual compression. At least we know the packet will not grow. */ break;#endif /* CONFIG_KLIPS_IPCOMP */ default: ixs->stats->tx_errors++; bundle_stat = IPSEC_XMIT_BADPROTO; goto cleanup; } ixs->ipsp = ixs->ipsp->ips_onext; KLIPS_PRINT(debug_tunnel & DB_TN_CROUT, "klips_debug:ipsec_xmit_encap_bundle: " "Required head,tailroom: %d,%d\n", ixs->headroom, ixs->tailroom); ixs->max_headroom += ixs->headroom; ixs->max_tailroom += ixs->tailroom; ixs->pyldsz += (ixs->headroom + ixs->tailroom); } ixs->ipsp = ixs->ipsq; /* restore the head of the ipsec_sa chain */ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT, "klips_debug:ipsec_xmit_encap_bundle: " "existing head,tailroom: %d,%d before applying xforms with head,tailroom: %d,%d .\n", skb_headroom(ixs->skb), skb_tailroom(ixs->skb), ixs->max_headroom, ixs->max_tailroom); ixs->tot_headroom += ixs->max_headroom; ixs->tot_tailroom += ixs->max_tailroom; ixs->mtudiff = ixs->prv->mtu + ixs->tot_headroom + ixs->tot_tailroom - ixs->physmtu; KLIPS_PRINT(debug_tunnel & DB_TN_CROUT, "klips_debug:ipsec_xmit_encap_bundle: " "mtu:%d physmtu:%d tothr:%d tottr:%d mtudiff:%d ippkttotlen:%d\n", ixs->prv->mtu, ixs->physmtu, ixs->tot_headroom, ixs->tot_tailroom, ixs->mtudiff, ntohs(ixs->iph->tot_len)); if(ixs->mtudiff > 0) { int newmtu = ixs->physmtu - (ixs->tot_headroom + ((ixs->tot_tailroom + 2) & ~7) + 5); KLIPS_PRINT(debug_tunnel & DB_TN_CROUT, "klips_info:ipsec_xmit_encap_bundle: " "dev %s mtu of %d decreased by %d to %d\n", ixs->dev->name, ixs->prv->mtu, ixs->prv->mtu - newmtu, newmtu); ixs->prv->mtu = newmtu;#ifdef NET_21#if 0 ixs->skb->dst->pmtu = ixs->prv->mtu; /* RGB */#endif /* 0 */#else /* NET_21 */#if 0 ixs->dev->mtu = ixs->prv->mtu; /* RGB */#endif /* 0 */#endif /* NET_21 */ } /* If the sender is doing PMTU discovery, and the packet doesn't fit within ixs->prv->mtu, notify him (unless it was an ICMP packet, or it was not the zero-offset packet) and send it anyways. Note: buggy firewall configuration may prevent the ICMP packet from getting back. */ if(sysctl_ipsec_icmp && ixs->prv->mtu < ntohs(ixs->iph->tot_len) && (ixs->iph->frag_off & __constant_htons(IP_DF)) ) { int notify = ixs->iph->protocol != IPPROTO_ICMP && (ixs->iph->frag_off & __constant_htons(IP_OFFSET)) == 0; #ifdef IPSEC_obey_DF KLIPS_PRINT(debug_tunnel & DB_TN_CROUT, "klips_debug:ipsec_xmit_encap_bundle: " "fragmentation needed and DF set; %sdropping packet\n", notify ? "sending ICMP and " : ""); if (notify) ICMP_SEND(ixs->skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, ixs->prv->mtu, ixs->physdev); ixs->stats->tx_errors++; bundle_stat = IPSEC_XMIT_CANNOTFRAG; goto cleanup;#else /* IPSEC_obey_DF */ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT, "klips_debug:ipsec_xmit_encap_bundle: " "fragmentation needed and DF set; %spassing packet\n", notify ? "sending ICMP and " : ""); if (notify) ICMP_SEND(ixs->skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, ixs->prv->mtu, ixs->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 (ixs->iph->protocol == IPPROTO_TCP && ixs->outgoing_said.proto != IPPROTO_IPIP) { struct tcphdr *tcph = ixs->skb->h.th; if (tcph->syn && !tcph->ack) { if(!ipsec_adjust_mss(ixs->skb, tcph, ixs->prv->mtu)) { printk(KERN_WARNING "klips_warning:ipsec_xmit_encap_bundle: " "ipsec_adjust_mss() failed\n"); ixs->stats->tx_errors++; bundle_stat = IPSEC_XMIT_MSSERR; goto cleanup; } } }#endif /* MSS_HACK */#ifdef CONFIG_KLIPS_NAT_TRAVERSAL if ((ixs->natt_type) && (ixs->outgoing_said.proto != IPPROTO_IPIP)) { /** * NAT-Traversal and Transport Mode: * we need to correct TCP/UDP checksum * * If we've got NAT-OA, we can fix checksum without recalculation. * If we don't we can zero udp checksum. */ __u32 natt_oa = ixs->ipsp->ips_natt_oa ? ((struct sockaddr_in*)(ixs->ipsp->ips_natt_oa))->sin_addr.s_addr : 0; __u16 pkt_len = ixs->skb->tail - (unsigned char *)ixs->iph; __u16 data_len = pkt_len - (ixs->iph->ihl << 2); switch (ixs->iph->protocol) { case IPPROTO_TCP: if (data_len >= sizeof(struct tcphdr)) { struct tcphdr *tcp = (struct tcphdr *)((__u32 *)ixs->iph+ixs->iph->ihl); if (natt_oa) { __u32 buff[2] = { ~ixs->iph->daddr, natt_oa }; KLIPS_PRINT(debug_tunnel, "klips_debug:ipsec_tunnel_start_xmit: " "NAT-T & TRANSPORT: " "fix TCP checksum using NAT-OA\n"); tcp->check = csum_fold( csum_partial((unsigned char *)buff, sizeof(buff), tcp->check^0xffff)); } else { KLIPS_PRINT(debug_tunnel, "klips_debug:ipsec_tunnel_start_xmit: " "NAT-T & TRANSPORT: do not recalc TCP checksum\n"); } } else { KLIPS_PRINT(debug_tunnel, "klips_debug:ipsec_tunnel_start_xmit: " "NAT-T & TRANSPORT: can't fix TCP checksum\n"); } break; case IPPROTO_UDP: if (data_len >= sizeof(struct udphdr)) { struct udphdr *udp = (struct udphdr *)((__u32 *)ixs->iph+ixs->iph->ihl); if (udp->check == 0) { KLIPS_PRINT(debug_tunnel, "klips_debug:ipsec_tunnel_start_xmit: " "NAT-T & TRANSPORT: UDP checksum already 0\n"); } else if (natt_oa) { __u32 buff[2] = { ~ixs->iph->daddr, natt_oa }; KLIPS_PRINT(debug_tunnel, "klips_debug:ipsec_tunnel_start_xmit: " "NAT-T & TRANSPORT: " "fix UDP checksum using NAT-OA\n"); udp->check = csum_fold( csum_partial((unsigned char *)buff, sizeof(buff), udp->check^0xffff)); } else { KLIPS_PRINT(debug_tunnel, "klips_debug:ipsec_tunnel_start_xmit: " "NAT-T & TRANSPORT: zero UDP checksum\n"); udp->check = 0; } } else { KLIPS_PRINT(debug_tunnel, "klips_debug:ipsec_tunnel_start_xmit: " "NAT-T & TRANSPORT: can't fix UDP checksum\n"); } break; default: KLIPS_PRINT(debug_tunnel, "klips_debug:ipsec_tunnel_start_xmit: " "NAT-T & TRANSPORT: non TCP/UDP packet -- do nothing\n"); break; } }#endif /* CONFIG_KLIPS_NAT_TRAVERSAL */ if(!ixs->hard_header_stripped) { KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_xmit_encap_bundle: " "allocating %d bytes for hardheader.\n", ixs->hard_header_len); if((ixs->saved_header = kmalloc(ixs->hard_header_len, GFP_ATOMIC)) == NULL) { printk(KERN_WARNING "klips_debug:ipsec_xmit_encap_bundle: " "Failed, tried to allocate %d bytes for temp hard_header.\n", ixs->hard_header_len); ixs->stats->tx_errors++; bundle_stat = IPSEC_XMIT_ERRMEMALLOC; goto cleanup; } { int i; for (i = 0; i < ixs->hard_header_len; i++) { ixs->saved_header[i] = ixs->skb->data[i]; } } if(ixs->skb->len < ixs->hard_header_len) { printk(KERN_WARNING "klips_error:ipsec_xmit_encap_bundle: " "tried to skb_pull hhlen=%d, %d available. This should never happen, please report.\n", ixs->hard_header_len, (int)(ixs->skb->len)); ixs->stats->tx_errors++; bundle_stat = IPSEC_XMIT_ESP_PUSHPULLERR; goto cleanup; } skb_pull(ixs->skb, ixs->hard_header_len); ixs->hard_header_stripped = 1; /* ixs->iph = (struct iphdr *) (ixs->skb->data); */ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT, "klips_debug:ipsec_xmit_encap_bundle: " "head,tailroom: %d,%d after hard_header stripped.\n", skb_headroom(ixs->skb), skb_tailroom(ixs->skb)); KLIPS_IP_PRINT(debug_tunnel & DB_TN_CROUT, ixs->iph); } else { KLIPS_PRINT(debug_tunnel & DB_TN_CROUT, "klips_debug:ipsec_xmit_encap_bundle: " "hard header already stripped.\n"); } ixs->ll_headroom = (ixs->hard_header_len + 15) & ~15; if ((skb_headroom(ixs->skb) >= ixs->max_headroom + 2 * ixs->ll_headroom) && (skb_tailroom(ixs->skb) >= ixs->max_tailroom)#ifndef NET_21 && ixs->skb->free#endif /* !NET_21 */ ) { KLIPS_PRINT(debug_tunnel & DB_TN_CROUT, "klips_debug:ipsec_xmit_encap_bundle: " "data fits in existing skb\n"); } else { struct sk_buff* tskb; if(!ixs->oskb) { ixs->oskb = ixs->skb; } tskb = skb_copy_expand(ixs->skb, /* The need for 2 * link layer length here remains unexplained...RGB */ ixs->max_headroom + 2 * ixs->ll_headroom, ixs->max_tailroom, GFP_ATOMIC);#ifdef NET_21 if(tskb && ixs->skb->sk) { skb_set_owner_w(tskb, ixs->skb->sk); }#endif /* NET_21 */ if(ixs->skb != ixs->oskb) { ipsec_kfree_skb(ixs->skb); } ixs->skb = tskb; if (!ixs->skb) { printk(KERN_WARNING "klips_debug:ipsec_xmit_encap_bundle: " "Failed, tried to allocate %d head and %d tailroom\n", ixs->max_headroom, ixs->max_tailroom); ixs->stats->tx_errors++; bundle_stat = IPSEC_XMIT_ERRSKBALLOC; goto cleanup; } KLIPS_PRINT(debug_tunnel & DB_TN_CROUT, "klips_debug:ipsec_xmit_encap_bundle: " "head,tailroom: %d,%d after allocation\n", skb_headroom(ixs->skb), skb_tailroom(ixs->skb)); } /* * Apply grouped transforms to packet */ while (ixs->ipsp) { enum ipsec_xmit_value encap_stat = IPSEC_XMIT_OK; encap_stat = ipsec_xmit_encap_once(ixs); if(encap_stat != IPSEC_XMIT_OK) { KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_xmit_encap_bundle: encap_once failed: %d\n", encap_stat); bundle_stat = IPSEC_XMIT_ENCAPFAIL; goto cleanup; } } /* end encapsulation loop here XXX */ cleanup: spin_unlock(&tdb_lock); return bundle_stat;}/* * $Log: ipsec_xmit.c,v $ * Revision 1.10 2004/09/13 17:55:21 ken * MD5* -> osMD5* * * Revision 1.9 2004/07/10 19:11:18 mcr * CONFIG_IPSEC -> CONFIG_KLIPS. * * Revision 1.8 2004/04/06 02:49:26 mcr * pullup of algo code from alg-branch. * * Revision 1.7 2004/02/03 03:13:41 mcr * mark invalid encapsulation states. * * Revision 1.6.2.1 2003/12/22 15:25:52 jjo * Merged algo-0.8.1-rc11-test1 into alg-branch * * Revision 1.6 2003/12/10 01:14:27 mcr * NAT-traversal patches to KLIPS. * * Revision 1.5 2003/10/31 02:27:55 mcr * pulled up port-selector patches and sa_id elimination. * * Revision 1.4.4.2 2003/10/29 01:37:39 mcr * when creating %hold from %trap, only make the %hold as * specific as the %trap was - so if the protocol and ports * were wildcards, then the %hold will be too. * * Revision 1.4.4.1 2003/09/21 13:59:56 mcr * pre-liminary X.509 patch - does not yet pass tests. * * Revision 1.4 2003/06/20 02:28:10 mcr * misstype of variable name, not detected by module build. * * Revision 1.3 2003/06/20 01:42:21 mcr * added counters to measure how many ACQUIREs we send to pluto, * and how many are successfully sent. * * Revision 1.2 2003/04/03 17:38:35 rgb * Centralised ipsec_kfree_skb and ipsec_dev_{get,put}. * Normalised coding style. * Simplified logic and reduced duplication of code. * * Revision 1.1 2003/02/12 19:31:23 rgb * Refactored from ipsec_tunnel.c * */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -