📄 ipsec_tunnel.c
字号:
"Failed, tried to allocate %d bytes for source ident.\n", len); stats->tx_dropped++; spin_unlock(&eroute_lock); goto cleanup; } memcpy(tdb.tdb_ident_s.data, er->er_ident_s.data, len); } tdb.tdb_ident_d.type = er->er_ident_d.type; tdb.tdb_ident_d.id = er->er_ident_d.id; tdb.tdb_ident_d.len = er->er_ident_d.len; if (tdb.tdb_ident_d.len) { len = tdb.tdb_ident_d.len * IPSEC_PFKEYv2_ALIGN - sizeof(struct sadb_ident); if ((tdb.tdb_ident_d.data = kmalloc(len, GFP_ATOMIC)) == NULL) { printk(KERN_WARNING "klips_debug:ipsec_tunnel_start_xmit: " "Failed, tried to allocate %d bytes for dest ident.\n", len); stats->tx_dropped++; spin_unlock(&eroute_lock); goto cleanup; } memcpy(tdb.tdb_ident_d.data, er->er_ident_d.data, len); } } } spin_unlock(&eroute_lock); KLIPS_PRINT(debug_tunnel & DB_TN_CROUT, "klips_debug:ipsec_tunnel_start_xmit: " "Original head,tailroom: %d,%d\n", skb_headroom(skb), skb_tailroom(skb)); innersrc = iph->saddr; /* start encapsulation loop here XXX */ do { struct ipsec_sa *tdbprev = NULL; newdst = orgdst = iph->daddr; newsrc = orgsrc = iph->saddr; orgedst = outgoing_said.dst.s_addr; iphlen = iph->ihl << 2; pyldsz = ntohs(iph->tot_len) - iphlen; max_headroom = max_tailroom = 0; if (outgoing_said.proto == IPPROTO_INT) { switch (ntohl(outgoing_said.spi)) { case SPI_DROP: KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_tunnel_start_xmit: " "shunt SA of DROP or no eroute: dropping.\n"); stats->tx_dropped++; break; case SPI_REJECT: KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_tunnel_start_xmit: " "shunt SA of REJECT: notifying and dropping.\n"); ICMP_SEND(skb, ICMP_DEST_UNREACH, ICMP_PKT_FILTERED, 0, physdev); stats->tx_dropped++; break; case SPI_PASS:#ifdef NET_21 pass = 1;#endif /* NET_21 */ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_tunnel_start_xmit: " "PASS: calling dev_queue_xmit\n"); goto bypass; #if 1 /* now moved up to finderoute so we don't need to lock it longer */ case SPI_HOLD: KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_tunnel_start_xmit: " "shunt SA of HOLD: this does not make sense here, dropping.\n"); stats->tx_dropped++; break;#endif case SPI_TRAP: case SPI_TRAPSUBNET: { struct sockaddr_in src, dst;#ifdef CONFIG_IPSEC_DEBUG char bufsrc[ADDRTOA_BUF], bufdst[ADDRTOA_BUF];#endif /* CONFIG_IPSEC_DEBUG */ /* Signal all listening KMds with a PF_KEY ACQUIRE */ tdb.tdb_said.proto = iph->protocol; src.sin_family = AF_INET; dst.sin_family = AF_INET; src.sin_addr.s_addr = iph->saddr; dst.sin_addr.s_addr = iph->daddr; src.sin_port = (iph->protocol == IPPROTO_UDP ? ((struct udphdr*) (((caddr_t)iph) + (iph->ihl << 2)))->source : (iph->protocol == IPPROTO_TCP ? ((struct tcphdr*)((caddr_t)iph + (iph->ihl << 2)))->source : 0)); dst.sin_port = (iph->protocol == IPPROTO_UDP ? ((struct udphdr*) (((caddr_t)iph) + (iph->ihl << 2)))->dest : (iph->protocol == IPPROTO_TCP ? ((struct tcphdr*)((caddr_t)iph + (iph->ihl << 2)))->dest : 0)); for(i = 0; //填充Pad为全0 i < sizeof(struct sockaddr_in) - offsetof(struct sockaddr_in, sin_zero); i++) { src.sin_zero[i] = 0; dst.sin_zero[i] = 0; } tdb.tdb_addr_s = (struct sockaddr*)(&src); tdb.tdb_addr_d = (struct sockaddr*)(&dst); KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_tunnel_start_xmit: " "SADB_ACQUIRE sent with src=%s:%d, dst=%s:%d, proto=%d.\n", addrtoa(((struct sockaddr_in*)(tdb.tdb_addr_s))->sin_addr, 0, bufsrc, sizeof(bufsrc)) <= ADDRTOA_BUF ? bufsrc : "BAD_ADDR", ntohs(((struct sockaddr_in*)(tdb.tdb_addr_s))->sin_port), addrtoa(((struct sockaddr_in*)(tdb.tdb_addr_d))->sin_addr, 0, bufdst, sizeof(bufdst)) <= ADDRTOA_BUF ? bufdst : "BAD_ADDR", ntohs(((struct sockaddr_in*)(tdb.tdb_addr_d))->sin_port), tdb.tdb_said.proto); if (pfkey_acquire(&tdb) == 0) { if (outgoing_said.spi==htonl(SPI_TRAPSUBNET)) { /* * The spinlock is to prevent any other * process from accessing or deleting * the eroute while we are using and * updating it. */ spin_lock(&eroute_lock); er = ipsec_findroute(&matcher); if(er) { er->er_said.spi = htonl(SPI_HOLD); er->er_first = skb; skb = NULL; } spin_unlock(&eroute_lock); } else if (create_hold_eroute(skb, iph, eroute_pid)) { skb = NULL; } } stats->tx_dropped++; } default: /* XXX what do we do with an unknown shunt spi? */ } /* switch (ntohl(outgoing_said.spi)) */ goto cleanup; } /* if (outgoing_said.proto == IPPROTO_INT) */ /* The spinlock is to prevent any other process from accessing or deleting the TDB hash table or any of the TDBs while we are using and updating them. 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. */ spin_lock(&tdb_lock); tdbp = ipsec_sa_getbyid(&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", IPS_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(sa_len == 0) { strcpy(sa, "(error)"); } /* 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", IPS_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", IPS_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", IPS_XFORM_NAME(tdbp), sa_len ? sa : " (error)"); ipsec_sa_delchain(tdbp); spin_unlock(&tdb_lock); stats->tx_errors++; goto cleanup; } /* * if this is the first time we are using this SA, mark start time, * and offset hard/soft counters by "now" for later checking. */#if 0 if(tdbp->ips_life.ipl_usetime.count == 0) { tdbp->ips_life.ipl_usetime.count = jiffies; tdbp->ips_life.ipl_usetime.hard += jiffies; tdbp->ips_life.ipl_usetime.soft += jiffies; }#endif if(ipsec_lifetime_check(&tdbp->ips_life.ipl_bytes, "bytes", sa, ipsec_life_countbased, ipsec_outgoing, tdbp) == ipsec_life_harddied || ipsec_lifetime_check(&tdbp->ips_life.ipl_addtime, "addtime",sa, ipsec_life_timebased, ipsec_outgoing, tdbp) == ipsec_life_harddied || ipsec_lifetime_check(&tdbp->ips_life.ipl_usetime, "usetime",sa, ipsec_life_timebased, ipsec_outgoing, tdbp) == ipsec_life_harddied || ipsec_lifetime_check(&tdbp->ips_life.ipl_packets, "packets",sa, ipsec_life_countbased, ipsec_outgoing, tdbp) == ipsec_life_harddied) { ipsec_sa_delchain(tdbp); spin_unlock(&tdb_lock); stats->tx_errors++; goto cleanup; } 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", 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: 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; } //padLength域及nextHeader域,1个byte //最长不超过32个字节 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); } //对于AH+ESP tunnelmode的包来说, //max_headroom = 20(IPIP)+24(AH)+16(ESP) = 60 bytes 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, 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 && prv->mtu < ntohs(iph->tot_len) && (iph->frag_off & __constant_htons(IP_DF)) ) { int notify = iph->protocol != IPPROTO_ICMP && (iph->frag_off & __constant_htons(IP_OFFSET)) == 0; #ifdef IPSEC_obey_DF 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_errors++; goto cleanup;#else /* IPSEC_obey_DF */ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT, "klips_debug:ipsec_tunnel_start_xmit: " "fragmentation needed and DF set; %spassing packet\n", notify ? "sending ICMP and " : ""); if (notify) ICMP_SEND(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -