📄 ipsec_rcv.c
字号:
break; default: tdbp->tdb_alg_errs += 1; spin_unlock(&tdb_lock); if(stats) { stats->rx_errors++; } goto rcvleave; } idat += esphlen; ilen -= esphlen; switch(tdbp->tdb_encalg) { case ESP_3DES: if ((ilen) % 8) { tdbp->tdb_encsize_errs += 1; spin_unlock(&tdb_lock); printk("klips_error:ipsec_rcv: " "got packet with esplen = %d from %s -- should be on 8 octet boundary, packet dropped\n", ilen, ipaddr_txt); if(stats) { stats->rx_errors++; } goto rcvleave; } des_ede3_cbc_encrypt(idat, idat, ilen, tdbp->tdb_key_e, tdbp->tdb_key_e + sizeof(struct des_eks), tdbp->tdb_key_e + 2 * sizeof(struct des_eks), (caddr_t)iv, 0); break; } next_header = idat[ilen - 1]; padlen = idat[ilen - 2]; pad = padlen + 2 + authlen; { int badpad = 0; KLIPS_PRINT(debug_rcv & DB_RX_IPAD, "klips_debug:ipsec_rcv: " "padlen=%d, contents: 0x<offset>: 0x<value> 0x<value> ...\n", padlen); for (i = 1; i <= padlen; i++) { if((i % 16) == 1) { KLIPS_PRINT(debug_rcv & DB_RX_IPAD, "klips_debug: %02x:", i - 1); } KLIPS_PRINTMORE(debug_rcv & DB_RX_IPAD, " %02x", idat[ilen - 2 - padlen + i - 1]); if(i != idat[ilen - 2 - padlen + i - 1]) { badpad = 1; } if((i % 16) == 0) { KLIPS_PRINTMORE(debug_rcv & DB_RX_IPAD, "\n"); } } if((i % 16) != 1) { KLIPS_PRINTMORE(debug_rcv & DB_RX_IPAD, "\n"); } if(badpad) { KLIPS_PRINT(debug_rcv & DB_RX_IPAD, "klips_debug:ipsec_rcv: " "warning, decrypted packet from %s has bad padding\n", ipaddr_txt); KLIPS_PRINT(debug_rcv & DB_RX_IPAD, "klips_debug:ipsec_rcv: " "...may be bad decryption -- not dropped\n"); tdbp->tdb_encpad_errs += 1; } KLIPS_PRINT(debug_rcv & DB_RX_IPAD, "klips_debug:ipsec_rcv: " "packet decrypted from %s: next_header = %d, padding = %d\n", ipaddr_txt, next_header, pad - 2 - authlen); }#endif /* !CONFIG_IPSEC_ESP */#ifdef CONFIG_IPSEC_AH case IPPROTO_AH: break;#endif /* CONFIG_IPSEC_AH */ } /* * Discard the original IP header */ ipp->protocol = next_header; switch(proto) {#ifdef CONFIG_IPSEC_ESP case IPPROTO_ESP: ipp->tot_len = htons(ntohs(ipp->tot_len) - (esphlen + pad)); memmove((void *)(skb->data + esphlen), (void *)(skb->data), iphlen); if(skb->len < esphlen) { spin_unlock(&tdb_lock); printk(KERN_WARNING "klips_error:ipsec_rcv: " "tried to skb_pull esphlen=%d, %d available. This should never happen, please report.\n", esphlen, (int)(skb->len)); goto rcvleave; } skb_pull(skb, esphlen); KLIPS_PRINT(debug_rcv & DB_RX_PKTRX, "klips_debug:ipsec_rcv: " "trimming to %d.\n", len - esphlen - pad); if(pad + esphlen <= len) { skb_trim(skb, len - esphlen - pad); } else { spin_unlock(&tdb_lock); KLIPS_PRINT(debug_rcv & DB_RX_PKTRX, "klips_debug:ipsec_rcv: " "bogus packet, size is zero or negative, dropping.\n"); goto rcvleave; } break;#endif /* !CONFIG_IPSEC_ESP */#ifdef CONFIG_IPSEC_AH case IPPROTO_AH: ipp->tot_len = htons(ntohs(ipp->tot_len) - ahhlen); memmove((void *)(skb->data + ahhlen), (void *)(skb->data), iphlen); if(skb->len < ahhlen) { spin_unlock(&tdb_lock); printk(KERN_WARNING "klips_error:ipsec_rcv: " "tried to skb_pull ahhlen=%d, %d available. This should never happen, please report.\n", ahhlen, (int)(skb->len)); goto rcvleave; } skb_pull(skb, ahhlen); break;#endif /* CONFIG_IPSEC_AH */ } /* * Adjust pointers */ len = skb->len; dat = skb->data; #ifdef NET_21/* skb->h.ipiph=(struct iphdr *)skb->data; */ skb->nh.raw = skb->data; skb->h.raw = skb->nh.raw + (skb->nh.iph->ihl << 2); memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));#else /* NET_21 */ skb->h.iph=(struct iphdr *)skb->data; skb->ip_hdr=(struct iphdr *)skb->data; memset(skb->proto_priv, 0, sizeof(struct options));#endif /* NET_21 */ ipp = (struct iphdr *)dat; ipp->check = 0; ipp->check = ip_fast_csum((unsigned char *)dat, iphlen >> 2); KLIPS_PRINT(debug_rcv & DB_RX_PKTRX, "klips_debug:ipsec_rcv: " "after <%s%s%s>, SA:%s:\n", TDB_XFORM_NAME(tdbp), sa_len ? sa : " (error)"); KLIPS_IP_PRINT(debug_rcv & DB_RX_PKTRX, ipp); skb->protocol = htons(ETH_P_IP); skb->ip_summed = 0; tdbprev = tdbp; tdbnext = tdbp->tdb_inext; if(sysctl_ipsec_inbound_policy_check) { if(tdbnext) { if(tdbnext->tdb_onext != tdbp) { spin_unlock(&tdb_lock); KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv: " "SA:%s, backpolicy does not agree with fwdpolicy.\n", sa_len ? sa : " (error)"); if(stats) { stats->rx_dropped++; } goto rcvleave; } KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv: " "SA:%s, backpolicy agrees with fwdpolicy.\n", sa_len ? sa : " (error)"); if(!( (ipp->protocol == IPPROTO_AH ) || (ipp->protocol == IPPROTO_ESP ) || (ipp->protocol == IPPROTO_IPIP)#ifdef CONFIG_IPSEC_IPCOMP || (ipp->protocol == IPPROTO_COMP)#endif /* CONFIG_IPSEC_IPCOMP */ )) { spin_unlock(&tdb_lock); KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv: " "packet with incomplete policy dropped, last successful SA:%s.\n", sa_len ? sa : " (error)"); if(stats) { stats->rx_dropped++; } goto rcvleave; } KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv: " "SA:%s, Another IPSEC header to process.\n", sa_len ? sa : " (error)"); } else { KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv: " "No tdb_inext from this SA:%s.\n", sa_len ? sa : " (error)"); } }#ifdef CONFIG_IPSEC_IPCOMP /* update ipcomp ratio counters, even if no ipcomp packet is present */ if (tdbnext && tdbnext->tdb_said.proto == IPPROTO_COMP && ipp->protocol != IPPROTO_COMP) { tdbnext->tdb_comp_ratio_cbytes += ntohs(ipp->tot_len); tdbnext->tdb_comp_ratio_dbytes += ntohs(ipp->tot_len); }#endif /* CONFIG_IPSEC_IPCOMP */ tdbp->tdb_lifetime_bytes_c += len; if(!tdbp->tdb_lifetime_usetime_c) { tdbp->tdb_lifetime_usetime_c = jiffies / HZ; } tdbp->tdb_lifetime_usetime_l = jiffies / HZ; tdbp->tdb_lifetime_packets_c += 1; /* end decapsulation loop here */ } while( (ipp->protocol == IPPROTO_ESP ) || (ipp->protocol == IPPROTO_AH )#ifdef CONFIG_IPSEC_IPCOMP || (ipp->protocol == IPPROTO_COMP)#endif /* CONFIG_IPSEC_IPCOMP */ ); #ifdef CONFIG_IPSEC_IPCOMP if(tdbnext && tdbnext->tdb_said.proto == IPPROTO_COMP) { tdbprev = tdbp; tdbp = tdbnext; tdbnext = tdbp->tdb_inext; }#endif /* CONFIG_IPSEC_IPCOMP */ /* * XXX this needs to be locked from when it was first looked * up in the decapsulation loop. Perhaps it is better to put * the IPIP decap inside the loop. */ if(tdbnext) { tdbp = tdbnext; sa_len = satoa(tdbp->tdb_said, 0, sa, SATOA_BUF); if(ipp->protocol != IPPROTO_IPIP) { spin_unlock(&tdb_lock); KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv: " "SA:%s, Hey! How did this get through? Dropped.\n", sa_len ? sa : " (error)"); if(stats) { stats->rx_dropped++; } goto rcvleave; } if(sysctl_ipsec_inbound_policy_check) { if((tdbnext = tdbp->tdb_inext)) { char sa2[SATOA_BUF]; size_t sa_len2; sa_len2 = satoa(tdbnext->tdb_said, 0, sa2, SATOA_BUF); spin_unlock(&tdb_lock); KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv: " "unexpected SA:%s after IPIP SA:%s\n", sa_len2 ? sa2 : " (error)", sa_len ? sa : " (error)"); if(stats) { stats->rx_dropped++; } goto rcvleave; } if(ipp->saddr != ((struct sockaddr_in*)(tdbp->tdb_addr_s))->sin_addr.s_addr) { spin_unlock(&tdb_lock); ipaddr.s_addr = ipp->saddr; addrtoa(ipaddr, 0, ipaddr_txt, sizeof(ipaddr_txt)); KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv: " "SA:%s, src=%s of pkt does not agree with expected SA source address policy.\n", sa_len ? sa : " (error)", ipaddr_txt); if(stats) { stats->rx_dropped++; } goto rcvleave; } } /* * XXX this needs to be locked from when it was first looked * up in the decapsulation loop. Perhaps it is better to put * the IPIP decap inside the loop. */ tdbp->tdb_lifetime_bytes_c += len; if(!tdbp->tdb_lifetime_usetime_c) { tdbp->tdb_lifetime_usetime_c = jiffies / HZ; } tdbp->tdb_lifetime_usetime_l = jiffies / HZ; tdbp->tdb_lifetime_packets_c += 1; if(skb->len < iphlen) { spin_unlock(&tdb_lock); printk(KERN_WARNING "klips_debug:ipsec_rcv: " "tried to skb_pull iphlen=%d, %d available. This should never happen, please report.\n", iphlen, (int)(skb->len)); goto rcvleave; } skb_pull(skb, iphlen);#ifdef NET_21 ipp = (struct iphdr *)skb->nh.raw = skb->data; skb->h.raw = skb->nh.raw + (skb->nh.iph->ihl << 2); memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));#else /* NET_21 */ ipp = skb->ip_hdr = skb->h.iph = (struct iphdr *)skb->data; memset(skb->proto_priv, 0, sizeof(struct options));#endif /* NET_21 */ skb->protocol = htons(ETH_P_IP); skb->ip_summed = 0; KLIPS_PRINT(debug_rcv & DB_RX_PKTRX, "klips_debug:ipsec_rcv: " "IPIP tunnel stripped.\n"); KLIPS_IP_PRINT(debug_rcv & DB_RX_PKTRX, ipp); }#ifdef INBOUND_POLICY_CHECK_eroute /* Do *not* enable this without thoroughly checking spinlock issues first. In particular, nesting an eroute spinlock within a tdb spinlock could result in a deadlock. (Well, only on a SMP machine under 2.4?) */ /* * First things first -- look us up in the erouting tables. */ matcher.sen_len = sizeof (struct sockaddr_encap); matcher.sen_family = AF_ENCAP; matcher.sen_type = SENT_IP4; if(ipp->protocol == IPPROTO_IPIP) { struct iphdr *ipp2; ipp2 = (struct iphdr*) (((char*)ipp) + (ipp->ihl << 2)); matcher.sen_ip_src.s_addr = ipp2->saddr; matcher.sen_ip_dst.s_addr = ipp2->daddr; } else { matcher.sen_ip_src.s_addr = ipp->saddr; matcher.sen_ip_dst.s_addr = ipp->daddr; } /* * 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) { policy_said = er->er_said; policy_eaddr = er->er_eaddr; policy_emask = er->er_emask; er->er_count++; er->er_lasttime = jiffies/HZ; } spin_unlock(&eroute_lock); if(er) { /* * The spinlock is to prevent any other process from * accessing or deleting the tdb while we are using and * updating it. */ spin_lock(&tdb_lock); policy_tdb = gettdb(&policy_said); if (policy_tdb == NULL) { spin_unlock(&tdb_lock); KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv: " "no Tunnel Descriptor Block for SA%s: incoming packet with no policy SA, dropped.\n", sa_len ? sa : " (error)"); goto rcvleave; } sa_len = satoa(policy_said, 0, sa, SATOA_BUF); KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv: " "found policy Tunnel Descriptor Block -- SA:%s\n", sa_len ? sa : " (error)"); while(1) { if(policy_tdb->tdb_inext) { policy_tdb = policy_tdb->tdb_inext; } else { break; } } if(policy_tdb != tdbp) { spin_unlock(&tdb_lock); KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv: " "Tunnel Descriptor Block for SA%s: incoming packet with different policy SA, dropped.\n", sa_len ? sa : " (error)"); goto rcvleave; } /* spin_unlock(&tdb_lock); */ }#endif /* INBOUND_POLICY_CHECK_eroute */ spin_unlock(&tdb_lock);#ifdef NET_21 if(stats) { stats->rx_bytes += skb->len; } if(skb->dst) { dst_release(skb->dst); skb->dst = NULL; } skb->pkt_type = PACKET_HOST; if(hard_header_len && (skb->mac.raw != (skb->data - hard_header_len)) && (hard_header_len <= skb_headroom(skb))) { /* copy back original MAC header */ memmove(skb->data - hard_header_len, skb->mac.raw, hard_header_len); skb->mac.raw = skb->data - hard_header_len; }#endif /* NET_21 */#ifdef CONFIG_IPSEC_IPCOMP if(ipp->protocol == IPPROTO_COMP) { unsigned int flags = 0; if(sysctl_ipsec_inbound_policy_check) { KLIPS_PRINT(debug_rcv & DB_RX_PKTRX, "klips_debug:ipsec_rcv: " "inbound policy checking enabled, IPCOMP follows IPIP, dropped.\n"); if (stats) { stats->rx_errors++; } goto rcvleave; } /* XXX need a TDB for updating ratio counters but it is not following policy anyways so it is not a priority */ skb = skb_decompress(skb, NULL, &flags); if (!skb || flags) { KLIPS_PRINT(debug_rcv & DB_RX_PKTRX, "klips_debug:ipsec_rcv: " "skb_decompress() returned error flags: %d, dropped.\n", flags); if (stats) { stats->rx_errors++; } goto rcvleave; } }#endif /* CONFIG_IPSEC_IPCOMP */#ifdef SKB_RESET_NFCT nf_conntrack_put(skb->nfct); skb->nfct = NULL;#ifdef CONFIG_NETFILTER_DEBUG skb->nf_debug = 0;#endif /* CONFIG_NETFILTER_DEBUG */#endif /* SKB_RESET_NFCT */ KLIPS_PRINT(debug_rcv & DB_RX_PKTRX, "klips_debug:ipsec_rcv: " "netif_rx() called.\n"); netif_rx(skb); MOD_DEC_USE_COUNT; return(0); rcvleave: if(skb) {#ifdef NET_21 kfree_skb(skb);#else /* NET_21 */ kfree_skb(skb, FREE_WRITE);#endif /* NET_21 */ } MOD_DEC_USE_COUNT;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -