📄 ipsec_tunnel.c
字号:
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); } tdbp = gettdb(&outgoing_said); sa_len = satoa(outgoing_said, 0, sa, SATOA_BUF); if (tdbp == NULL) { spin_unlock(&tdb_lock); KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_tunnel_start_xmit: " "no Tunnel Descriptor Block for SA%s: outgoing packet with no SA, dropped.\n", sa_len ? sa : " (error)"); stats->tx_dropped++; goto cleanup; } KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_tunnel_start_xmit: " "found Tunnel Descriptor Block -- SA:<%s%s%s> %s\n", TDB_XFORM_NAME(tdbp), sa_len ? sa : " (error)"); /* * How much headroom do we need to be able to apply * all the grouped transforms? */ tdbq = tdbp; /* save the head of the tdb chain */ while (tdbp) { sa_len = satoa(tdbp->tdb_said, 0, sa, SATOA_BUF); /* If it is in larval state, drop the packet, we cannot process yet. */ if(tdbp->tdb_state == SADB_SASTATE_LARVAL) { KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_tunnel_start_xmit: " "TDB in larval state for SA:<%s%s%s> %s, cannot be used yet, dropping packet.\n", TDB_XFORM_NAME(tdbp), sa_len ? sa : " (error)"); spin_unlock(&tdb_lock); stats->tx_errors++; goto cleanup; } if(tdbp->tdb_state == SADB_SASTATE_DEAD) { KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_tunnel_start_xmit: " "TDB in dead state for SA:<%s%s%s> %s, can no longer be used, dropping packet.\n", TDB_XFORM_NAME(tdbp), sa_len ? sa : " (error)"); spin_unlock(&tdb_lock); stats->tx_errors++; goto cleanup; } /* If the replay window counter == -1, expire SA, it will roll */ if(tdbp->tdb_replaywin && tdbp->tdb_replaywin_lastseq == -1) { pfkey_expire(tdbp, 1); KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_tunnel_start_xmit: " "replay window counter rolled for SA:<%s%s%s> %s, packet dropped, expiring SA.\n", TDB_XFORM_NAME(tdbp), sa_len ? sa : " (error)"); deltdbchain(tdbp); spin_unlock(&tdb_lock); stats->tx_errors++; goto cleanup; } /* If any of the lifetime counters have overflowed, expire the SA(s). */ if(tdbp->tdb_lifetime_bytes_h && (tdbp->tdb_lifetime_bytes_c > tdbp->tdb_lifetime_bytes_h)) { pfkey_expire(tdbp, 1); KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_tunnel_start_xmit: " "hard bytes lifetime of SA:<%s%s%s> %s has been reached, SA expired, outgoing packet dropped.\n", TDB_XFORM_NAME(tdbp), sa_len ? sa : " (error)"); deltdbchain(tdbp); spin_unlock(&tdb_lock); stats->tx_errors++; goto cleanup; } if(tdbp->tdb_lifetime_bytes_s && (tdbp->tdb_lifetime_bytes_c > tdbp->tdb_lifetime_bytes_s)) { if(tdbp->tdb_state != SADB_SASTATE_DYING) { pfkey_expire(tdbp, 0); } tdbp->tdb_state = SADB_SASTATE_DYING; KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_tunnel_start_xmit: " "soft bytes lifetime of SA:<%s%s%s> %s has been reached, SA expiring, soft expire message sent up, outgoing packet still processed.\n", TDB_XFORM_NAME(tdbp), sa_len ? sa : " (error)"); } if(tdbp->tdb_lifetime_addtime_h && ((jiffies / HZ) - tdbp->tdb_lifetime_addtime_c > tdbp->tdb_lifetime_addtime_h)) { pfkey_expire(tdbp, 1); KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_tunnel_start_xmit: " "hard addtime lifetime of SA:<%s%s%s> %s has been reached, SA expired, outgoing packet dropped.\n", TDB_XFORM_NAME(tdbp), sa_len ? sa : " (error)"); deltdbchain(tdbp); spin_unlock(&tdb_lock); stats->tx_errors++; goto cleanup; } if(tdbp->tdb_lifetime_addtime_s && ((jiffies / HZ) - tdbp->tdb_lifetime_addtime_c > tdbp->tdb_lifetime_addtime_s)) { if(tdbp->tdb_state != SADB_SASTATE_DYING) { pfkey_expire(tdbp, 0); } tdbp->tdb_state = SADB_SASTATE_DYING; KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_tunnel_start_xmit: " "soft addtime lifetime of SA:<%s%s%s> %s has been reached, SA expiring, soft expire message sent up, outgoing packet still processed.\n", TDB_XFORM_NAME(tdbp), sa_len ? sa : " (error)"); } if(tdbp->tdb_lifetime_usetime_c) { if(tdbp->tdb_lifetime_usetime_h && ((jiffies / HZ) - tdbp->tdb_lifetime_usetime_c > tdbp->tdb_lifetime_usetime_h)) { pfkey_expire(tdbp, 1); KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_tunnel_start_xmit: " "hard usetime lifetime of SA:<%s%s%s> %s has been reached, SA expired, outgoing packet dropped.\n", TDB_XFORM_NAME(tdbp), sa_len ? sa : " (error)"); deltdbchain(tdbp); spin_unlock(&tdb_lock); stats->tx_errors++; goto cleanup; } if(tdbp->tdb_lifetime_usetime_s && ((jiffies / HZ) - tdbp->tdb_lifetime_usetime_c > tdbp->tdb_lifetime_usetime_s)) { if(tdbp->tdb_state != SADB_SASTATE_DYING) { pfkey_expire(tdbp, 0); } tdbp->tdb_state = SADB_SASTATE_DYING; KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_tunnel_start_xmit: " "soft usetime lifetime of SA:<%s%s%s> %s has been reached, SA expiring, soft expire message sent up, outgoing packet still processed.\n", TDB_XFORM_NAME(tdbp), sa_len ? sa : " (error)"); } } if(tdbp->tdb_lifetime_packets_h && (tdbp->tdb_lifetime_packets_c > tdbp->tdb_lifetime_packets_h)) { pfkey_expire(tdbp, 1); KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_tunnel_start_xmit: " "hard packets lifetime of SA:<%s%s%s> %s has been reached, SA expired, outgoing packet dropped.\n", TDB_XFORM_NAME(tdbp), sa_len ? sa : " (error)"); deltdbchain(tdbp); spin_unlock(&tdb_lock); stats->tx_errors++; goto cleanup; } if(tdbp->tdb_lifetime_packets_s && (tdbp->tdb_lifetime_packets_c > tdbp->tdb_lifetime_packets_s)) { if(tdbp->tdb_state != SADB_SASTATE_DYING) { pfkey_expire(tdbp, 0); } tdbp->tdb_state = SADB_SASTATE_DYING; KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_tunnel_start_xmit: " "soft packets lifetime of SA:<%s%s%s> %s has been reached, SA expiring, soft expire message sent up, outgoing packet still processed.\n", TDB_XFORM_NAME(tdbp), sa_len ? sa : " (error)"); } headroom = tailroom = 0; KLIPS_PRINT(debug_tunnel & DB_TN_CROUT, "klips_debug:ipsec_tunnel_start_xmit: " "calling room for <%s%s%s>, SA:%s\n", TDB_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: tailroom += AHHMAC_HASHLEN; break;#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1 case AH_SHA: tailroom += 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; break;#endif /* !CONFIG_IPSEC_ESP */#ifdef CONFIG_IPSEC_IPIP case IPPROTO_IPIP: headroom += sizeof(struct iphdr); break;#endif /* !CONFIG_IPSEC_IPIP */ case IPPROTO_COMP:#ifdef CONFIG_IPSEC_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_IPSEC_IPCOMP */ default: spin_unlock(&tdb_lock); stats->tx_errors++; goto cleanup; } tdbp = tdbp->tdb_onext; KLIPS_PRINT(debug_tunnel & DB_TN_CROUT, "klips_debug:ipsec_tunnel_start_xmit: " "Required head,tailroom: %d,%d\n", headroom, tailroom); max_headroom += headroom; max_tailroom += tailroom; pyldsz += (headroom + tailroom); } tdbp = tdbq; /* restore the head of the tdb chain */ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT, "klips_debug:ipsec_tunnel_start_xmit: " "existing head,tailroom: %d,%d before applying xforms with head,tailroom: %d,%d .\n", skb_headroom(skb), skb_tailroom(skb), max_headroom, max_tailroom); tot_headroom += max_headroom; tot_tailroom += max_tailroom; mtudiff = prv->mtu + tot_headroom + tot_tailroom - physmtu; KLIPS_PRINT(debug_tunnel & DB_TN_CROUT, "klips_debug:ipsec_tunnel_start_xmit: " "mtu:%d physmtu:%d tothr:%d tottr:%d mtudiff:%d ippkttotlen:%d\n", prv->mtu, physmtu, tot_headroom, tot_tailroom, mtudiff, ntohs(iph->tot_len)); if(mtudiff > 0) { int newmtu = physmtu - (tot_headroom + ((tot_tailroom + 2) & ~7) + 5); KLIPS_PRINT(debug_tunnel & DB_TN_CROUT, "klips_info:ipsec_tunnel_start_xmit: " "dev %s mtu of %d decreased by %d to %d\n", dev->name, prv->mtu, prv->mtu - newmtu, newmtu); prv->mtu = newmtu;#ifdef NET_21#if 0 skb->dst->pmtu = prv->mtu; /* RGB */#endif /* 0 */#else /* NET_21 */#if 0 dev->mtu = prv->mtu; /* RGB */#endif /* 0 */#endif /* NET_21 */ } /* If the sender is doing PMTU discovery, and the packet doesn't fit within * prv->mtu, notify him (unless it was an ICMP packet) and drop it. * Note: buggy firewall configuration may prevent the ICMP packet from getting back. * Note2: Linux 2.4.x is trying to do PMTU discovery on ICMP packets, but this seems * bogus, and should be fixed in the kernel. */ if (iph->frag_off & __constant_htons(IP_DF) && prv->mtu < ntohs(iph->tot_len)) { int notify = iph->protocol != IPPROTO_ICMP && (iph->frag_off & __constant_htons(IP_OFFSET)) == 0; spin_unlock(&tdb_lock); KLIPS_PRINT(debug_tunnel & DB_TN_CROUT, "klips_debug:ipsec_tunnel_start_xmit: " "fragmentation needed and DF set; %sdropping packet\n", notify ? "sending ICMP and " : ""); if (notify) ICMP_SEND(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, prv->mtu, physdev); stats->tx_dropped++; goto cleanup; } #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; } 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"); } 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; } 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -