summaryrefslogtreecommitdiff
path: root/linux/net/ipsec/ipsec_rcv.c
diff options
context:
space:
mode:
Diffstat (limited to 'linux/net/ipsec/ipsec_rcv.c')
-rw-r--r--linux/net/ipsec/ipsec_rcv.c2204
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