📄 ipsec_rcv.c
字号:
ipsec_lifetime_check(&irs->ipsp->ips_life.ipl_packets, "packets", irs->sa, ipsec_life_countbased, ipsec_incoming, irs->ipsp) == ipsec_life_harddied) { ipsec_sa_delchain(irs->ipsp); if(irs->stats) { irs->stats->rx_dropped++; } KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv_decap_once: " "decap (%d) failed lifetime check\n", proto); return IPSEC_RCV_LIFETIMEFAILED; }#ifdef CONFIG_KLIPS_NAT_TRAVERSAL 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; /** 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 policy (pluto has been informed).\n", irs->sa_len ? irs->sa : " (error)", irs->ipsaddr_txt, irs->natt_sport); if(irs->stats) { irs->stats->rx_dropped++; } ipsec_sa_put(newipsp); return IPSEC_RCV_FAILEDINBOUND; } }#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; } irs->ilen = irs->len - iphlen - 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; }#ifdef CONFIG_KLIPS_ALG if(irs->authfuncs || ixt_a) {#else if(irs->authfuncs) {#endif 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; 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; 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 *)dat, 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;}intipsec_rcv(struct sk_buff *skb#ifndef PROTO_HANDLER_SINGLE_PARM#ifdef NET_21 unsigned short xlen#else /* NET_21 */ struct net_device *dev, struct options *opt, __u32 daddr_unused, unsigned short xlen, __u32 saddr, int redo, struct inet_protocol *protocol#endif /* NET_21 */#endif /* PROTO_HANDLER_SINGLE_PARM */ ){#ifdef NET_21#ifdef CONFIG_KLIPS_DEBUG struct net_device *dev = skb->dev;#endif /* CONFIG_KLIPS_DEBUG */#endif /* NET_21 */ unsigned char protoc; struct iphdr *ipp; struct ipsec_sa *ipsp = NULL; struct net_device_stats *stats = NULL; /* This device's statistics */ struct net_device *ipsecdev = NULL, *prvdev; struct ipsecpriv *prv; char name[9]; int i; struct in_addr ipsaddr; struct in_addr ipdaddr; struct ipsec_sa* ipsnext = NULL; /* next SA towards inside of packet */ struct ipsec_rcv_state irs; /* Don't unlink in the middle of a turnaround */ KLIPS_INC_USE; memset(&irs, 0, sizeof(struct ipsec_rcv_state)); if (skb == NULL) { KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv: " "NULL skb passed in.\n"); goto rcvleave; } if (skb->data == NULL) { KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv: " "NULL skb->data passed in, packet is bogus, dropping.\n"); goto rcvleave; }#ifdef CONFIG_IPSEC_NAT_TRAVERSAL if (skb->sk && skb->nh.iph && skb->nh.iph->protocol==IPPROTO_UDP) { /** * Packet comes from udp_queue_rcv_skb so it is already defrag, * checksum verified, ... (ie safe to use) * * If the packet is not for us, return -1 and udp_queue_rcv_skb * will continue to handle it (do not kfree skb !!). */#ifdef NET_26#if 0 /* at this time, NAT-T is not supported on 2.6. */ struct udp_sock *us = udp_sk(skb->sk);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -