📄 ipsec_xform.c
字号:
/* * Common routines for IPSEC transformations. * 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. * * RCSID $Id: ipsec_xform.c,v 1.52 2001/06/14 19:35:11 rgb Exp $ */#include <linux/config.h>#include <linux/version.h>#include <linux/kernel.h> /* printk() */#include <linux/malloc.h> /* kmalloc() */#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 <linux/random.h> /* get_random_bytes() */#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>#endif#include <asm/checksum.h>#include <net/ip.h>#include "radij.h"#include "ipsec_encap.h"#include "ipsec_radij.h"#include "ipsec_netlink.h"#include "ipsec_xform.h"#include "ipsec_ipe4.h"#include "ipsec_ah.h"#include "ipsec_esp.h"#include <pfkeyv2.h>#include <pfkey.h>#ifdef CONFIG_IPSEC_DEBUGint debug_xform = 0;#endif /* CONFIG_IPSEC_DEBUG */#define SENDERR(_x) do { error = -(_x); goto errlab; } while (0)extern int des_set_key(caddr_t, caddr_t);struct xformsw xformsw[] = {{ XF_IP4, 0, "IPv4_Encapsulation"},{ XF_AHHMACMD5, XFT_AUTH, "HMAC_MD5_Authentication"},{ XF_AHHMACSHA1, XFT_AUTH, "HMAC_SHA-1_Authentication"},{ XF_ESP3DES, XFT_CONF, "3DES_Encryption"},{ XF_ESP3DESMD596, XFT_CONF, "3DES-MD5-96_Encryption"},{ XF_ESP3DESSHA196, XFT_CONF, "3DES-SHA1-96_Encryption"},{ XF_ESPNULLMD596, XFT_CONF, "NULL-MD5-96_ESP_*Plaintext*"},{ XF_ESPNULLSHA196, XFT_CONF, "NULL-SHA1-96_ESP_*Plaintext*"},};struct tdb *tdbh[TDB_HASHMOD];#ifdef SPINLOCKspinlock_t tdb_lock = SPIN_LOCK_UNLOCKED;#else /* SPINLOCK */spinlock_t tdb_lock;#endif /* SPINLOCK */struct xformsw *xformswNXFORMSW = &xformsw[sizeof(xformsw)/sizeof(xformsw[0])];intipsec_tdbinit(void){ int i; for(i = 1; i < TDB_HASHMOD; i++) { tdbh[i] = NULL; } return 0;}struct tdb *gettdb(struct sa_id *said){ int hashval; struct tdb *tdbp; char sa[SATOA_BUF]; size_t sa_len; if(!said) { KLIPS_PRINT(debug_xform, "klips_error:gettdb: " "null pointer passed in!\n"); return NULL; } sa_len = satoa(*said, 0, sa, SATOA_BUF); hashval = (said->spi+said->dst.s_addr+said->proto) % TDB_HASHMOD; KLIPS_PRINT(debug_xform, "klips_debug:gettdb: " "linked entry in tdb table for hash=%d of SA:%s requested.\n", hashval, sa_len ? sa : " (error)"); if(!(tdbp = tdbh[hashval])) { KLIPS_PRINT(debug_xform, "klips_debug:gettdb: " "no entries in tdb table for hash=%d of SA:%s.\n", hashval, sa_len ? sa : " (error)"); return NULL; } for (; tdbp; tdbp = tdbp->tdb_hnext) { if ((tdbp->tdb_said.spi == said->spi) && (tdbp->tdb_said.dst.s_addr == said->dst.s_addr) && (tdbp->tdb_said.proto == said->proto)) { return tdbp; } } KLIPS_PRINT(debug_xform, "klips_debug:gettdb: " "no entry in linked list for hash=%d of SA:%s.\n", hashval, sa_len ? sa : " (error)"); return NULL;}/* The tdb table better *NOT* be locked before it is handed in, or SMP locks will happen*/intputtdb(struct tdb *tdbp){ int error = 0; unsigned int hashval; if(!tdbp) { KLIPS_PRINT(debug_xform, "klips_error:puttdb: " "null pointer passed in!\n"); return -ENODATA; } hashval = ((tdbp->tdb_said.spi + tdbp->tdb_said.dst.s_addr + tdbp->tdb_said.proto) % TDB_HASHMOD); spin_lock_bh(&tdb_lock); tdbp->tdb_hnext = tdbh[hashval]; tdbh[hashval] = tdbp; spin_unlock_bh(&tdb_lock); return error;}/* The tdb table better be locked before it is handed in, or races might happen*/intdeltdb(struct tdb *tdbp){ unsigned int hashval; struct tdb *tdbtp; char sa[SATOA_BUF]; size_t sa_len; if(!tdbp) { KLIPS_PRINT(debug_xform, "klips_error:deltdb: " "null pointer passed in!\n"); return -ENODATA; } sa_len = satoa(tdbp->tdb_said, 0, sa, SATOA_BUF); if(tdbp->tdb_inext || tdbp->tdb_onext) { KLIPS_PRINT(debug_xform, "klips_error:deltdb: " "SA:%s still linked!\n", sa_len ? sa : " (error)"); return -EMLINK; } hashval = ((tdbp->tdb_said.spi + tdbp->tdb_said.dst.s_addr + tdbp->tdb_said.proto) % TDB_HASHMOD); KLIPS_PRINT(debug_xform, "klips_debug:deltdb: " "deleting SA:%s, hashval=%d.\n", sa_len ? sa : " (error)", hashval); if(!tdbh[hashval]) { KLIPS_PRINT(debug_xform, "klips_debug:deltdb: " "no entries in tdb table for hash=%d of SA:%s.\n", hashval, sa_len ? sa : " (error)"); return -ENOENT; } if (tdbp == tdbh[hashval]) { tdbh[hashval] = tdbh[hashval]->tdb_hnext; tdbp->tdb_hnext = NULL; KLIPS_PRINT(debug_xform, "klips_debug:deltdb: " "successfully deleted first tdb in chain.\n"); return 0; } else { for (tdbtp = tdbh[hashval]; tdbtp; tdbtp = tdbtp->tdb_hnext) { if (tdbtp->tdb_hnext == tdbp) { tdbtp->tdb_hnext = tdbp->tdb_hnext; tdbp->tdb_hnext = NULL; KLIPS_PRINT(debug_xform, "klips_debug:deltdb: " "successfully deleted link in tdb chain.\n"); return 0; } } } KLIPS_PRINT(debug_xform, "klips_debug:deltdb: " "no entries in linked list for hash=%d of SA:%s.\n", hashval, sa_len ? sa : " (error)"); return -ENOENT;}/* The tdb table better be locked before it is handed in, or races might happen*/intdeltdbchain(struct tdb *tdbp){ struct tdb *tdbdel; int error = 0; char sa[SATOA_BUF]; size_t sa_len; if(!tdbp) { KLIPS_PRINT(debug_xform, "klips_error:deltdbchain: " "null pointer passed in!\n"); return -ENODATA; } sa_len = satoa(tdbp->tdb_said, 0, sa, SATOA_BUF); KLIPS_PRINT(debug_xform, "klips_debug:deltdbchain: " "passed SA:%s\n", sa_len ? sa : " (error)"); while(tdbp->tdb_onext) { tdbp = tdbp->tdb_onext; } while(tdbp) { /* XXX send a pfkey message up to advise of deleted TDB */ sa_len = satoa(tdbp->tdb_said, 0, sa, SATOA_BUF); KLIPS_PRINT(debug_xform, "klips_debug:deltdbchain: " "unlinking and delting SA:%s", sa_len ? sa : " (error)"); tdbdel = tdbp; tdbp = tdbp->tdb_inext; if(tdbp) { sa_len = satoa(tdbp->tdb_said, 0, sa, SATOA_BUF); KLIPS_PRINT(debug_xform, ", inext=%s", sa_len ? sa : " (error)"); tdbdel->tdb_inext = NULL; tdbp->tdb_onext = NULL; } KLIPS_PRINT(debug_xform, ".\n"); if((error = deltdb(tdbdel))) { KLIPS_PRINT(debug_xform, "klips_debug:deltdbchain: " "deltdb returned error %d.\n", -error); return error; } if((error = ipsec_tdbwipe(tdbdel))) { KLIPS_PRINT(debug_xform, "klips_debug:deltdbchain: " "ipsec_tdbwipe returned error %d.\n", -error); return error; } } return error;}#if 0inttdb_init(struct tdb *tdbp, struct encap_msghdr *em){ int alg; struct xformsw *xsp; int error = 0; int i;#if defined(CONFIG_IPSEC_ENC_3DES) int error;#endif /* CONFIG_IPSEC_ENC_3DES */ char sa[SATOA_BUF]; size_t sa_len; if(!tdbp || !em) { KLIPS_PRINT(debug_xform, "klips_error:tdb_init: " "null pointer passed in!\n"); SENDERR(ENODATA); } sa_len = satoa(em->em_said, 0, sa, SATOA_BUF); KLIPS_PRINT(debug_esp, "klips_debug:tdb_init: " "(algo_switch defined) called for SA:%s\n", sa_len ? sa : " (error)"); alg = em->em_alg; for (xsp = xformsw; xsp < xformswNXFORMSW; xsp++) { if (xsp->xf_type == alg) { KLIPS_PRINT(debug_netlink, "klips_debug:tdb_init: " "called with tdbp=0x%p, xsp=0x%p, em=0x%p\n", tdbp, xsp, em); KLIPS_PRINT(debug_netlink, "klips_debug:tdb_init: " "calling init routine of %s\n", xsp->xf_name); tdbp->tdb_xform = xsp; tdbp->tdb_replaywin_lastseq = 0; tdbp->tdb_replaywin_bitmap = 0; /* check size of message here XXX */ switch(alg) {#ifdef CONFIG_IPSEC_IPIP case XF_IP4: { struct ipe4_xdata *xd; xd = (struct ipe4_xdata *)(em->em_dat); tdbp->tdb_authalg = AH_NONE; tdbp->tdb_encalg = ESP_NONE; if((tdbp->tdb_addr_s = (struct sockaddr*) kmalloc((tdbp->tdb_addr_s_size = sizeof(struct sockaddr_in)), GFP_ATOMIC)) == NULL) { SENDERR(ENOMEM); } if((tdbp->tdb_addr_d = (struct sockaddr*) kmalloc((tdbp->tdb_addr_d_size = sizeof(struct sockaddr_in)), GFP_ATOMIC)) == NULL) { SENDERR(ENOMEM); } /* might want to use a different structure here, or set sin_family and sin_port */ ((struct sockaddr_in*)(tdbp->tdb_addr_s))->sin_addr = xd->i4_src; ((struct sockaddr_in*)(tdbp->tdb_addr_d))->sin_addr = xd->i4_dst; } break;#endif /* !CONFIG_IPSEC_IPIP */#ifdef CONFIG_IPSEC_AH# ifdef CONFIG_IPSEC_AUTH_HMAC_MD5 case XF_AHHMACMD5: { struct ahhmacmd5_edata *ed; unsigned char kb[AHMD596_BLKLEN]; MD5_CTX *ictx; MD5_CTX *octx; ed = (struct ahhmacmd5_edata *)em->em_dat; tdbp->tdb_authalg = AH_MD5; tdbp->tdb_encalg = ESP_NONE; if (em->em_msglen - EMT_SETSPI_FLEN > sizeof (struct ahhmacmd5_edata)) SENDERR(EINVAL); if (ed->ame_klen != AHMD596_KLEN) { KLIPS_PRINT(debug_ah, "klips_debug:tdb_init: " "incorrect key size: %d -- must be %d octets (bytes)\n", ed->ame_klen, AHMD596_KLEN); SENDERR(EINVAL); } if (ed->ame_alen != AHMD596_ALEN) { KLIPS_PRINT(debug_ah, "klips_debug:tdb_init: " "authenticator size: %d -- must be %d octets (bytes)\n", ed->ame_alen, AHMD596_ALEN); SENDERR(EINVAL); } KLIPS_PRINT(debug_ah, "klips_debug:tdb_init: " "hmac md5-96 key is 0x%08x %08x %08x %08x\n", (__u32)ntohl(*(((__u32 *)ed->ame_key)+0)), (__u32)ntohl(*(((__u32 *)ed->ame_key)+1)),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -