ipsec_rcv.c
来自「FREESWAN VPN源代码包」· C语言 代码 · 共 2,240 行 · 第 1/5 页
C
2,240 行
goto rcvleave; } memmove(skb->data + natt_len, skb->data, iphlen); skb_pull(skb, natt_len); /* update nh.iph */ ipp = skb->nh.iph = (struct iphdr *)skb->data; /* modify protocol */ ipp->protocol = IPPROTO_ESP; skb->sk = NULL; KLIPS_IP_PRINT(debug_rcv, skb->nh.iph); }#endif KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv: " "<<< Info -- "); KLIPS_PRINTMORE(debug_rcv && skb->dev, "skb->dev=%s ", skb->dev->name ? skb->dev->name : "NULL"); KLIPS_PRINTMORE(debug_rcv && dev, "dev=%s ", dev->name ? dev->name : "NULL"); KLIPS_PRINTMORE(debug_rcv, "\n"); KLIPS_PRINT(debug_rcv && !(skb->dev && dev && (skb->dev == dev)), "klips_debug:ipsec_rcv: " "Informational -- **if this happens, find out why** skb->dev:%s is not equal to dev:%s\n", skb->dev ? (skb->dev->name ? skb->dev->name : "NULL") : "NULL", dev ? (dev->name ? dev->name : "NULL") : "NULL"); protoc = ipp->protocol;#ifndef NET_21 if((!protocol) || (protocol->protocol != protoc)) { KLIPS_PRINT(debug_rcv & DB_RX_TDB, "klips_debug:ipsec_rcv: " "protocol arg is NULL or unequal to the packet contents, this is odd, using value in packet.\n"); }#endif /* !NET_21 */ if( (protoc != IPPROTO_AH) &&#ifdef CONFIG_IPSEC_IPCOMP_disabled_until_we_register_IPCOMP_HANDLER (protoc != IPPROTO_COMP) &&#endif /* CONFIG_IPSEC_IPCOMP */ (protoc != IPPROTO_ESP) ) { KLIPS_PRINT(debug_rcv & DB_RX_TDB, "klips_debug:ipsec_rcv: Why the hell is someone " "passing me a non-ipsec protocol = %d packet? -- dropped.\n", protoc); goto rcvleave; } if(skb->dev) { for(i = 0; i < IPSEC_NUM_IF; i++) { sprintf(name, "ipsec%d", i); if(!strcmp(name, skb->dev->name)) { prv = (struct ipsecpriv *)(skb->dev->priv); if(prv) { stats = (struct net_device_stats *) &(prv->mystats); } ipsecdev = skb->dev; KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv: " "Info -- pkt already proc'ed a group of ipsec headers, processing next group of ipsec headers.\n"); break; } if((ipsecdev = ipsec_dev_get(name)) == NULL) { KLIPS_PRINT(debug_rcv, "klips_error:ipsec_rcv: " "device %s does not exist\n", name); } prv = ipsecdev ? (struct ipsecpriv *)(ipsecdev->priv) : NULL; prvdev = prv ? (struct device *)(prv->dev) : NULL; #if 0 KLIPS_PRINT(debug_rcv && prvdev, "klips_debug:ipsec_rcv: " "physical device for device %s is %s\n", name, prvdev->name);#endif if(prvdev && skb->dev && !strcmp(prvdev->name, skb->dev->name)) { stats = prv ? ((struct net_device_stats *) &(prv->mystats)) : NULL; skb->dev = ipsecdev; KLIPS_PRINT(debug_rcv && prvdev, "klips_debug:ipsec_rcv: " "assigning packet ownership to virtual device %s from physical device %s.\n", name, prvdev->name); if(stats) { stats->rx_packets++; } break; } } } else { KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv: " "device supplied with skb is NULL\n"); } if(!stats) { ipsecdev = NULL; } KLIPS_PRINT((debug_rcv && !stats), "klips_error:ipsec_rcv: " "packet received from physical I/F (%s) not connected to ipsec I/F. Cannot record stats. May not have SA for decoding. Is IPSEC traffic expected on this I/F? Check routing.\n", skb->dev ? (skb->dev->name ? skb->dev->name : "NULL") : "NULL"); KLIPS_IP_PRINT(debug_rcv, ipp); /* begin decapsulating loop here */ do { authlen = 0;#ifdef CONFIG_IPSEC_ESP espp = NULL; esphlen = 0;#endif /* !CONFIG_IPSEC_ESP */#ifdef CONFIG_IPSEC_AH ahp = NULL; ahhlen = 0;#endif /* CONFIG_IPSEC_AH */#ifdef CONFIG_IPSEC_IPCOMP compp = NULL;#endif /* CONFIG_IPSEC_IPCOMP */ len = skb->len; dat = skb->data; ipp = (struct iphdr *)skb->data; proto = ipp->protocol; ipaddr.s_addr = ipp->saddr; addrtoa(ipaddr, 0, ipaddr_txt, sizeof(ipaddr_txt)); iphlen = ipp->ihl << 2; ipp->check = 0; /* we know the sum is good */ #ifdef CONFIG_IPSEC_ESP /* XXX this will need to be 8 for IPv6 */ if ((proto == IPPROTO_ESP) && ((len - iphlen) % 4)) { printk("klips_error:ipsec_rcv: " "got packet with content length = %d from %s -- should be on 4 octet boundary, packet dropped\n", len - iphlen, ipaddr_txt); if(stats) { stats->rx_errors++; } goto rcvleave; }#endif /* !CONFIG_IPSEC_ESP */ /* * Find tunnel control block and (indirectly) call the * appropriate tranform routine. The resulting sk_buf * is a valid IP packet ready to go through input processing. */ said.dst.s_addr = ipp->daddr; switch(proto) {#ifdef CONFIG_IPSEC_ESP case IPPROTO_ESP: if(skb->len < (hard_header_len + sizeof(struct iphdr) + sizeof(struct esp))) { KLIPS_PRINT(debug_rcv & DB_RX_INAU, "klips_debug:ipsec_rcv: " "runt esp packet of skb->len=%d received from %s, dropped.\n", skb->len, ipaddr_txt); if(stats) { stats->rx_errors++; } goto rcvleave; } espp = (struct esp *)(skb->data + iphlen); said.spi = espp->esp_spi; break;#endif /* !CONFIG_IPSEC_ESP */#ifdef CONFIG_IPSEC_AH case IPPROTO_AH: if((skb->len < (hard_header_len + sizeof(struct iphdr) + sizeof(struct ah))) || (skb->len < (hard_header_len + sizeof(struct iphdr) + ((ahp = (struct ah *) (skb->data + iphlen))->ah_hl << 2)))) { KLIPS_PRINT(debug_rcv & DB_RX_INAU, "klips_debug:ipsec_rcv: " "runt ah packet of skb->len=%d received from %s, dropped.\n", skb->len, ipaddr_txt); if(stats) { stats->rx_errors++; } goto rcvleave; } said.spi = ahp->ah_spi; break;#endif /* CONFIG_IPSEC_AH */#ifdef CONFIG_IPSEC_IPCOMP case IPPROTO_COMP: if(skb->len < (hard_header_len + sizeof(struct iphdr) + sizeof(struct ipcomphdr))) { KLIPS_PRINT(debug_rcv & DB_RX_INAU, "klips_debug:ipsec_rcv: " "runt comp packet of skb->len=%d received from %s, dropped.\n", skb->len, ipaddr_txt); if(stats) { stats->rx_errors++; } goto rcvleave; } compp = (struct ipcomphdr *)(skb->data + iphlen); said.spi = htonl((__u32)ntohs(compp->ipcomp_cpi)); break;#endif /* CONFIG_IPSEC_IPCOMP */ default: if(stats) { stats->rx_errors++; } goto rcvleave; } said.proto = proto; sa_len = satoa(said, 0, sa, SATOA_BUF); if(sa_len == 0) { strcpy(sa, "(error)"); } #ifdef CONFIG_IPSEC_AH if(proto == IPPROTO_AH) { ahhlen = (ahp->ah_hl << 2) + ((caddr_t)&(ahp->ah_rpl) - (caddr_t)ahp); next_header = ahp->ah_nh; if (ahhlen != sizeof(struct ah)) { KLIPS_PRINT(debug_rcv & DB_RX_INAU, "klips_debug:ipsec_rcv: " "bad authenticator length %d, expected %d from %s.\n", ahhlen - ((caddr_t)(ahp->ah_data) - (caddr_t)ahp), AHHMAC_HASHLEN, ipaddr_txt); if(stats) { stats->rx_errors++; } goto rcvleave; } }#endif /* CONFIG_IPSEC_AH */ /* 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. */ if(tdbprev == NULL) { spin_lock(&tdb_lock); } #ifdef CONFIG_IPSEC_IPCOMP if (proto == IPPROTO_COMP) { unsigned int flags = 0; if (tdbp == NULL) { spin_unlock(&tdb_lock); KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv: " "Incoming packet with outer IPCOMP header SA:%s: not yet supported by KLIPS, dropped\n", sa_len ? sa : " (error)"); if(stats) { stats->rx_dropped++; } goto rcvleave; } tdbprev = tdbp; tdbp = tdbnext; if(sysctl_ipsec_inbound_policy_check && ((tdbp == NULL) || (((ntohl(tdbp->tdb_said.spi) & 0x0000ffff) != ntohl(said.spi)) /* next line is a workaround for peer non-compliance with rfc2393 */ && (tdbp->tdb_encalg != ntohl(said.spi)) ))) { char sa2[SATOA_BUF]; size_t sa_len2 = 0; if(tdbp) { sa_len2 = satoa(tdbp->tdb_said, 0, sa2, SATOA_BUF); } KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv: " "Incoming packet with SA(IPCA):%s does not match policy SA(IPCA):%s cpi=%04x cpi->spi=%08x spi=%08x, spi->cpi=%04x for SA grouping, dropped.\n", sa_len ? sa : " (error)", tdbp ? (sa_len2 ? sa2 : " (error)") : "NULL", ntohs(compp->ipcomp_cpi), (__u32)ntohl(said.spi), tdbp ? (__u32)ntohl((tdbp->tdb_said.spi)) : 0, tdbp ? (__u16)(ntohl(tdbp->tdb_said.spi) & 0x0000ffff) : 0); spin_unlock(&tdb_lock); if(stats) { stats->rx_dropped++; } goto rcvleave; } if (tdbp) { tdbp->tdb_comp_ratio_cbytes += ntohs(ipp->tot_len); tdbnext = tdbp->tdb_inext; } next_header = compp->ipcomp_nh; skb = skb_decompress(skb, tdbp, &flags); if (!skb || flags) { spin_unlock(&tdb_lock); KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv: " "skb_decompress() returned error flags=%x, dropped.\n", flags); if (stats) { if (flags) stats->rx_errors++; else stats->rx_dropped++; } goto rcvleave; }#ifdef NET_21 ipp = skb->nh.iph;#else /* NET_21 */ ipp = skb->ip_hdr;#endif /* NET_21 */ if (tdbp) { tdbp->tdb_comp_ratio_dbytes += ntohs(ipp->tot_len); } KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv: " "packet decompressed SA(IPCA):%s cpi->spi=%08x spi=%08x, spi->cpi=%04x, nh=%d.\n", sa_len ? sa : " (error)", (__u32)ntohl(said.spi), tdbp ? (__u32)ntohl((tdbp->tdb_said.spi)) : 0, tdbp ? (__u16)(ntohl(tdbp->tdb_said.spi) & 0x0000ffff) : 0, next_header); KLIPS_IP_PRINT(debug_rcv & DB_RX_PKTRX, ipp); continue; /* Skip rest of stuff and decapsulate next inner packet, if any */ }#endif /* CONFIG_IPSEC_IPCOMP */ tdbp = ipsec_sa_getbyid(&said); if (tdbp == NULL) { spin_unlock(&tdb_lock); KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv: " "no Tunnel Descriptor Block for SA:%s: incoming packet with no SA dropped\n", sa_len ? sa : " (error)"); if(stats) { stats->rx_dropped++; } goto rcvleave; }#ifdef CONFIG_IPSEC_NAT_TRAVERSAL if ((natt_type) && ( (ipp->saddr != (((struct sockaddr_in*)(tdbp->tdb_addr_s))->sin_addr.s_addr)) || (natt_sport != tdbp->ips_natt_sport) )) { struct sockaddr sipaddr; /** Advertise NAT-T addr change to pluto **/ sipaddr.sa_family = AF_INET; ((struct sockaddr_in*)&sipaddr)->sin_addr.s_addr = ipp->saddr; ((struct sockaddr_in*)&sipaddr)->sin_port = htons(natt_sport); pfkey_nat_t_new_mapping(tdbp, &sipaddr, natt_sport); /** * Then allow or block packet depending on * sysctl_ipsec_inbound_policy_check. * * In all cases, pluto will update SA if new mapping is * accepted. */ if (sysctl_ipsec_inbound_policy_check) { 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:%u of pkt does not agree with expected " "SA source address policy (pluto has been informed).\n", sa_len ? sa : " (error)", ipaddr_txt, natt_sport); if(stats) { stats->rx_dropped++; } goto rcvleave; } }#endif if(sysctl_ipsec_inbound_policy_check) { 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; } 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 agrees with expected SA source address policy.\n", sa_len ? sa : " (error)", ipaddr_txt); if(tdbnext) { if(tdbnext != tdbp) { spin_unlock(&tdb_lock); KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv: " "unexpected SA:%s: does not agree with tdb->inext policy, dropped\n", sa_len ? sa : " (error)"); if(stats) { stats->rx_dropped++; } goto rcvleave; } KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv: " "SA:%s grouping from previous SA is OK.\n",
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?