📄 ipsec_rcv.c
字号:
if ((irs->natt_type) && ( (irs->ipp->saddr != (((struct sockaddr_in*)(newipsp->ips_addr_s))->sin_addr.s_addr)) || (irs->natt_sport != newipsp->ips_natt_sport) )) { struct sockaddr sipaddr; struct sockaddr_in *psin = (struct sockaddr_in*)(newipsp->ips_addr_s); /** Advertise NAT-T addr change to pluto **/ sipaddr.sa_family = AF_INET; ((struct sockaddr_in*)&sipaddr)->sin_addr.s_addr = irs->ipp->saddr; ((struct sockaddr_in*)&sipaddr)->sin_port = htons(irs->natt_sport); pfkey_nat_t_new_mapping(newipsp, &sipaddr, irs->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) { KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv: " "SA:%s, src=%s:%u of pkt does not agree with expected " "SA source address [%08x:%u] (notifying pluto of change).\n", irs->sa_len ? irs->sa : " (error)", irs->ipsaddr_txt, irs->natt_sport, psin->sin_addr.s_addr, newipsp->ips_natt_sport); if(irs->stats) { irs->stats->rx_dropped++; } ipsec_sa_put(newipsp); return IPSEC_RCV_FAILEDINBOUND; } }#endif#endif irs->authfuncs=NULL; /* authenticate, if required */#ifdef CONFIG_KLIPS_ALG if ((ixt_a=irs->ipsp->ips_alg_auth)) { irs->authlen = AHHMAC_HASHLEN; irs->authfuncs = NULL; irs->ictx = NULL; irs->octx = NULL; irs->ictx_len = 0; irs->octx_len = 0; KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv: " "authalg=%d authlen=%d\n", irs->ipsp->ips_authalg, irs->authlen); } else#endif /* CONFIG_KLIPS_ALG */ switch(irs->ipsp->ips_authalg) {#ifdef CONFIG_KLIPS_AUTH_HMAC_MD5 case AH_MD5: irs->authlen = AHHMAC_HASHLEN; irs->authfuncs = ipsec_rcv_md5; irs->ictx = (void *)&((struct md5_ctx*)(irs->ipsp->ips_key_a))->ictx; irs->octx = (void *)&((struct md5_ctx*)(irs->ipsp->ips_key_a))->octx; irs->ictx_len = sizeof(((struct md5_ctx*)(irs->ipsp->ips_key_a))->ictx); irs->octx_len = sizeof(((struct md5_ctx*)(irs->ipsp->ips_key_a))->octx); break;#endif /* CONFIG_KLIPS_AUTH_HMAC_MD5 */#ifdef CONFIG_KLIPS_AUTH_HMAC_SHA1 case AH_SHA: irs->authlen = AHHMAC_HASHLEN; irs->authfuncs = ipsec_rcv_sha1; irs->ictx = (void *)&((struct sha1_ctx*)(irs->ipsp->ips_key_a))->ictx; irs->octx = (void *)&((struct sha1_ctx*)(irs->ipsp->ips_key_a))->octx; irs->ictx_len = sizeof(((struct sha1_ctx*)(irs->ipsp->ips_key_a))->ictx); irs->octx_len = sizeof(((struct sha1_ctx*)(irs->ipsp->ips_key_a))->octx); break;#endif /* CONFIG_KLIPS_AUTH_HMAC_SHA1 */ case AH_NONE: irs->authlen = 0; irs->authfuncs = NULL; irs->ictx = NULL; irs->octx = NULL; irs->ictx_len = 0; irs->octx_len = 0; break; default: irs->ipsp->ips_errs.ips_alg_errs += 1; if(irs->stats) { irs->stats->rx_errors++; } return IPSEC_RCV_BADAUTH; } /* ilen counts number of bytes in ESP portion */ irs->ilen = ((skb->data + skb->len) - skb->h.raw) - irs->authlen; if(irs->ilen <= 0) { KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv: " "runt %s packet with no data, dropping.\n", (proto == IPPROTO_ESP ? "esp" : "ah")); if(irs->stats) { irs->stats->rx_dropped++; } return IPSEC_RCV_BADLEN; } if(irs->authfuncs || ixt_a) { unsigned char *authenticator = NULL; if(proto_funcs->rcv_setup_auth) { enum ipsec_rcv_value retval = (*proto_funcs->rcv_setup_auth)(irs, skb, &replay, &authenticator); if(retval < 0) { return retval; } } if(!authenticator) { irs->ipsp->ips_errs.ips_auth_errs += 1; if(irs->stats) { irs->stats->rx_dropped++; } return IPSEC_RCV_BADAUTH; } if(!ipsec_checkreplaywindow(irs->ipsp, replay)) { irs->ipsp->ips_errs.ips_replaywin_errs += 1; KLIPS_PRINT(debug_rcv & DB_RX_REPLAY, "klips_debug:ipsec_rcv: " "duplicate frame from %s, packet dropped\n", irs->ipsaddr_txt); if(irs->stats) { irs->stats->rx_dropped++; } return IPSEC_RCV_REPLAYFAILED; } /* * verify authenticator */ KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv: " "encalg = %d, authalg = %d.\n", irs->ipsp->ips_encalg, irs->ipsp->ips_authalg); /* calculate authenticator */ if(proto_funcs->rcv_calc_auth == NULL) { return IPSEC_RCV_BADAUTH; } (*proto_funcs->rcv_calc_auth)(irs, skb); if (memcmp(irs->hash, authenticator, irs->authlen)) { irs->ipsp->ips_errs.ips_auth_errs += 1; KLIPS_PRINT(debug_rcv & DB_RX_INAU, "klips_debug:ipsec_rcv: " "auth failed on incoming packet from %s: hash=%08x%08x%08x auth=%08x%08x%08x, dropped\n", irs->ipsaddr_txt, ntohl(*(__u32*)&irs->hash[0]), ntohl(*(__u32*)&irs->hash[4]), ntohl(*(__u32*)&irs->hash[8]), ntohl(*(__u32*)authenticator), ntohl(*((__u32*)authenticator + 1)), ntohl(*((__u32*)authenticator + 2))); if(irs->stats) { irs->stats->rx_dropped++; } return IPSEC_RCV_AUTHFAILED; } else { KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv: " "authentication successful.\n"); } /* Crypto hygiene: clear memory used to calculate autheticator. * The length varies with the algorithm. */ memset(irs->hash, 0, irs->authlen); /* If the sequence number == 0, expire SA, it had rolled */ if(irs->ipsp->ips_replaywin && !replay /* !irs->ipsp->ips_replaywin_lastseq */) { ipsec_sa_delchain(irs->ipsp); KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv: " "replay window counter rolled, expiring SA.\n"); if(irs->stats) { irs->stats->rx_dropped++; } return IPSEC_RCV_REPLAYROLLED; } /* now update the replay counter */ if (!ipsec_updatereplaywindow(irs->ipsp, replay)) { irs->ipsp->ips_errs.ips_replaywin_errs += 1; KLIPS_PRINT(debug_rcv & DB_RX_REPLAY, "klips_debug:ipsec_rcv: " "duplicate frame from %s, packet dropped\n", irs->ipsaddr_txt); if(irs->stats) { irs->stats->rx_dropped++; } return IPSEC_RCV_REPLAYROLLED; } } if(proto_funcs->rcv_decrypt) { enum ipsec_rcv_value retval = (*proto_funcs->rcv_decrypt)(irs); if(retval != IPSEC_RCV_OK) { return retval; } } /* * Adjust pointers */ skb = irs->skb; irs->len = skb->len; ipp = irs->ipp = skb->nh.iph; iphlen = ipp->ihl<<2; skb->h.raw = skb->nh.raw + iphlen; /* zero any options that there might be */ memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); ipsaddr.s_addr = ipp->saddr; addrtoa(ipsaddr, 0, irs->ipsaddr_txt, sizeof(irs->ipsaddr_txt)); ipdaddr.s_addr = ipp->daddr; addrtoa(ipdaddr, 0, irs->ipdaddr_txt, sizeof(irs->ipdaddr_txt)); /* * Discard the original ESP/AH header */ ipp->protocol = irs->next_header; ipp->check = 0; /* NOTE: this will be included in checksum */ ipp->check = ip_fast_csum((unsigned char *)skb->nh.iph, iphlen >> 2); KLIPS_PRINT(debug_rcv & DB_RX_PKTRX, "klips_debug:ipsec_rcv: " "after <%s%s%s>, SA:%s:\n", IPS_XFORM_NAME(irs->ipsp), irs->sa_len ? irs->sa : " (error)"); KLIPS_IP_PRINT(debug_rcv & DB_RX_PKTRX, ipp); skb->protocol = htons(ETH_P_IP); skb->ip_summed = 0; ipsnext = irs->ipsp->ips_inext; if(sysctl_ipsec_inbound_policy_check) { if(ipsnext) { if( ipp->protocol != IPPROTO_AH && ipp->protocol != IPPROTO_ESP#ifdef CONFIG_KLIPS_IPCOMP && ipp->protocol != IPPROTO_COMP && (ipsnext->ips_said.proto != IPPROTO_COMP || ipsnext->ips_inext)#endif /* CONFIG_KLIPS_IPCOMP */ && ipp->protocol != IPPROTO_IPIP && ipp->protocol != IPPROTO_ATT_HEARTBEAT /* heartbeats to AT&T SIG/GIG */ ) { KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv: " "packet with incomplete policy dropped, last successful SA:%s.\n", irs->sa_len ? irs->sa : " (error)"); if(irs->stats) { irs->stats->rx_dropped++; } return IPSEC_RCV_FAILEDINBOUND; } KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv: " "SA:%s, Another IPSEC header to process.\n", irs->sa_len ? irs->sa : " (error)"); } else { KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv: " "No ips_inext from this SA:%s.\n", irs->sa_len ? irs->sa : " (error)"); } }#ifdef CONFIG_KLIPS_IPCOMP /* update ipcomp ratio counters, even if no ipcomp packet is present */ if (ipsnext && ipsnext->ips_said.proto == IPPROTO_COMP && ipp->protocol != IPPROTO_COMP) { ipsnext->ips_comp_ratio_cbytes += ntohs(ipp->tot_len); ipsnext->ips_comp_ratio_dbytes += ntohs(ipp->tot_len); }#endif /* CONFIG_KLIPS_IPCOMP */ irs->ipsp->ips_life.ipl_bytes.ipl_count += irs->len; irs->ipsp->ips_life.ipl_bytes.ipl_last = irs->len; if(!irs->ipsp->ips_life.ipl_usetime.ipl_count) { irs->ipsp->ips_life.ipl_usetime.ipl_count = jiffies / HZ; } irs->ipsp->ips_life.ipl_usetime.ipl_last = jiffies / HZ; irs->ipsp->ips_life.ipl_packets.ipl_count += 1;#ifdef CONFIG_NETFILTER if(proto == IPPROTO_ESP || proto == IPPROTO_AH) { skb->nfmark = (skb->nfmark & (~(IPsecSAref2NFmark(IPSEC_SA_REF_MASK)))) | IPsecSAref2NFmark(IPsecSA2SAref(irs->ipsp)); KLIPS_PRINT(debug_rcv & DB_RX_PKTRX, "klips_debug:ipsec_rcv: " "%s SA sets skb->nfmark=0x%x.\n", proto == IPPROTO_ESP ? "ESP" : "AH", (unsigned)skb->nfmark); }#endif /* CONFIG_NETFILTER */ return IPSEC_RCV_OK;}/* * core decapsulation loop for all protocols. * * the following things should be setup to enter this function. * * irs->stats == stats structure (or NULL) * irs->ipp = IP header. * irs->ipsp = NULL. * irs->ilen = 0; * irs->authlen = 0; * irs->authfuncs = NULL; * irs->skb = skb; * skb->nh.iph = ipp; * skb->h.raw = start of payload * */int ipsec_rcv_decap(struct ipsec_rcv_state *irs){ struct ipsec_sa *ipsp = NULL; struct ipsec_sa* ipsnext = NULL; struct in_addr ipsaddr; struct in_addr ipdaddr; struct iphdr *ipp; struct sk_buff *skb = NULL; /* begin decapsulating loop here */ /* 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); do { int decap_stat; struct xform_functions *proto_funcs; switch(irs->ipp->protocol) { case IPPROTO_ESP: proto_funcs = esp_xform_funcs; break; #ifdef CONFIG_KLIPS_AH case IPPROTO_AH: proto_funcs = ah_xform_funcs; break;#endif /* !CONFIG_KLIPS_AH */ #ifdef CONFIG_KLIPS_IPCOMP case IPPROTO_COMP: proto_funcs = ipcomp_xform_funcs; break;#endif /* !CONFIG_KLIPS_IPCOMP */ default: if(irs->stats) { irs->stats->rx_errors++; } decap_stat = IPSEC_RCV_BADPROTO; goto rcvleave; } decap_stat = ipsec_rcv_decap_once(irs, proto_funcs); if(decap_stat != IPSEC_RCV_OK) { spin_unlock(&tdb_lock); KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv: decap_once failed: %d\n", decap_stat); goto rcvleave; } /* end decapsulation loop here */ } while( (irs->ipp->protocol == IPPROTO_ESP ) || (irs->ipp->protocol == IPPROTO_AH )#ifdef CONFIG_KLIPS_IPCOMP || (irs->ipp->protocol == IPPROTO_COMP)#endif /* CONFIG_KLIPS_IPCOMP */ ); /* set up for decap loop */ ipp =irs->ipp; ipsp =irs->ipsp; ipsnext = ipsp->ips_inext; skb = irs->skb; /* if there is an IPCOMP, but we don't have an IPPROTO_COMP, * then we can just skip it */#ifdef CONFIG_KLIPS_IPCOMP if(ipsnext && ipsnext->ips_said.proto == IPPROTO_COMP) { ipsp = ipsnext; ipsnext = ipsp->ips_inext; }#endif /* CONFIG_KLIPS_IPCOMP */#ifdef CONFIG_IPSEC_NAT_TRAVERSAL if ((irs->natt_type) && (ipp->protocol != IPPROTO_IPIP)) { /** * NAT-Traversal and Transport Mode: * we need to correct TCP/UDP checksum * * If we've got NAT-OA, we can fix checksum without recalculation. */ __u32 natt_oa = ipsp->ips_natt_oa ? ((struct sockaddr_in*)(ipsp->ips_natt_oa))->sin_addr.s_addr : 0; __u16 pkt_len = skb->tail - (unsigned char *)ipp; __u16 data_len = pkt_len - (ipp->ihl << 2); switch (ipp->protocol) { case IPPROTO_TCP: if (data_len >= sizeof(struct tcphdr)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -