📄 ipsec_rcv.c
字号:
/* * receive code * Copyright (C) 1996, 1997 John Ioannidis. * Copyright (C) 1998-2003 Richard Guy Briggs. * Copyright (C) 2004 Michael Richardson <mcr@xelerance.com> * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */char ipsec_rcv_c_version[] = "RCSID $Id: ipsec_rcv.c,v 1.156 2004/12/03 21:34:51 mcr Exp $";#include <linux/config.h>#include <linux/version.h>#define __NO_VERSION__#include <linux/module.h>#include <linux/kernel.h> /* printk() */#include "openswan/ipsec_param.h"#ifdef MALLOC_SLAB# include <linux/slab.h> /* kmalloc() */#else /* MALLOC_SLAB */# include <linux/malloc.h> /* kmalloc() */#endif /* MALLOC_SLAB */#include <linux/errno.h> /* error codes */#include <linux/types.h> /* size_t */#include <linux/interrupt.h> /* mark_bh */#include <linux/netdevice.h> /* struct device, and other headers */#include <linux/etherdevice.h> /* eth_type_trans */#include <linux/ip.h> /* struct iphdr */#include <net/tcp.h>#include <net/udp.h>#include <linux/skbuff.h>#include <openswan.h>#ifdef SPINLOCK# ifdef SPINLOCK_23# include <linux/spinlock.h> /* *lock* */# else /* SPINLOCK_23 */# include <asm/spinlock.h> /* *lock* */# endif /* SPINLOCK_23 */#endif /* SPINLOCK */#ifdef NET_21# include <asm/uaccess.h># include <linux/in6.h># define proto_priv cb#endif /* NET21 */#include <asm/checksum.h>#include <net/ip.h>#include "openswan/radij.h"#include "openswan/ipsec_encap.h"#include "openswan/ipsec_sa.h"#include "openswan/ipsec_radij.h"#include "openswan/ipsec_xform.h"#include "openswan/ipsec_tunnel.h"#include "openswan/ipsec_rcv.h"#include "openswan/ipsec_auth.h"#include "openswan/ipsec_esp.h"#ifdef CONFIG_KLIPS_AH#include "openswan/ipsec_ah.h"#endif /* CONFIG_KLIPS_AH */#ifdef CONFIG_KLIPS_IPCOMP#include "openswan/ipsec_ipcomp.h"#endif /* CONFIG_KLIPS_COMP */#include <pfkeyv2.h>#include <pfkey.h>#include "openswan/ipsec_proto.h"#include "openswan/ipsec_alg.h"#include "openswan/ipsec_kern24.h"#ifdef CONFIG_KLIPS_DEBUGint debug_rcv = 0;#endif /* CONFIG_KLIPS_DEBUG */int sysctl_ipsec_inbound_policy_check = 1;#ifdef CONFIG_KLIPS_NAT_TRAVERSAL#include <linux/udp.h>#endif/* This is a private use protocol, and AT&T should be ashamed. They should have * used protocol # 59, which is "no next header" instead of 0xFE. */#ifndef IPPROTO_ATT_HEARTBEAT#define IPPROTO_ATT_HEARTBEAT 0xFE#endif#ifdef CONFIG_KLIPS_DEBUGvoidipsec_dmp(char *s, caddr_t bb, int len){ int i; unsigned char *b = bb; printk(KERN_INFO "klips_debug:ipsec_tunnel_:dmp: " "at %s, len=%d:", s, len); for (i=0; i < len; i++) { if(!(i%16)){ printk("\nklips_debug: "); } printk(" %02x", *b++); } printk("\n");}#endif /* CONFIG_KLIPS_DEBUG *//* * Check-replay-window routine, adapted from the original * by J. Hughes, from draft-ietf-ipsec-esp-des-md5-03.txt * * This is a routine that implements a 64 packet window. This is intend- * ed on being an implementation sample. */DEBUG_NO_STATIC intipsec_checkreplaywindow(struct ipsec_sa*ipsp, __u32 seq){ __u32 diff; if (ipsp->ips_replaywin == 0) /* replay shut off */ return 1; if (seq == 0) return 0; /* first == 0 or wrapped */ /* new larger sequence number */ if (seq > ipsp->ips_replaywin_lastseq) { return 1; /* larger is good */ } diff = ipsp->ips_replaywin_lastseq - seq; /* too old or wrapped */ /* if wrapped, kill off SA? */ if (diff >= ipsp->ips_replaywin) { return 0; } /* this packet already seen */ if (ipsp->ips_replaywin_bitmap & (1 << diff)) return 0; return 1; /* out of order but good */}DEBUG_NO_STATIC intipsec_updatereplaywindow(struct ipsec_sa*ipsp, __u32 seq){ __u32 diff; if (ipsp->ips_replaywin == 0) /* replay shut off */ return 1; if (seq == 0) return 0; /* first == 0 or wrapped */ /* new larger sequence number */ if (seq > ipsp->ips_replaywin_lastseq) { diff = seq - ipsp->ips_replaywin_lastseq; /* In win, set bit for this pkt */ if (diff < ipsp->ips_replaywin) ipsp->ips_replaywin_bitmap = (ipsp->ips_replaywin_bitmap << diff) | 1; else /* This packet has way larger seq num */ ipsp->ips_replaywin_bitmap = 1; if(seq - ipsp->ips_replaywin_lastseq - 1 > ipsp->ips_replaywin_maxdiff) { ipsp->ips_replaywin_maxdiff = seq - ipsp->ips_replaywin_lastseq - 1; } ipsp->ips_replaywin_lastseq = seq; return 1; /* larger is good */ } diff = ipsp->ips_replaywin_lastseq - seq; /* too old or wrapped */ /* if wrapped, kill off SA? */ if (diff >= ipsp->ips_replaywin) {/* if(seq < 0.25*max && ipsp->ips_replaywin_lastseq > 0.75*max) { ipsec_sa_delchain(ipsp); }*/ return 0; } /* this packet already seen */ if (ipsp->ips_replaywin_bitmap & (1 << diff)) return 0; ipsp->ips_replaywin_bitmap |= (1 << diff); /* mark as seen */ return 1; /* out of order but good */}#ifdef CONFIG_KLIPS_AUTH_HMAC_MD5struct auth_alg ipsec_rcv_md5[]={ {osMD5Init, osMD5Update, osMD5Final, AHMD596_ALEN}};#endif /* CONFIG_KLIPS_AUTH_HMAC_MD5 */#ifdef CONFIG_KLIPS_AUTH_HMAC_SHA1struct auth_alg ipsec_rcv_sha1[]={ {SHA1Init, SHA1Update, SHA1Final, AHSHA196_ALEN}};#endif /* CONFIG_KLIPS_AUTH_HMAC_MD5 */enum ipsec_rcv_valueipsec_rcv_decap_once(struct ipsec_rcv_state *irs, struct xform_functions *proto_funcs){ int iphlen; unsigned char *dat; __u8 proto; struct in_addr ipsaddr; struct in_addr ipdaddr; int replay = 0; /* replay value in AH or ESP packet */ struct ipsec_sa* ipsnext = NULL; /* next SA towards inside of packet */ struct ipsec_sa *newipsp; struct iphdr *ipp; struct sk_buff *skb;#ifdef CONFIG_KLIPS_ALG struct ipsec_alg_auth *ixt_a=NULL;#endif /* CONFIG_KLIPS_ALG */ skb = irs->skb; irs->len = skb->len; dat = skb->data; ipp = irs->ipp; proto = ipp->protocol; 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)); iphlen = ipp->ihl << 2; irs->iphlen=iphlen; ipp->check = 0; /* we know the sum is good */ KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv_decap_once: " "decap (%d) from %s -> %s\n", proto, irs->ipsaddr_txt, irs->ipdaddr_txt); /* * 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. */ irs->said.dst.u.v4.sin_addr.s_addr = ipp->daddr; irs->said.dst.u.v4.sin_family = AF_INET; if(proto_funcs->rcv_checks) { enum ipsec_rcv_value retval = (*proto_funcs->rcv_checks)(irs, skb); if(retval < 0) { return retval; } } irs->said.proto = proto; irs->sa_len = satot(&irs->said, 0, irs->sa, sizeof(irs->sa)); if(irs->sa_len == 0) { strcpy(irs->sa, "(error)"); } newipsp = ipsec_sa_getbyid(&irs->said); if (newipsp == NULL) { KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv: " "no ipsec_sa for SA:%s: incoming packet with no SA dropped\n", irs->sa_len ? irs->sa : " (error)"); if(irs->stats) { irs->stats->rx_dropped++; } return IPSEC_RCV_SAIDNOTFOUND; } /* MCR - XXX this is bizarre. ipsec_sa_getbyid returned it, having incremented the refcount, * why in the world would we decrement it here? ipsec_sa_put(irs->ipsp);*/ /* incomplete */ /* If it is in larval state, drop the packet, we cannot process yet. */ if(newipsp->ips_state == SADB_SASTATE_LARVAL) { KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv: " "ipsec_sa in larval state, cannot be used yet, dropping packet.\n"); if(irs->stats) { irs->stats->rx_dropped++; } ipsec_sa_put(newipsp); return IPSEC_RCV_SAIDNOTLIVE; } if(newipsp->ips_state == SADB_SASTATE_DEAD) { KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv: " "ipsec_sa in dead state, cannot be used any more, dropping packet.\n"); if(irs->stats) { irs->stats->rx_dropped++; } ipsec_sa_put(newipsp); return IPSEC_RCV_SAIDNOTLIVE; } if(sysctl_ipsec_inbound_policy_check) { if(irs->ipp->saddr != ((struct sockaddr_in*)(newipsp->ips_addr_s))->sin_addr.s_addr) { KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv: " "SA:%s, src=%s of pkt does not agree with expected SA source address policy.\n", irs->sa_len ? irs->sa : " (error)", irs->ipsaddr_txt); if(irs->stats) { irs->stats->rx_dropped++; } ipsec_sa_put(newipsp); return IPSEC_RCV_FAILEDINBOUND; } KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv: " "SA:%s, src=%s of pkt agrees with expected SA source address policy.\n", irs->sa_len ? irs->sa : " (error)", irs->ipsaddr_txt); /* * at this point, we have looked up a new SA, and we want to make sure that if this * isn't the first SA in the list, that the previous SA actually points at this one. */ if(irs->ipsp) { if(irs->ipsp->ips_inext != newipsp) { KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv: " "unexpected SA:%s: does not agree with ips->inext policy, dropped\n", irs->sa_len ? irs->sa : " (error)"); if(irs->stats) { irs->stats->rx_dropped++; } ipsec_sa_put(newipsp); return IPSEC_RCV_FAILEDINBOUND; } KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv: " "SA:%s grouping from previous SA is OK.\n", irs->sa_len ? irs->sa : " (error)"); } else { KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv: " "SA:%s First SA in group.\n", irs->sa_len ? irs->sa : " (error)"); } /* * previously, at this point, we checked if the back pointer from the new SA that * we just found matched the back pointer. But, we won't do this check anymore, * because we want to be able to nest SAs */#ifdef CONFIG_KLIPS_NAT_TRAVERSAL KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv: " "natt_type=%u tdbp->ips_natt_type=%u : %s\n", irs->natt_type, newipsp->ips_natt_type, (irs->natt_type==newipsp->ips_natt_type)?"ok":"bad"); if (irs->natt_type != newipsp->ips_natt_type) { KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv: " "SA:%s does not agree with expected NAT-T policy.\n", irs->sa_len ? irs->sa : " (error)"); if(irs->stats) { irs->stats->rx_dropped++; } ipsec_sa_put(newipsp); return IPSEC_RCV_FAILEDINBOUND; }#endif } /* okay, SA checks out, so free any previous SA, and record a new one */ if(irs->ipsp) { ipsec_sa_put(irs->ipsp); } irs->ipsp=newipsp; /* note that the outer code will free the irs->ipsp if there is an error */ /* now check the lifetimes */ if(ipsec_lifetime_check(&irs->ipsp->ips_life.ipl_bytes, "bytes", irs->sa, ipsec_life_countbased, ipsec_incoming, irs->ipsp) == ipsec_life_harddied || ipsec_lifetime_check(&irs->ipsp->ips_life.ipl_addtime, "addtime", irs->sa, ipsec_life_timebased, ipsec_incoming, irs->ipsp) == ipsec_life_harddied || ipsec_lifetime_check(&irs->ipsp->ips_life.ipl_addtime, "usetime", irs->sa, ipsec_life_timebased, ipsec_incoming, irs->ipsp) == ipsec_life_harddied ||
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -