📄 ipsec_xmit.c
字号:
#ifdef NET_21 ixs->iph = ixs->skb->nh.iph;#else /* NET_21 */ ixs->iph = ixs->skb->ip_hdr;#endif /* NET_21 */ ixs->ipsp->ips_comp_ratio_cbytes += ntohs(ixs->iph->tot_len);#ifdef CONFIG_KLIPS_DEBUG if (debug_tunnel & DB_TN_CROUT) { if (old_tot_len > ntohs(ixs->iph->tot_len)) KLIPS_PRINT(debug_tunnel & DB_TN_CROUT, "klips_debug:ipsec_xmit_encap_once: " "packet shrunk from %d to %d bytes after compression, cpi=%04x (should be from spi=%08x, spi&0xffff=%04x.\n", old_tot_len, ntohs(ixs->iph->tot_len), ntohs(((struct ipcomphdr*)(((char*)ixs->iph) + ((ixs->iph->ihl) << 2)))->ipcomp_cpi), ntohl(ixs->ipsp->ips_said.spi), (__u16)(ntohl(ixs->ipsp->ips_said.spi) & 0x0000ffff)); else KLIPS_PRINT(debug_tunnel & DB_TN_CROUT, "klips_debug:ipsec_xmit_encap_once: " "packet did not compress (flags = %d).\n", flags); }#endif /* CONFIG_KLIPS_DEBUG */ } break;#endif /* CONFIG_KLIPS_IPCOMP */ default: ixs->stats->tx_errors++; return IPSEC_XMIT_BADPROTO; } #ifdef NET_21 ixs->skb->nh.raw = ixs->skb->data;#else /* NET_21 */ ixs->skb->ip_hdr = ixs->skb->h.iph = (struct iphdr *) ixs->skb->data;#endif /* NET_21 */ ixs->iph->check = 0; ixs->iph->check = ip_fast_csum((unsigned char *)ixs->iph, ixs->iph->ihl); KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_xmit_encap_once: " "after <%s%s%s>, SA:%s:\n", IPS_XFORM_NAME(ixs->ipsp), ixs->sa_len ? ixs->sa_txt : " (error)"); KLIPS_IP_PRINT(debug_tunnel & DB_TN_XMIT, ixs->iph); ixs->ipsp->ips_life.ipl_bytes.ipl_count += len; ixs->ipsp->ips_life.ipl_bytes.ipl_last = len; if(!ixs->ipsp->ips_life.ipl_usetime.ipl_count) { ixs->ipsp->ips_life.ipl_usetime.ipl_count = jiffies / HZ; } ixs->ipsp->ips_life.ipl_usetime.ipl_last = jiffies / HZ; ixs->ipsp->ips_life.ipl_packets.ipl_count++; ixs->ipsp = ixs->ipsp->ips_onext; return IPSEC_XMIT_OK;}/* * If the IP packet (iph) is a carrying TCP/UDP, then set the encaps * source and destination ports to those from the TCP/UDP header. */void ipsec_extract_ports(struct iphdr * iph, struct sockaddr_encap * er){ struct udphdr *udp; switch (iph->protocol) { case IPPROTO_UDP: case IPPROTO_TCP: /* * The ports are at the same offsets in a TCP and UDP * header so hack it ... */ udp = (struct udphdr*)(((char*)iph)+(iph->ihl<<2)); er->sen_sport = udp->source; er->sen_dport = udp->dest; break; default: er->sen_sport = 0; er->sen_dport = 0; break; }}/* * A TRAP eroute is installed and we want to replace it with a HOLD * eroute. */static int create_hold_eroute(struct eroute *origtrap, struct sk_buff * skb, struct iphdr * iph, uint32_t eroute_pid){ struct eroute hold_eroute; ip_said hold_said; struct sk_buff *first, *last; int error; first = last = NULL; memset((caddr_t)&hold_eroute, 0, sizeof(hold_eroute)); memset((caddr_t)&hold_said, 0, sizeof(hold_said)); hold_said.proto = IPPROTO_INT; hold_said.spi = htonl(SPI_HOLD); hold_said.dst.u.v4.sin_addr.s_addr = INADDR_ANY; hold_eroute.er_eaddr.sen_len = sizeof(struct sockaddr_encap); hold_eroute.er_emask.sen_len = sizeof(struct sockaddr_encap); hold_eroute.er_eaddr.sen_family = AF_ENCAP; hold_eroute.er_emask.sen_family = AF_ENCAP; hold_eroute.er_eaddr.sen_type = SENT_IP4; hold_eroute.er_emask.sen_type = 255; hold_eroute.er_eaddr.sen_ip_src.s_addr = iph->saddr; hold_eroute.er_eaddr.sen_ip_dst.s_addr = iph->daddr; hold_eroute.er_emask.sen_ip_src.s_addr = INADDR_BROADCAST; hold_eroute.er_emask.sen_ip_dst.s_addr = INADDR_BROADCAST; hold_eroute.er_emask.sen_sport = 0; hold_eroute.er_emask.sen_dport = 0; hold_eroute.er_pid = eroute_pid; hold_eroute.er_count = 0; hold_eroute.er_lasttime = jiffies/HZ; /* * if it wasn't captured by a wildcard, then don't record it as * a wildcard. */ if(origtrap->er_eaddr.sen_proto != 0) { hold_eroute.er_eaddr.sen_proto = iph->protocol; if((iph->protocol == IPPROTO_TCP || iph->protocol == IPPROTO_UDP) && (origtrap->er_eaddr.sen_sport != 0 || origtrap->er_eaddr.sen_dport != 0)) { if(origtrap->er_eaddr.sen_sport != 0) hold_eroute.er_emask.sen_sport = ~0; if(origtrap->er_eaddr.sen_dport != 0) hold_eroute.er_emask.sen_dport = ~0; ipsec_extract_ports(iph, &hold_eroute.er_eaddr); } }#ifdef CONFIG_KLIPS_DEBUG if (debug_pfkey) { char buf1[64], buf2[64]; subnettoa(hold_eroute.er_eaddr.sen_ip_src, hold_eroute.er_emask.sen_ip_src, 0, buf1, sizeof(buf1)); subnettoa(hold_eroute.er_eaddr.sen_ip_dst, hold_eroute.er_emask.sen_ip_dst, 0, buf2, sizeof(buf2)); KLIPS_PRINT(debug_pfkey, "klips_debug:ipsec_tunnel_start_xmit: " "calling breakeroute and makeroute for %s:%d->%s:%d %d HOLD eroute.\n", buf1, ntohs(hold_eroute.er_eaddr.sen_sport), buf2, ntohs(hold_eroute.er_eaddr.sen_dport), hold_eroute.er_eaddr.sen_proto); }#endif /* CONFIG_KLIPS_DEBUG */ if (ipsec_breakroute(&(hold_eroute.er_eaddr), &(hold_eroute.er_emask), &first, &last)) { KLIPS_PRINT(debug_pfkey, "klips_debug:ipsec_tunnel_start_xmit: " "HOLD breakeroute found nothing.\n"); } else { KLIPS_PRINT(debug_pfkey, "klips_debug:ipsec_tunnel_start_xmit: " "HOLD breakroute deleted %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u %u\n", NIPQUAD(hold_eroute.er_eaddr.sen_ip_src), ntohs(hold_eroute.er_eaddr.sen_sport), NIPQUAD(hold_eroute.er_eaddr.sen_ip_dst), ntohs(hold_eroute.er_eaddr.sen_dport), hold_eroute.er_eaddr.sen_proto); } if (first != NULL) kfree_skb(first); if (last != NULL) kfree_skb(last); error = ipsec_makeroute(&(hold_eroute.er_eaddr), &(hold_eroute.er_emask), hold_said, eroute_pid, skb, NULL, NULL); if (error) { KLIPS_PRINT(debug_pfkey, "klips_debug:ipsec_tunnel_start_xmit: " "HOLD makeroute returned %d, failed.\n", error); } else { KLIPS_PRINT(debug_pfkey, "klips_debug:ipsec_tunnel_start_xmit: " "HOLD makeroute call successful.\n"); } return (error == 0);}enum ipsec_xmit_valueipsec_xmit_encap_bundle(struct ipsec_xmit_state *ixs){#ifdef CONFIG_KLIPS_ALG struct ipsec_alg_enc *ixt_e = NULL; struct ipsec_alg_auth *ixt_a = NULL; int blocksize = 8;#endif /* CONFIG_KLIPS_ALG */ enum ipsec_xmit_value bundle_stat = IPSEC_XMIT_OK; ixs->newdst = ixs->orgdst = ixs->iph->daddr; ixs->newsrc = ixs->orgsrc = ixs->iph->saddr; ixs->orgedst = ixs->outgoing_said.dst.u.v4.sin_addr.s_addr; ixs->iphlen = ixs->iph->ihl << 2; ixs->pyldsz = ntohs(ixs->iph->tot_len) - ixs->iphlen; ixs->max_headroom = ixs->max_tailroom = 0; if (ixs->outgoing_said.proto == IPPROTO_INT) { switch (ntohl(ixs->outgoing_said.spi)) { case SPI_DROP: KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_xmit_encap_bundle: " "shunt SA of DROP or no eroute: dropping.\n"); ixs->stats->tx_dropped++; break; case SPI_REJECT: KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_xmit_encap_bundle: " "shunt SA of REJECT: notifying and dropping.\n"); ICMP_SEND(ixs->skb, ICMP_DEST_UNREACH, ICMP_PKT_FILTERED, 0, ixs->physdev); ixs->stats->tx_dropped++; break; case SPI_PASS:#ifdef NET_21 ixs->pass = 1;#endif /* NET_21 */ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_xmit_encap_bundle: " "PASS: calling dev_queue_xmit\n"); return IPSEC_XMIT_PASS; goto cleanup; case SPI_HOLD: KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_xmit_encap_bundle: " "shunt SA of HOLD: this does not make sense here, dropping.\n"); ixs->stats->tx_dropped++; break; case SPI_TRAP: case SPI_TRAPSUBNET: { struct sockaddr_in src, dst;#ifdef CONFIG_KLIPS_DEBUG char bufsrc[ADDRTOA_BUF], bufdst[ADDRTOA_BUF];#endif /* CONFIG_KLIPS_DEBUG */ /* Signal all listening KMds with a PF_KEY ACQUIRE */ src.sin_family = AF_INET; dst.sin_family = AF_INET; src.sin_addr.s_addr = ixs->iph->saddr; dst.sin_addr.s_addr = ixs->iph->daddr; ixs->ips.ips_transport_protocol = 0; src.sin_port = 0; dst.sin_port = 0; { int i; for(i = 0; i < sizeof(struct sockaddr_in) - offsetof(struct sockaddr_in, sin_zero); i++) { src.sin_zero[i] = 0; dst.sin_zero[i] = 0; } } if(ixs->eroute->er_eaddr.sen_proto != 0) { ixs->ips.ips_transport_protocol = ixs->iph->protocol; if(ixs->eroute->er_eaddr.sen_sport != 0) { src.sin_port = (ixs->iph->protocol == IPPROTO_UDP ? ((struct udphdr*) (((caddr_t)ixs->iph) + (ixs->iph->ihl << 2)))->source : (ixs->iph->protocol == IPPROTO_TCP ? ((struct tcphdr*)((caddr_t)ixs->iph + (ixs->iph->ihl << 2)))->source : 0)); } if(ixs->eroute->er_eaddr.sen_dport != 0) { dst.sin_port = (ixs->iph->protocol == IPPROTO_UDP ? ((struct udphdr*) (((caddr_t)ixs->iph) + (ixs->iph->ihl << 2)))->dest : (ixs->iph->protocol == IPPROTO_TCP ? ((struct tcphdr*)((caddr_t)ixs->iph + (ixs->iph->ihl << 2)))->dest : 0)); } } ixs->ips.ips_addr_s = (struct sockaddr*)(&src); ixs->ips.ips_addr_d = (struct sockaddr*)(&dst); KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_xmit_encap_bundle: " "SADB_ACQUIRE sent with src=%s:%d, dst=%s:%d, proto=%d.\n", addrtoa(((struct sockaddr_in*)(ixs->ips.ips_addr_s))->sin_addr, 0, bufsrc, sizeof(bufsrc)) <= ADDRTOA_BUF ? bufsrc : "BAD_ADDR", ntohs(((struct sockaddr_in*)(ixs->ips.ips_addr_s))->sin_port), addrtoa(((struct sockaddr_in*)(ixs->ips.ips_addr_d))->sin_addr, 0, bufdst, sizeof(bufdst)) <= ADDRTOA_BUF ? bufdst : "BAD_ADDR", ntohs(((struct sockaddr_in*)(ixs->ips.ips_addr_d))->sin_port), ixs->ips.ips_said.proto); /* increment count of total traps needed */ ipsec_xmit_trap_count++; if (pfkey_acquire(&ixs->ips) == 0) { /* note that we succeeded */ ipsec_xmit_trap_sendcount++; if (ixs->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); ixs->eroute = ipsec_findroute(&ixs->matcher); if(ixs->eroute) { ixs->eroute->er_said.spi = htonl(SPI_HOLD); ixs->eroute->er_first = ixs->skb; ixs->skb = NULL; } spin_unlock(&eroute_lock); } else if (create_hold_eroute(ixs->eroute, ixs->skb, ixs->iph, ixs->eroute_pid)) { ixs->skb = NULL; } /* whether or not the above succeeded, we continue */ } ixs->stats->tx_dropped++; } default: /* XXX what do we do with an unknown shunt spi? */ break; } /* switch (ntohl(ixs->outgoing_said.spi)) */ return IPSEC_XMIT_STOLEN; } /* if (ixs->outgoing_said.proto == IPPROTO_INT) */ /* The spinlock is to prevent any other process from accessing or deleting the ipsec_sa hash table or any of the ipsec_sa s 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 ipsec_sa instead. This is not likely to happen in KLIPS1 unless a volunteer contributes it, but will be designed into KLIPS2. */ spin_lock(&tdb_lock); ixs->ipsp = ipsec_sa_getbyid(&ixs->outgoing_said); ixs->sa_len = satot(&ixs->outgoing_said, 0, ixs->sa_txt, sizeof(ixs->sa_txt)); if (ixs->ipsp == NULL) { KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_xmit_encap_bundle: " "no ipsec_sa for SA%s: outgoing packet with no SA, dropped.\n", ixs->sa_len ? ixs->sa_txt : " (error)"); ixs->stats->tx_dropped++; bundle_stat = IPSEC_XMIT_SAIDNOTFOUND; goto cleanup; } ipsec_sa_put(ixs->ipsp); /* incomplete */ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_xmit_encap_bundle: " "found ipsec_sa -- SA:<%s%s%s> %s\n", IPS_XFORM_NAME(ixs->ipsp), ixs->sa_len ? ixs->sa_txt : " (error)"); /* * How much headroom do we need to be able to apply * all the grouped transforms? */ ixs->ipsq = ixs->ipsp; /* save the head of the ipsec_sa chain */ while (ixs->ipsp) { ixs->sa_len = satot(&ixs->ipsp->ips_said, 0, ixs->sa_txt, sizeof(ixs->sa_txt)); if(ixs->sa_len == 0) { strcpy(ixs->sa_txt, "(error)"); } /* If it is in larval state, drop the packet, we cannot process yet. */ if(ixs->ipsp->ips_state == SADB_SASTATE_LARVAL) { KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_xmit_encap_bundle: " "ipsec_sa in larval state for SA:<%s%s%s> %s, cannot be used yet, dropping packet.\n", IPS_XFORM_NAME(ixs->ipsp), ixs->sa_len ? ixs->sa_txt : " (error)"); ixs->stats->tx_errors++; bundle_stat = IPSEC_XMIT_SAIDNOTLIVE; goto cleanup; } if(ixs->ipsp->ips_state == SADB_SASTATE_DEAD) { KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_xmit_encap_bundle: " "ipsec_sa in dead state for SA:<%s%s%s> %s, can no longer be used, dropping packet.\n", IPS_XFORM_NAME(ixs->ipsp), ixs->sa_len ? ixs->sa_txt : " (error)"); ixs->stats->tx_errors++; bundle_stat = IPSEC_XMIT_SAIDNOTLIVE; goto cleanup; } /* If the replay window counter == -1, expire SA, it will roll */ if(ixs->ipsp->ips_replaywin && ixs->ipsp->ips_replaywin_lastseq == -1) { pfkey_expire(ixs->ipsp, 1); KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_xmit_encap_bundle: " "replay window counter rolled for SA:<%s%s%s> %s, packet dropped, expiring SA.\n", IPS_XFORM_NAME(ixs->ipsp), ixs->sa_len ? ixs->sa_txt : " (error)"); ipsec_sa_delchain(ixs->ipsp); ixs->stats->tx_errors++; bundle_stat = IPSEC_XMIT_REPLAYROLLED; 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(ixs->ipsp->ips_life.ipl_usetime.count == 0) { ixs->ipsp->ips_life.ipl_usetime.count = jiffies; ixs->ipsp->ips_life.ipl_usetime.hard += jiffies; ixs->ipsp->ips_life.ipl_usetime.soft += jiffies; }#endif if(ipsec_lifetime_check(&ixs->ipsp->ips_life.ipl_bytes, "bytes", ixs->sa_txt, ipsec_life_countbased, ipsec_outgoing, ixs->ipsp) == ipsec_life_harddied || ipsec_lifetime_check(&ixs->ipsp->ips_life.ipl_addtime, "addtime",ixs->sa_txt, ipsec_life_timebased, ipsec_outgoing, ixs->ipsp) == ipsec_life_harddied || ipsec_lifetime_check(&ixs->ipsp->ips_life.ipl_usetime, "usetime",ixs->sa_txt, ipsec_life_timebased, ipsec_outgoing, ixs->ipsp) == ipsec_life_harddied || ipsec_lifetime_check(&ixs->ipsp->ips_life.ipl_packets, "packets",ixs->sa_txt, ipsec_life_countbased, ipsec_outgoing, ixs->ipsp) == ipsec_life_harddied) { ipsec_sa_delchain(ixs->ipsp); ixs->stats->tx_errors++; bundle_stat = IPSEC_XMIT_LIFETIMEFAILED; goto cleanup; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -