diff options
Diffstat (limited to 'linux/net/ipsec/ipsec_rcv.c')
-rw-r--r-- | linux/net/ipsec/ipsec_rcv.c | 2204 |
1 files changed, 0 insertions, 2204 deletions
diff --git a/linux/net/ipsec/ipsec_rcv.c b/linux/net/ipsec/ipsec_rcv.c deleted file mode 100644 index 4df839fe2..000000000 --- a/linux/net/ipsec/ipsec_rcv.c +++ /dev/null @@ -1,2204 +0,0 @@ -/* - * receive code - * Copyright (C) 1996, 1997 John Ioannidis. - * Copyright (C) 1998, 1999, 2000, 2001 Richard Guy Briggs. - * - * 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.5 2005/04/10 21:38:32 as Exp $"; - -#include <linux/config.h> -#include <linux/version.h> - -#define __NO_VERSION__ -#include <linux/module.h> -#include <linux/kernel.h> /* printk() */ - -#include "freeswan/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 <linux/skbuff.h> -#include <freeswan.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 "freeswan/radij.h" -#include "freeswan/ipsec_encap.h" -#include "freeswan/ipsec_sa.h" - -#include "freeswan/ipsec_radij.h" -#include "freeswan/ipsec_xform.h" -#include "freeswan/ipsec_tunnel.h" -#include "freeswan/ipsec_rcv.h" - -#if defined(CONFIG_IPSEC_ESP) || defined(CONFIG_IPSEC_AH) -#include "freeswan/ipsec_ah.h" -#endif /* defined(CONFIG_IPSEC_ESP) || defined(CONFIG_IPSEC_AH) */ - -#ifdef CONFIG_IPSEC_ESP -#include "freeswan/ipsec_esp.h" -#endif /* !CONFIG_IPSEC_ESP */ - -#ifdef CONFIG_IPSEC_IPCOMP -#include "freeswan/ipcomp.h" -#endif /* CONFIG_IPSEC_COMP */ - -#include <pfkeyv2.h> -#include <pfkey.h> - -#include "freeswan/ipsec_proto.h" -#include "freeswan/ipsec_alg.h" - -#ifdef CONFIG_IPSEC_DEBUG -int debug_ah = 0; -int debug_esp = 0; -int debug_rcv = 0; -#endif /* CONFIG_IPSEC_DEBUG */ - -int sysctl_ipsec_inbound_policy_check = 1; - -#ifdef CONFIG_IPSEC_NAT_TRAVERSAL -#include <linux/udp.h> -#endif - -#ifdef CONFIG_IPSEC_DEBUG -static void -rcv_dmp(char *s, caddr_t bb, int len) -{ - int i; - unsigned char *b = bb; - - if (debug_rcv && sysctl_ipsec_debug_verbose) { - 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"); - } -} -#else /* CONFIG_IPSEC_DEBUG */ -#define rcv_dmp(_x, _y, _z) -#endif /* CONFIG_IPSEC_DEBUG */ - - -#if defined(CONFIG_IPSEC_ESP) || defined(CONFIG_IPSEC_AH) -__u32 zeroes[AH_AMAX]; -#endif /* defined(CONFIG_IPSEC_ESP) || defined(CONFIG_IPSEC_AH) */ - -/* - * 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 int -ipsec_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 int -ipsec_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_IPSEC_AUTH_HMAC_MD5 -struct auth_alg ipsec_rcv_md5[]={ - {MD5Init, MD5Update, MD5Final, AHMD596_ALEN} -}; - -#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */ - -#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1 -struct auth_alg ipsec_rcv_sha1[]={ - {SHA1Init, SHA1Update, SHA1Final, AHSHA196_ALEN} -}; -#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */ - -enum ipsec_rcv_value { - IPSEC_RCV_LASTPROTO=1, - IPSEC_RCV_OK=0, - IPSEC_RCV_BADPROTO=-1, - IPSEC_RCV_BADLEN=-2, - IPSEC_RCV_ESP_BADALG=-3, - IPSEC_RCV_3DES_BADBLOCKING=-4, - IPSEC_RCV_ESP_DECAPFAIL=-5, - IPSEC_RCV_DECAPFAIL=-6, - IPSEC_RCV_SAIDNOTFOUND=-7, - IPSEC_RCV_IPCOMPALONE=-8, - IPSEC_RCV_IPCOMPFAILED=-10, - IPSEC_RCV_SAIDNOTLIVE=-11, - IPSEC_RCV_FAILEDINBOUND=-12, - IPSEC_RCV_LIFETIMEFAILED=-13, - IPSEC_RCV_BADAUTH=-14, - IPSEC_RCV_REPLAYFAILED=-15, - IPSEC_RCV_AUTHFAILED=-16, - IPSEC_RCV_REPLAYROLLED=-17, - IPSEC_RCV_BAD_DECRYPT=-18 -}; - -struct ipsec_rcv_state { - struct sk_buff *skb; - struct net_device_stats *stats; - struct iphdr *ipp; - struct ipsec_sa *ipsp; - int len; - int ilen; - int authlen; - int hard_header_len; - int iphlen; - struct auth_alg *authfuncs; - struct sa_id said; - char sa[SATOA_BUF]; - size_t sa_len; - __u8 next_header; - __u8 hash[AH_AMAX]; - char ipsaddr_txt[ADDRTOA_BUF]; - char ipdaddr_txt[ADDRTOA_BUF]; - __u8 *octx; - __u8 *ictx; - int ictx_len; - int octx_len; - union { - struct { - struct esphdr *espp; - } espstuff; - struct { - struct ahhdr *ahp; - } ahstuff; - struct { - struct ipcomphdr *compp; - } ipcompstuff; - } protostuff; -#ifdef CONFIG_IPSEC_NAT_TRAVERSAL - __u16 natt_len; - __u16 natt_sport; - __u16 natt_dport; - __u8 natt_type; -#endif -}; - -struct xform_functions { - enum ipsec_rcv_value (*checks)(struct ipsec_rcv_state *irs, - struct sk_buff *skb); - enum ipsec_rcv_value (*decrypt)(struct ipsec_rcv_state *irs); - - enum ipsec_rcv_value (*setup_auth)(struct ipsec_rcv_state *irs, - struct sk_buff *skb, - __u32 *replay, - unsigned char **authenticator); - enum ipsec_rcv_value (*calc_auth)(struct ipsec_rcv_state *irs, - struct sk_buff *skb); -}; - -#ifdef CONFIG_IPSEC_ESP -enum ipsec_rcv_value -ipsec_rcv_esp_checks(struct ipsec_rcv_state *irs, - struct sk_buff *skb) -{ - __u8 proto; - int len; /* packet length */ - - len = skb->len; - proto = irs->ipp->protocol; - - /* XXX this will need to be 8 for IPv6 */ - if ((proto == IPPROTO_ESP) && ((len - irs->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 - irs->iphlen, - irs->ipsaddr_txt); - if(irs->stats) { - irs->stats->rx_errors++; - } - return IPSEC_RCV_BADLEN; - } - - if(skb->len < (irs->hard_header_len + sizeof(struct iphdr) + sizeof(struct esphdr))) { - 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, - irs->ipsaddr_txt); - if(irs->stats) { - irs->stats->rx_errors++; - } - return IPSEC_RCV_BADLEN; - } - - irs->protostuff.espstuff.espp = (struct esphdr *)(skb->data + irs->iphlen); - irs->said.spi = irs->protostuff.espstuff.espp->esp_spi; - - return IPSEC_RCV_OK; -} - -enum ipsec_rcv_value -ipsec_rcv_esp_decrypt_setup(struct ipsec_rcv_state *irs, - struct sk_buff *skb, - __u32 *replay, - unsigned char **authenticator) -{ - struct esphdr *espp = irs->protostuff.espstuff.espp; - - KLIPS_PRINT(debug_rcv, - "klips_debug:ipsec_rcv: " - "packet from %s received with seq=%d (iv)=0x%08x%08x iplen=%d esplen=%d sa=%s\n", - irs->ipsaddr_txt, - (__u32)ntohl(espp->esp_rpl), - (__u32)ntohl(*((__u32 *)(espp->esp_iv) )), - (__u32)ntohl(*((__u32 *)(espp->esp_iv) + 1)), - irs->len, - irs->ilen, - irs->sa_len ? irs->sa : " (error)"); - - *replay = ntohl(espp->esp_rpl); - *authenticator = &(skb->data[irs->len - irs->authlen]); - - return IPSEC_RCV_OK; -} - -enum ipsec_rcv_value -ipsec_rcv_esp_authcalc(struct ipsec_rcv_state *irs, - struct sk_buff *skb) -{ - struct auth_alg *aa; - struct esphdr *espp = irs->protostuff.espstuff.espp; - union { - MD5_CTX md5; - SHA1_CTX sha1; - } tctx; - -#ifdef CONFIG_IPSEC_ALG - if (irs->ipsp->ips_alg_auth) { - KLIPS_PRINT(debug_rcv, - "klips_debug:ipsec_rcv: " - "ipsec_alg hashing proto=%d... ", - irs->said.proto); - if(irs->said.proto == IPPROTO_ESP) { - ipsec_alg_sa_esp_hash(irs->ipsp, - (caddr_t)espp, irs->ilen, - irs->hash, AHHMAC_HASHLEN); - return IPSEC_RCV_OK; - } - return IPSEC_RCV_BADPROTO; - } -#endif - aa = irs->authfuncs; - - /* copy the initialized keying material */ - memcpy(&tctx, irs->ictx, irs->ictx_len); - - (*aa->update)((void *)&tctx, (caddr_t)espp, irs->ilen); - - (*aa->final)(irs->hash, (void *)&tctx); - - memcpy(&tctx, irs->octx, irs->octx_len); - - (*aa->update)((void *)&tctx, irs->hash, aa->hashlen); - (*aa->final)(irs->hash, (void *)&tctx); - - return IPSEC_RCV_OK; -} - - -enum ipsec_rcv_value -ipsec_rcv_esp_decrypt(struct ipsec_rcv_state *irs) -{ - struct ipsec_sa *ipsp = irs->ipsp; - struct esphdr *espp = irs->protostuff.espstuff.espp; - int esphlen = 0; - __u8 *idat; /* pointer to content to be decrypted/authenticated */ -#ifdef CONFIG_IPSEC_ENC_3DES - __u32 iv[2]; -#endif /* !CONFIG_IPSEC_ENC_3DES */ - int pad = 0, padlen; - int badpad = 0; - int i; - struct sk_buff *skb; -#ifdef CONFIG_IPSEC_ALG - struct ipsec_alg_enc *ixt_e=NULL; -#endif /* CONFIG_IPSEC_ALG */ - - skb=irs->skb; - - idat = skb->data + irs->iphlen; - -#ifdef CONFIG_IPSEC_ALG - if ((ixt_e=ipsp->ips_alg_enc)) { - esphlen = ESP_HEADER_LEN + ixt_e->ixt_ivlen/8; - KLIPS_PRINT(debug_rcv, - "klips_debug:ipsec_rcv: " - "encalg=%d esphlen=%d\n", - ipsp->ips_encalg, esphlen); - } else -#endif /* CONFIG_IPSEC_ALG */ - switch(ipsp->ips_encalg) { -#ifdef CONFIG_IPSEC_ENC_3DES - case ESP_3DES: - iv[0] = *((__u32 *)(espp->esp_iv) ); - iv[1] = *((__u32 *)(espp->esp_iv) + 1); - esphlen = sizeof(struct esphdr); - break; -#endif /* !CONFIG_IPSEC_ENC_3DES */ - default: - ipsp->ips_errs.ips_alg_errs += 1; - if(irs->stats) { - irs->stats->rx_errors++; - } - return IPSEC_RCV_ESP_BADALG; - } - - idat += esphlen; - irs->ilen -= esphlen; - -#ifdef CONFIG_IPSEC_ALG - if (ixt_e) - { - if (ipsec_alg_esp_encrypt(ipsp, - idat, irs->ilen, espp->esp_iv, - IPSEC_ALG_DECRYPT) <= 0) - { - printk("klips_error:ipsec_rcv: " - "got packet with esplen = %d " - "from %s -- should be on " - "ENC(%d) octet boundary, " - "packet dropped\n", - irs->ilen, - irs->ipsaddr_txt, - ipsp->ips_encalg); - if(irs->stats) { - irs->stats->rx_errors++; - } - return IPSEC_RCV_BAD_DECRYPT; - } - } else -#endif /* CONFIG_IPSEC_ALG */ - switch(ipsp->ips_encalg) { -#ifdef CONFIG_IPSEC_ENC_3DES - case ESP_3DES: - if ((irs->ilen) % 8) { - ipsp->ips_errs.ips_encsize_errs += 1; - printk("klips_error:ipsec_rcv: " - "got packet with esplen = %d from %s -- should be on 8 octet boundary, packet dropped\n", - irs->ilen, - irs->ipsaddr_txt); - if(irs->stats) { - irs->stats->rx_errors++; - } - return IPSEC_RCV_3DES_BADBLOCKING; - } - des_ede3_cbc_encrypt((des_cblock *)idat, - (des_cblock *)idat, - irs->ilen, - ((struct des_eks *)(ipsp->ips_key_e))[0].ks, - ((struct des_eks *)(ipsp->ips_key_e))[1].ks, - ((struct des_eks *)(ipsp->ips_key_e))[2].ks, - (des_cblock *)iv, 0); - break; -#endif /* !CONFIG_IPSEC_ENC_3DES */ - } - - rcv_dmp("postdecrypt", skb->data, skb->len); - - irs->next_header = idat[irs->ilen - 1]; - padlen = idat[irs->ilen - 2]; - pad = padlen + 2 + irs->authlen; - - KLIPS_PRINT(debug_rcv & DB_RX_IPAD, - "klips_debug:ipsec_rcv: " - "padlen=%d, contents: 0x<offset>: 0x<value> 0x<value> ...\n", - padlen); - - for (i = 1; i <= padlen; i++) { - if((i % 16) == 1) { - KLIPS_PRINT(debug_rcv & DB_RX_IPAD, - "klips_debug: %02x:", - i - 1); - } - KLIPS_PRINTMORE(debug_rcv & DB_RX_IPAD, - " %02x", - idat[irs->ilen - 2 - padlen + i - 1]); - if(i != idat[irs->ilen - 2 - padlen + i - 1]) { - badpad = 1; - } - if((i % 16) == 0) { - KLIPS_PRINTMORE(debug_rcv & DB_RX_IPAD, - "\n"); - } - } - if((i % 16) != 1) { - KLIPS_PRINTMORE(debug_rcv & DB_RX_IPAD, - "\n"); - } - if(badpad) { - KLIPS_PRINT(debug_rcv & DB_RX_IPAD, - "klips_debug:ipsec_rcv: " - "warning, decrypted packet from %s has bad padding\n", - irs->ipsaddr_txt); - KLIPS_PRINT(debug_rcv & DB_RX_IPAD, - "klips_debug:ipsec_rcv: " - "...may be bad decryption -- not dropped\n"); - ipsp->ips_errs.ips_encpad_errs += 1; - } - - KLIPS_PRINT(debug_rcv & DB_RX_IPAD, - "klips_debug:ipsec_rcv: " - "packet decrypted from %s: next_header = %d, padding = %d\n", - irs->ipsaddr_txt, - irs->next_header, - pad - 2 - irs->authlen); - - irs->ipp->tot_len = htons(ntohs(irs->ipp->tot_len) - (esphlen + pad)); - - /* - * move the IP header forward by the size of the ESP header, which - * will remove the the ESP header from the packet. - */ - memmove((void *)(skb->data + esphlen), - (void *)(skb->data), irs->iphlen); - - rcv_dmp("esp postmove", skb->data, skb->len); - - /* skb_pull below, will move up by esphlen */ - - /* XXX not clear how this can happen, as the message indicates */ - if(skb->len < esphlen) { - printk(KERN_WARNING - "klips_error:ipsec_rcv: " - "tried to skb_pull esphlen=%d, %d available. This should never happen, please report.\n", - esphlen, (int)(skb->len)); - return IPSEC_RCV_ESP_DECAPFAIL; - } - skb_pull(skb, esphlen); - - irs->ipp = (struct iphdr *)skb->data; - - rcv_dmp("esp postpull", skb->data, skb->len); - - /* now, trip off the padding from the end */ - KLIPS_PRINT(debug_rcv & DB_RX_PKTRX, - "klips_debug:ipsec_rcv: " - "trimming to %d.\n", - irs->len - esphlen - pad); - if(pad + esphlen <= irs->len) { - skb_trim(skb, irs->len - esphlen - pad); - } else { - KLIPS_PRINT(debug_rcv & DB_RX_PKTRX, - "klips_debug:ipsec_rcv: " - "bogus packet, size is zero or negative, dropping.\n"); - return IPSEC_RCV_DECAPFAIL; - } - - return IPSEC_RCV_OK; -} - - -struct xform_functions esp_rcv_funcs[]={ - { checks: ipsec_rcv_esp_checks, - setup_auth: ipsec_rcv_esp_decrypt_setup, - calc_auth: ipsec_rcv_esp_authcalc, - decrypt: ipsec_rcv_esp_decrypt, - }, -}; -#endif /* !CONFIG_IPSEC_ESP */ - -#ifdef CONFIG_IPSEC_AH -enum ipsec_rcv_value -ipsec_rcv_ah_checks(struct ipsec_rcv_state *irs, - struct sk_buff *skb) -{ - int ahminlen; - - ahminlen = irs->hard_header_len + sizeof(struct iphdr); - - /* take care not to deref this pointer until we check the minlen though */ - irs->protostuff.ahstuff.ahp = (struct ahhdr *) (skb->data + irs->iphlen); - - if((skb->len < ahminlen+sizeof(struct ahhdr)) || - (skb->len < ahminlen+(irs->protostuff.ahstuff.ahp->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, - irs->ipsaddr_txt); - if(irs->stats) { - irs->stats->rx_errors++; - } - return IPSEC_RCV_BADLEN; - } - - irs->said.spi = irs->protostuff.ahstuff.ahp->ah_spi; - - /* XXX we only support the one 12-byte authenticator for now */ - if(irs->protostuff.ahstuff.ahp->ah_hl != ((AHHMAC_HASHLEN+AHHMAC_RPLLEN) >> 2)) { - KLIPS_PRINT(debug_rcv & DB_RX_INAU, - "klips_debug:ipsec_rcv: " - "bad authenticator length %ld, expected %lu from %s.\n", - (long)(irs->protostuff.ahstuff.ahp->ah_hl << 2), - (unsigned long) sizeof(struct ahhdr), - irs->ipsaddr_txt); - if(irs->stats) { - irs->stats->rx_errors++; - } - return IPSEC_RCV_BADLEN; - } - - return IPSEC_RCV_OK; -} - - -enum ipsec_rcv_value -ipsec_rcv_ah_setup_auth(struct ipsec_rcv_state *irs, - struct sk_buff *skb, - __u32 *replay, - unsigned char **authenticator) -{ - struct ahhdr *ahp = irs->protostuff.ahstuff.ahp; - - *replay = ntohl(ahp->ah_rpl); - *authenticator = ahp->ah_data; - - return IPSEC_RCV_OK; -} - -enum ipsec_rcv_value -ipsec_rcv_ah_authcalc(struct ipsec_rcv_state *irs, - struct sk_buff *skb) -{ - struct auth_alg *aa; - struct ahhdr *ahp = irs->protostuff.ahstuff.ahp; - union { - MD5_CTX md5; - SHA1_CTX sha1; - } tctx; - struct iphdr ipo; - int ahhlen; - - aa = irs->authfuncs; - - /* copy the initialized keying material */ - memcpy(&tctx, irs->ictx, irs->ictx_len); - - ipo = *irs->ipp; - ipo.tos = 0; /* mutable RFC 2402 3.3.3.1.1.1 */ - ipo.frag_off = 0; - ipo.ttl = 0; - ipo.check = 0; - - - /* do the sanitized header */ - (*aa->update)((void*)&tctx, (caddr_t)&ipo, sizeof(struct iphdr)); - - /* XXX we didn't do the options here! */ - - /* now do the AH header itself */ - ahhlen = AH_BASIC_LEN + (ahp->ah_hl << 2); - (*aa->update)((void*)&tctx, (caddr_t)ahp, ahhlen - AHHMAC_HASHLEN); - - /* now, do some zeroes */ - (*aa->update)((void*)&tctx, (caddr_t)zeroes, AHHMAC_HASHLEN); - - /* finally, do the packet contents themselves */ - (*aa->update)((void*)&tctx, - (caddr_t)skb->data + irs->iphlen + ahhlen, - skb->len - irs->iphlen - ahhlen); - - (*aa->final)(irs->hash, (void *)&tctx); - - memcpy(&tctx, irs->octx, irs->octx_len); - - (*aa->update)((void *)&tctx, irs->hash, aa->hashlen); - (*aa->final)(irs->hash, (void *)&tctx); - - return IPSEC_RCV_OK; -} - -enum ipsec_rcv_value -ipsec_rcv_ah_decap(struct ipsec_rcv_state *irs) -{ - struct ahhdr *ahp = irs->protostuff.ahstuff.ahp; - struct sk_buff *skb; - int ahhlen; - - skb=irs->skb; - - ahhlen = AH_BASIC_LEN + (ahp->ah_hl << 2); - - irs->ipp->tot_len = htons(ntohs(irs->ipp->tot_len) - ahhlen); - irs->next_header = ahp->ah_nh; - - /* - * move the IP header forward by the size of the AH header, which - * will remove the the AH header from the packet. - */ - memmove((void *)(skb->data + ahhlen), - (void *)(skb->data), irs->iphlen); - - rcv_dmp("ah postmove", skb->data, skb->len); - - /* skb_pull below, will move up by ahhlen */ - - /* XXX not clear how this can happen, as the message indicates */ - if(skb->len < ahhlen) { - printk(KERN_WARNING - "klips_error:ipsec_rcv: " - "tried to skb_pull ahhlen=%d, %d available. This should never happen, please report.\n", - ahhlen, - (int)(skb->len)); - return IPSEC_RCV_DECAPFAIL; - } - skb_pull(skb, ahhlen); - - irs->ipp = (struct iphdr *)skb->data; - - rcv_dmp("ah postpull", skb->data, skb->len); - - return IPSEC_RCV_OK; -} - - -struct xform_functions ah_rcv_funcs[]={ - { checks: ipsec_rcv_ah_checks, - setup_auth: ipsec_rcv_ah_setup_auth, - calc_auth: ipsec_rcv_ah_authcalc, - decrypt: ipsec_rcv_ah_decap, - }, -}; - -#endif /* CONFIG_IPSEC_AH */ - -#ifdef CONFIG_IPSEC_IPCOMP -enum ipsec_rcv_value -ipsec_rcv_ipcomp_checks(struct ipsec_rcv_state *irs, - struct sk_buff *skb) -{ - int ipcompminlen; - - ipcompminlen = irs->hard_header_len + sizeof(struct iphdr); - - if(skb->len < (ipcompminlen + 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, - irs->ipsaddr_txt); - if(irs->stats) { - irs->stats->rx_errors++; - } - return IPSEC_RCV_BADLEN; - } - - irs->protostuff.ipcompstuff.compp = (struct ipcomphdr *)(skb->data + irs->iphlen); - irs->said.spi = htonl((__u32)ntohs(irs->protostuff.ipcompstuff.compp->ipcomp_cpi)); - return IPSEC_RCV_OK; -} - -enum ipsec_rcv_value -ipsec_rcv_ipcomp_decomp(struct ipsec_rcv_state *irs) -{ - unsigned int flags = 0; - struct ipsec_sa *ipsp = irs->ipsp; - struct sk_buff *skb; - - skb=irs->skb; - - rcv_dmp("ipcomp", skb->data, skb->len); - - if(ipsp == NULL) { - return IPSEC_RCV_SAIDNOTFOUND; - } - -#if 0 - /* we want to check that this wasn't the first SA on the list, because - * we don't support bare IPCOMP, for unexplained reasons. MCR - */ - if (ipsp->ips_onext != NULL) { - KLIPS_PRINT(debug_rcv, - "klips_debug:ipsec_rcv: " - "Incoming packet with outer IPCOMP header SA:%s: not yet supported by KLIPS, dropped\n", - irs->sa_len ? irs->sa : " (error)"); - if(irs->stats) { - irs->stats->rx_dropped++; - } - - return IPSEC_RCV_IPCOMPALONE; - } -#endif - - if(sysctl_ipsec_inbound_policy_check && - ((((ntohl(ipsp->ips_said.spi) & 0x0000ffff) != ntohl(irs->said.spi)) && - (ipsp->ips_encalg != ntohl(irs->said.spi)) /* this is a workaround for peer non-compliance with rfc2393 */ - ))) { - char sa2[SATOA_BUF]; - size_t sa_len2 = 0; - - sa_len2 = satoa(ipsp->ips_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", - irs->sa_len ? irs->sa : " (error)", - ipsp != NULL ? (sa_len2 ? sa2 : " (error)") : "NULL", - ntohs(irs->protostuff.ipcompstuff.compp->ipcomp_cpi), - (__u32)ntohl(irs->said.spi), - ipsp != NULL ? (__u32)ntohl((ipsp->ips_said.spi)) : 0, - ipsp != NULL ? (__u16)(ntohl(ipsp->ips_said.spi) & 0x0000ffff) : 0); - if(irs->stats) { - irs->stats->rx_dropped++; - } - return IPSEC_RCV_SAIDNOTFOUND; - } - - ipsp->ips_comp_ratio_cbytes += ntohs(irs->ipp->tot_len); - irs->next_header = irs->protostuff.ipcompstuff.compp->ipcomp_nh; - - skb = skb_decompress(skb, ipsp, &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 (irs->stats) { - if (flags) - irs->stats->rx_errors++; - else - irs->stats->rx_dropped++; - } - return IPSEC_RCV_IPCOMPFAILED; - } - - /* make sure we update the pointer */ - irs->skb = skb; - -#ifdef NET_21 - irs->ipp = skb->nh.iph; -#else /* NET_21 */ - irs->ipp = skb->ip_hdr; -#endif /* NET_21 */ - - ipsp->ips_comp_ratio_dbytes += ntohs(irs->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", - irs->sa_len ? irs->sa : " (error)", - (__u32)ntohl(irs->said.spi), - ipsp != NULL ? (__u32)ntohl((ipsp->ips_said.spi)) : 0, - ipsp != NULL ? (__u16)(ntohl(ipsp->ips_said.spi) & 0x0000ffff) : 0, - irs->next_header); - KLIPS_IP_PRINT(debug_rcv & DB_RX_PKTRX, irs->ipp); - - return IPSEC_RCV_OK; -} - - -struct xform_functions ipcomp_rcv_funcs[]={ - {checks: ipsec_rcv_ipcomp_checks, - decrypt: ipsec_rcv_ipcomp_decomp, - }, -}; - -#endif /* CONFIG_IPSEC_IPCOMP */ - -enum ipsec_rcv_value -ipsec_rcv_decap_once(struct ipsec_rcv_state *irs) -{ - 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 xform_functions *proto_funcs; - struct ipsec_sa *newipsp; - struct iphdr *ipp; - struct sk_buff *skb; -#ifdef CONFIG_IPSEC_ALG - struct ipsec_alg_auth *ixt_a=NULL; -#endif /* CONFIG_IPSEC_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); - - switch(proto) { -#ifdef CONFIG_IPSEC_ESP - case IPPROTO_ESP: - proto_funcs = esp_rcv_funcs; - break; -#endif /* !CONFIG_IPSEC_ESP */ - -#ifdef CONFIG_IPSEC_AH - case IPPROTO_AH: - proto_funcs = ah_rcv_funcs; - break; -#endif /* !CONFIG_IPSEC_AH */ - -#ifdef CONFIG_IPSEC_IPCOMP - case IPPROTO_COMP: - proto_funcs = ipcomp_rcv_funcs; - break; -#endif /* !CONFIG_IPSEC_IPCOMP */ - default: - if(irs->stats) { - irs->stats->rx_errors++; - } - return IPSEC_RCV_BADPROTO; - } - - /* - * 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.s_addr = ipp->daddr; - - if(proto_funcs->checks) { - enum ipsec_rcv_value retval = (*proto_funcs->checks)(irs, skb); - - if(retval < 0) { - return retval; - } - } - - irs->said.proto = proto; - irs->sa_len = satoa(irs->said, 0, irs->sa, SATOA_BUF); - 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_IPSEC_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 || - 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_IPSEC_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_IPSEC_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_IPSEC_ALG */ - switch(irs->ipsp->ips_authalg) { -#ifdef CONFIG_IPSEC_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_IPSEC_AUTH_HMAC_MD5 */ -#ifdef CONFIG_IPSEC_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_IPSEC_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_IPSEC_ALG - if(irs->authfuncs || ixt_a) { -#else - if(irs->authfuncs) { -#endif - unsigned char *authenticator = NULL; - - if(proto_funcs->setup_auth) { - enum ipsec_rcv_value retval - = (*proto_funcs->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->calc_auth == NULL) { - return IPSEC_RCV_BADAUTH; - } - (*proto_funcs->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->decrypt) { - enum ipsec_rcv_value retval = - (*proto_funcs->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_IPSEC_IPCOMP - && ipp->protocol != IPPROTO_COMP - && (ipsnext->ips_said.proto != IPPROTO_COMP - || ipsnext->ips_inext) -#endif /* CONFIG_IPSEC_IPCOMP */ - && ipp->protocol != IPPROTO_IPIP - ) { - 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_IPSEC_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_IPSEC_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; -} - - -int -#ifdef PROTO_HANDLER_SINGLE_PARM -ipsec_rcv(struct sk_buff *skb) -#else /* PROTO_HANDLER_SINGLE_PARM */ -#ifdef NET_21 -ipsec_rcv(struct sk_buff *skb, unsigned short xlen) -#else /* NET_21 */ -ipsec_rcv(struct sk_buff *skb, struct 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_IPSEC_DEBUG - struct device *dev = skb->dev; -#endif /* CONFIG_IPSEC_DEBUG */ -#endif /* NET_21 */ - unsigned char protoc; - struct iphdr *ipp; -#if defined(CONFIG_IPSEC_ESP) || defined(CONFIG_IPSEC_AH) -#endif /* defined(CONFIG_IPSEC_ESP) || defined(CONFIG_IPSEC_AH) */ - - struct ipsec_sa *ipsp = NULL; - struct net_device_stats *stats = NULL; /* This device's statistics */ - struct 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 */ - MOD_INC_USE_COUNT; - - 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 !!). - */ - struct udp_opt *tp = &(skb->sk->tp_pinfo.af_udp); - struct iphdr *ip = (struct iphdr *)skb->nh.iph; - struct udphdr *udp = (struct udphdr *)((__u32 *)ip+ip->ihl); - __u8 *udpdata = (__u8 *)udp + sizeof(struct udphdr); - __u32 *udpdata32 = (__u32 *)udpdata; - - irs.natt_sport = ntohs(udp->source); - irs.natt_dport = ntohs(udp->dest); - - KLIPS_PRINT(debug_rcv, - "klips_debug:ipsec_rcv: " - "suspected ESPinUDP packet (NAT-Traversal) [%d].\n", - tp->esp_in_udp); - KLIPS_IP_PRINT(debug_rcv, ip); - - if (udpdata < skb->tail) { - unsigned int len = skb->tail - udpdata; - if ((len==1) && (udpdata[0]==0xff)) { - KLIPS_PRINT(debug_rcv, - "klips_debug:ipsec_rcv: " - /* not IPv6 compliant message */ - "NAT-keepalive from %d.%d.%d.%d.\n", NIPQUAD(ip->saddr)); - goto rcvleave; - } - else if ( (tp->esp_in_udp == ESPINUDP_WITH_NON_IKE) && - (len > (2*sizeof(__u32) + sizeof(struct esphdr))) && - (udpdata32[0]==0) && (udpdata32[1]==0) ) { - /* ESP Packet with Non-IKE header */ - KLIPS_PRINT(debug_rcv, - "klips_debug:ipsec_rcv: " - "ESPinUDP pkt with Non-IKE - spi=0x%x\n", - udpdata32[2]); - irs.natt_type = ESPINUDP_WITH_NON_IKE; - irs.natt_len = sizeof(struct udphdr)+(2*sizeof(__u32)); - } - else if ( (tp->esp_in_udp == ESPINUDP_WITH_NON_ESP) && - (len > sizeof(struct esphdr)) && - (udpdata32[0]!=0) ) { - /* ESP Packet without Non-ESP header */ - irs.natt_type = ESPINUDP_WITH_NON_ESP; - irs.natt_len = sizeof(struct udphdr); - KLIPS_PRINT(debug_rcv, - "klips_debug:ipsec_rcv: " - "ESPinUDP pkt without Non-ESP - spi=0x%x\n", - udpdata32[0]); - } - else { - KLIPS_PRINT(debug_rcv, - "klips_debug:ipsec_rcv: " - "IKE packet - not handled here\n"); - MOD_DEC_USE_COUNT; - return -1; - } - } - else { - MOD_DEC_USE_COUNT; - return -1; - } - } -#endif - -#ifdef IPH_is_SKB_PULLED - /* In Linux 2.4.4, the IP header has been skb_pull()ed before the - packet is passed to us. So we'll skb_push() to get back to it. */ - if (skb->data == skb->h.raw) { - skb_push(skb, skb->h.raw - skb->nh.raw); - } -#endif /* IPH_is_SKB_PULLED */ - - /* dev->hard_header_len is unreliable and should not be used */ - irs.hard_header_len = skb->mac.raw ? (skb->data - skb->mac.raw) : 0; - if((irs.hard_header_len < 0) || (irs.hard_header_len > skb_headroom(skb))) - irs.hard_header_len = 0; - -#ifdef NET_21 - /* if skb was cloned (most likely due to a packet sniffer such as - tcpdump being momentarily attached to the interface), make - a copy of our own to modify */ - if(skb_cloned(skb)) { - /* include any mac header while copying.. */ - if(skb_headroom(skb) < irs.hard_header_len) { - printk(KERN_WARNING "klips_error:ipsec_rcv: " - "tried to skb_push hhlen=%d, %d available. This should never happen, please report.\n", - irs.hard_header_len, - skb_headroom(skb)); - goto rcvleave; - } - skb_push(skb, irs.hard_header_len); - if -#ifdef SKB_COW_NEW - (skb_cow(skb, skb_headroom(skb)) != 0) -#else /* SKB_COW_NEW */ - ((skb = skb_cow(skb, skb_headroom(skb))) == NULL) -#endif /* SKB_COW_NEW */ - { - goto rcvleave; - } - if(skb->len < irs.hard_header_len) { - printk(KERN_WARNING "klips_error:ipsec_rcv: " - "tried to skb_pull hhlen=%d, %d available. This should never happen, please report.\n", - irs.hard_header_len, - skb->len); - goto rcvleave; - } - skb_pull(skb, irs.hard_header_len); - } - -#endif /* NET_21 */ - -#if IP_FRAGMENT_LINEARIZE - /* In Linux 2.4.4, we may have to reassemble fragments. They are - not assembled automatically to save TCP from having to copy - twice. - */ - if (skb_is_nonlinear(skb)) { - if (skb_linearize(skb, GFP_ATOMIC) != 0) { - goto rcvleave; - } - } -#endif /* IP_FRAGMENT_LINEARIZE */ - -#ifdef CONFIG_IPSEC_NAT_TRAVERSAL - if (irs.natt_len) { - /** - * Now, we are sure packet is ESPinUDP. Remove natt_len bytes from - * packet and modify protocol to ESP. - */ - if (((unsigned char *)skb->data > (unsigned char *)skb->nh.iph) && - ((unsigned char *)skb->nh.iph > (unsigned char *)skb->head)) { - unsigned int _len = (unsigned char *)skb->data - - (unsigned char *)skb->nh.iph; - KLIPS_PRINT(debug_rcv, - "klips_debug:ipsec_rcv: adjusting skb: skb_push(%u)\n", - _len); - skb_push(skb, _len); - } - KLIPS_PRINT(debug_rcv, - "klips_debug:ipsec_rcv: " - "removing %d bytes from ESPinUDP packet\n", irs.natt_len); - ipp = (struct iphdr *)skb->data; - irs.iphlen = ipp->ihl << 2; - ipp->tot_len = htons(ntohs(ipp->tot_len) - irs.natt_len); - if (skb->len < irs.iphlen + irs.natt_len) { - printk(KERN_WARNING - "klips_error:ipsec_rcv: " - "ESPinUDP packet is too small (%d < %d+%d). " - "This should never happen, please report.\n", - (int)(skb->len), irs.iphlen, irs.natt_len); - goto rcvleave; - } - memmove(skb->data + irs.natt_len, skb->data, irs.iphlen); - skb_pull(skb, irs.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 - - ipp = skb->nh.iph; - 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)); - irs.iphlen = ipp->ihl << 2; - - 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_IPSA, - "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_IPSA, - "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_DEV_FORMAT, 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 == NULL) { - KLIPS_PRINT((debug_rcv), - "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 */ - - /* - 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); - - /* set up for decap loop */ - irs.stats= stats; - irs.ipp = ipp; - irs.ipsp = NULL; - irs.ilen = 0; - irs.authlen=0; - irs.authfuncs=NULL; - irs.skb = skb; - - do { - int decap_stat; - - decap_stat = ipsec_rcv_decap_once(&irs); - - 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_IPSEC_IPCOMP - || (irs.ipp->protocol == IPPROTO_COMP) -#endif /* CONFIG_IPSEC_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_IPSEC_IPCOMP - if(ipsnext && ipsnext->ips_said.proto == IPPROTO_COMP) { - ipsp = ipsnext; - ipsnext = ipsp->ips_inext; - } -#endif /* CONFIG_IPSEC_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)) { - struct tcphdr *tcp = (struct tcphdr *)((__u32 *)ipp+ipp->ihl); - if (natt_oa) { - __u32 buff[2] = { ~natt_oa, ipp->saddr }; - KLIPS_PRINT(debug_rcv, - "klips_debug:ipsec_rcv: " - "NAT-T & TRANSPORT: " - "fix TCP checksum using NAT-OA\n"); - tcp->check = csum_fold( - csum_partial((unsigned char *)buff, sizeof(buff), - tcp->check^0xffff)); - } - else { - KLIPS_PRINT(debug_rcv, - "klips_debug:ipsec_rcv: " - "NAT-T & TRANSPORT: recalc TCP checksum\n"); - if (pkt_len > (ntohs(ipp->tot_len))) - data_len -= (pkt_len - ntohs(ipp->tot_len)); - tcp->check = 0; - tcp->check = csum_tcpudp_magic(ipp->saddr, ipp->daddr, - data_len, IPPROTO_TCP, - csum_partial((unsigned char *)tcp, data_len, 0)); - } - } - else { - KLIPS_PRINT(debug_rcv, - "klips_debug:ipsec_rcv: " - "NAT-T & TRANSPORT: can't fix TCP checksum\n"); - } - break; - case IPPROTO_UDP: - if (data_len >= sizeof(struct udphdr)) { - struct udphdr *udp = (struct udphdr *)((__u32 *)ipp+ipp->ihl); - if (udp->check == 0) { - KLIPS_PRINT(debug_rcv, - "klips_debug:ipsec_rcv: " - "NAT-T & TRANSPORT: UDP checksum already 0\n"); - } - else if (natt_oa) { - __u32 buff[2] = { ~natt_oa, ipp->saddr }; - KLIPS_PRINT(debug_rcv, - "klips_debug:ipsec_rcv: " - "NAT-T & TRANSPORT: " - "fix UDP checksum using NAT-OA\n"); - udp->check = csum_fold( - csum_partial((unsigned char *)buff, sizeof(buff), - udp->check^0xffff)); - } - else { - KLIPS_PRINT(debug_rcv, - "klips_debug:ipsec_rcv: " - "NAT-T & TRANSPORT: zero UDP checksum\n"); - udp->check = 0; - } - } - else { - KLIPS_PRINT(debug_rcv, - "klips_debug:ipsec_rcv: " - "NAT-T & TRANSPORT: can't fix UDP checksum\n"); - } - break; - default: - KLIPS_PRINT(debug_rcv, - "klips_debug:ipsec_rcv: " - "NAT-T & TRANSPORT: non TCP/UDP packet -- do nothing\n"); - break; - } - } -#endif - - /* - * XXX this needs to be locked from when it was first looked - * up in the decapsulation loop. Perhaps it is better to put - * the IPIP decap inside the loop. - */ - if(ipsnext) { - ipsp = ipsnext; - irs.sa_len = satoa(irs.said, 0, irs.sa, SATOA_BUF); - if(ipp->protocol != IPPROTO_IPIP) { - spin_unlock(&tdb_lock); - KLIPS_PRINT(debug_rcv, - "klips_debug:ipsec_rcv: " - "SA:%s, Hey! How did this get through? Dropped.\n", - irs.sa_len ? irs.sa : " (error)"); - if(stats) { - stats->rx_dropped++; - } - goto rcvleave; - } - if(sysctl_ipsec_inbound_policy_check) { - if((ipsnext = ipsp->ips_inext)) { - char sa2[SATOA_BUF]; - size_t sa_len2; - sa_len2 = satoa(ipsnext->ips_said, 0, sa2, SATOA_BUF); - spin_unlock(&tdb_lock); - KLIPS_PRINT(debug_rcv, - "klips_debug:ipsec_rcv: " - "unexpected SA:%s after IPIP SA:%s\n", - sa_len2 ? sa2 : " (error)", - irs.sa_len ? irs.sa : " (error)"); - if(stats) { - stats->rx_dropped++; - } - goto rcvleave; - } - if(ipp->saddr != ((struct sockaddr_in*)(ipsp->ips_addr_s))->sin_addr.s_addr) { - spin_unlock(&tdb_lock); - 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(stats) { - stats->rx_dropped++; - } - goto rcvleave; - } - } - - /* - * XXX this needs to be locked from when it was first looked - * up in the decapsulation loop. Perhaps it is better to put - * the IPIP decap inside the loop. - */ - ipsp->ips_life.ipl_bytes.ipl_count += skb->len; - ipsp->ips_life.ipl_bytes.ipl_last = skb->len; - - if(!ipsp->ips_life.ipl_usetime.ipl_count) { - ipsp->ips_life.ipl_usetime.ipl_count = jiffies / HZ; - } - ipsp->ips_life.ipl_usetime.ipl_last = jiffies / HZ; - ipsp->ips_life.ipl_packets.ipl_count += 1; - - if(skb->len < irs.iphlen) { - spin_unlock(&tdb_lock); - printk(KERN_WARNING "klips_debug:ipsec_rcv: " - "tried to skb_pull iphlen=%d, %d available. This should never happen, please report.\n", - irs.iphlen, - (int)(skb->len)); - - goto rcvleave; - } - skb_pull(skb, irs.iphlen); - -#ifdef NET_21 - skb->nh.raw = skb->data; - ipp = (struct iphdr *)skb->nh.raw; - skb->h.raw = skb->nh.raw + (skb->nh.iph->ihl << 2); - - memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); -#else /* NET_21 */ - ipp = skb->ip_hdr = skb->h.iph = (struct iphdr *)skb->data; - - memset(skb->proto_priv, 0, sizeof(struct options)); -#endif /* NET_21 */ - 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)); - - skb->protocol = htons(ETH_P_IP); - skb->ip_summed = 0; - KLIPS_PRINT(debug_rcv & DB_RX_PKTRX, - "klips_debug:ipsec_rcv: " - "IPIP tunnel stripped.\n"); - KLIPS_IP_PRINT(debug_rcv & DB_RX_PKTRX, ipp); - - if(sysctl_ipsec_inbound_policy_check - /* - Note: "xor" (^) logically replaces "not equal" - (!=) and "bitwise or" (|) logically replaces - "boolean or" (||). This is done to speed up - execution by doing only bitwise operations and - no branch operations - */ - && (((ipp->saddr & ipsp->ips_mask_s.u.v4.sin_addr.s_addr) - ^ ipsp->ips_flow_s.u.v4.sin_addr.s_addr) - | ((ipp->daddr & ipsp->ips_mask_d.u.v4.sin_addr.s_addr) - ^ ipsp->ips_flow_d.u.v4.sin_addr.s_addr)) ) - { - char sflow_txt[SUBNETTOA_BUF], dflow_txt[SUBNETTOA_BUF]; - - subnettoa(ipsp->ips_flow_s.u.v4.sin_addr, - ipsp->ips_mask_s.u.v4.sin_addr, - 0, sflow_txt, sizeof(sflow_txt)); - subnettoa(ipsp->ips_flow_d.u.v4.sin_addr, - ipsp->ips_mask_d.u.v4.sin_addr, - 0, dflow_txt, sizeof(dflow_txt)); - spin_unlock(&tdb_lock); - KLIPS_PRINT(debug_rcv, - "klips_debug:ipsec_rcv: " - "SA:%s, inner tunnel policy [%s -> %s] does not agree with pkt contents [%s -> %s].\n", - irs.sa_len ? irs.sa : " (error)", - sflow_txt, - dflow_txt, - irs.ipsaddr_txt, - irs.ipdaddr_txt); - if(stats) { - stats->rx_dropped++; - } - goto rcvleave; - } -#ifdef CONFIG_NETFILTER - skb->nfmark = (skb->nfmark & (~(IPsecSAref2NFmark(IPSEC_SA_REF_TABLE_MASK)))) - | IPsecSAref2NFmark(IPsecSA2SAref(ipsp)); - KLIPS_PRINT(debug_rcv & DB_RX_PKTRX, - "klips_debug:ipsec_rcv: " - "IPIP SA sets skb->nfmark=0x%x.\n", - (unsigned)skb->nfmark); -#endif /* CONFIG_NETFILTER */ - } - - spin_unlock(&tdb_lock); - -#ifdef NET_21 - if(stats) { - stats->rx_bytes += skb->len; - } - if(skb->dst) { - dst_release(skb->dst); - skb->dst = NULL; - } - skb->pkt_type = PACKET_HOST; - if(irs.hard_header_len && - (skb->mac.raw != (skb->data - irs.hard_header_len)) && - (irs.hard_header_len <= skb_headroom(skb))) { - /* copy back original MAC header */ - memmove(skb->data - irs.hard_header_len, skb->mac.raw, irs.hard_header_len); - skb->mac.raw = skb->data - irs.hard_header_len; - } -#endif /* NET_21 */ - -#ifdef CONFIG_IPSEC_IPCOMP - if(ipp->protocol == IPPROTO_COMP) { - unsigned int flags = 0; - - if(sysctl_ipsec_inbound_policy_check) { - KLIPS_PRINT(debug_rcv & DB_RX_PKTRX, - "klips_debug:ipsec_rcv: " - "inbound policy checking enabled, IPCOMP follows IPIP, dropped.\n"); - if (stats) { - stats->rx_errors++; - } - goto rcvleave; - } - /* - XXX need a ipsec_sa for updating ratio counters but it is not - following policy anyways so it is not a priority - */ - skb = skb_decompress(skb, NULL, &flags); - if (!skb || flags) { - KLIPS_PRINT(debug_rcv & DB_RX_PKTRX, - "klips_debug:ipsec_rcv: " - "skb_decompress() returned error flags: %d, dropped.\n", - flags); - if (stats) { - stats->rx_errors++; - } - goto rcvleave; - } - } -#endif /* CONFIG_IPSEC_IPCOMP */ - -#ifdef SKB_RESET_NFCT - nf_conntrack_put(skb->nfct); - skb->nfct = NULL; -#ifdef CONFIG_NETFILTER_DEBUG - skb->nf_debug = 0; -#endif /* CONFIG_NETFILTER_DEBUG */ -#endif /* SKB_RESET_NFCT */ - KLIPS_PRINT(debug_rcv & DB_RX_PKTRX, - "klips_debug:ipsec_rcv: " - "netif_rx() called.\n"); - netif_rx(skb); - - MOD_DEC_USE_COUNT; - return(0); - - rcvleave: - if(skb) { - ipsec_kfree_skb(skb); - } - - MOD_DEC_USE_COUNT; - return(0); -} - -struct inet_protocol ah_protocol = -{ - ipsec_rcv, /* AH handler */ - NULL, /* TUNNEL error control */ -#ifdef NETDEV_25 - 1, /* no policy */ -#else - 0, /* next */ - IPPROTO_AH, /* protocol ID */ - 0, /* copy */ - NULL, /* data */ - "AH" /* name */ -#endif -}; - -struct inet_protocol esp_protocol = -{ - ipsec_rcv, /* ESP handler */ - NULL, /* TUNNEL error control */ -#ifdef NETDEV_25 - 1, /* no policy */ -#else - 0, /* next */ - IPPROTO_ESP, /* protocol ID */ - 0, /* copy */ - NULL, /* data */ - "ESP" /* name */ -#endif -}; - -#if 0 -/* We probably don't want to install a pure IPCOMP protocol handler, but - only want to handle IPCOMP if it is encapsulated inside an ESP payload - (which is already handled) */ -#ifdef CONFIG_IPSEC_IPCOMP -struct inet_protocol comp_protocol = -{ - ipsec_rcv, /* COMP handler */ - NULL, /* COMP error control */ -#ifdef NETDEV_25 - 1, /* no policy */ -#else - 0, /* next */ - IPPROTO_COMP, /* protocol ID */ - 0, /* copy */ - NULL, /* data */ - "COMP" /* name */ -#endif -}; -#endif /* CONFIG_IPSEC_IPCOMP */ -#endif |