📄 ipsec_alg.c
字号:
/* * Modular extensions service and registration functions * * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar> * * Version: 0.8.1 * * ipsec_alg.c,v 1.1.2.1 2003/11/21 18:12:23 jjo Exp * * 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. * */#define __NO_VERSION__#if defined (MODULE)#include <linux/module.h>#endif#include <linux/kernel.h> /* printk() */#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/socket.h>#include <linux/in.h>#include <linux/types.h>#include <linux/string.h> /* memcmp() */#include <linux/random.h> /* get_random_bytes() */#include <linux/errno.h> /* error codes */#ifdef SPINLOCK# ifdef SPINLOCK_23# include <linux/spinlock.h> /* *lock* */# else /* SPINLOCK_23 */# include <asm/spinlock.h> /* *lock* */# endif /* SPINLOCK_23 */#endif /* SPINLOCK */#include "openswan/ipsec_param.h"#include <openswan.h>#include "openswan/ipsec_sa.h"#include "openswan/radij.h"#include "openswan/ipsec_encap.h"#include "openswan/ipsec_radij.h"#include "openswan/ipsec_xform.h"#include "openswan/ipsec_tunnel.h"#include "openswan/ipsec_rcv.h"#if defined(CONFIG_KLIPS_ESP) || defined(CONFIG_KLIPS_AH)# include "openswan/ipsec_ah.h"#endif /* defined(CONFIG_KLIPS_ESP) || defined(CONFIG_KLIPS_AH) */#ifdef CONFIG_KLIPS_ESP# include "openswan/ipsec_esp.h"#endif /* !CONFIG_KLIPS_ESP */#ifdef CONFIG_KLIPS_IPCOMP# include "openswan/ipcomp.h"#endif /* CONFIG_KLIPS_COMP */#include <pfkeyv2.h>#include <pfkey.h>#include "openswan/ipsec_alg.h"#include "openswan/ipsec_proto.h"#ifndef CONFIG_KLIPS_ALG#error This file _MUST_ be compiled with CONFIG_KLIPS_ALG enabled !#endif#if SADB_EALG_MAX < 255#warning Compiling with limited ESP support ( SADB_EALG_MAX < 256 )#endifstatic rwlock_t ipsec_alg_lock = RW_LOCK_UNLOCKED;#define IPSEC_ALG_HASHSZ 16 /* must be power of 2, even 2^0=1 */static struct list_head ipsec_alg_hash_table[IPSEC_ALG_HASHSZ];/* Old gcc's will fail here */#define barf_out(fmt, args...) do { struct ipsec_alg *ixtc = (struct ipsec_alg *)ixt; printk(KERN_ERR "%s: (%s) " fmt, __FUNCTION__, ixtc->ixt_name , ## args) \ ; goto out; } while(0)#ifdef NET_26/* * Must be already protected by lock */static void __ipsec_alg_usage_inc(struct ipsec_alg *ixt){#ifdef MODULE if (ixt->ixt_module) try_module_get(ixt->ixt_module);#endif atomic_inc(&ixt->ixt_refcnt);}static void __ipsec_alg_usage_dec(struct ipsec_alg *ixt) { atomic_dec(&ixt->ixt_refcnt);#ifdef MODULE if (ixt->ixt_module) module_put(ixt->ixt_module);#endif}#else/* * Must be already protected by lock */static void __ipsec_alg_usage_inc(struct ipsec_alg *ixt) {#ifdef MODULE if (ixt->ixt_module) { __MOD_INC_USE_COUNT(ixt->ixt_module); }#endif atomic_inc(&ixt->ixt_refcnt);}static void __ipsec_alg_usage_dec(struct ipsec_alg *ixt) { atomic_dec(&ixt->ixt_refcnt);#ifdef MODULE if (ixt->ixt_module) __MOD_DEC_USE_COUNT(ixt->ixt_module);#endif}#endif/* * simple hash function, optimized for 0-hash (1 list) special * case */#if IPSEC_ALG_HASHSZ > 1static inline unsigned ipsec_alg_hashfn(int alg_type, int alg_id) { return ((alg_type^alg_id)&(IPSEC_ALG_HASHSZ-1));}#else#define ipsec_alg_hashfn(x,y) (0)#endif/***************************************************************** * * INTERNAL table handling: insert, delete, find * *****************************************************************//* * hash table initialization, called from ipsec_alg_init() */static void ipsec_alg_hash_init(void) { struct list_head *head = ipsec_alg_hash_table; int i = IPSEC_ALG_HASHSZ; do { INIT_LIST_HEAD(head); head++; i--; } while (i);}/* * hash list lookup by {alg_type, alg_id} and table head, * must be already protected by lock */static struct ipsec_alg *__ipsec_alg_find(unsigned alg_type, unsigned alg_id, struct list_head * head) { struct list_head *p; struct ipsec_alg *ixt=NULL; for (p=head->next; p!=head; p=p->next) { ixt = list_entry(p, struct ipsec_alg, ixt_list); if (ixt->ixt_alg_type == alg_type && ixt->ixt_alg_id==alg_id) { goto out; } } ixt=NULL;out: return ixt;}/* * inserts (in front) a new entry in hash table, * called from ipsec_alg_register() when new algorithm is registered. */static int ipsec_alg_insert(struct ipsec_alg *ixt) { int ret=-EINVAL; unsigned hashval=ipsec_alg_hashfn(ixt->ixt_alg_type, ixt->ixt_alg_id); struct list_head *head= ipsec_alg_hash_table + hashval; struct ipsec_alg *ixt_cur; /* new element must be virgin ... */ if (ixt->ixt_list.next != &ixt->ixt_list || ixt->ixt_list.prev != &ixt->ixt_list) { printk(KERN_ERR "ipsec_alg_insert: ixt object \"%s\" " "list head not initialized\n", ixt->ixt_name); return ret; } write_lock_bh(&ipsec_alg_lock); ixt_cur = __ipsec_alg_find(ixt->ixt_alg_type, ixt->ixt_alg_id, head); /* if previous (current) ipsec_alg found check excl flag of _anyone_ */ if (ixt_cur && ((ixt->ixt_state|ixt_cur->ixt_state) & IPSEC_ALG_ST_EXCL)) { barf_out("ipsec_alg for alg_type=%d, alg_id=%d already exist. " "Not loaded (ret=%d).\n", ixt->ixt_alg_type, ixt->ixt_alg_id, ret=-EEXIST); } list_add(&ixt->ixt_list, head); ixt->ixt_state |= IPSEC_ALG_ST_REGISTERED; ret=0;out: write_unlock_bh(&ipsec_alg_lock); return ret;}/* * deletes an existing entry in hash table, * called from ipsec_alg_unregister() when algorithm is unregistered. */static int ipsec_alg_delete(struct ipsec_alg *ixt) { write_lock_bh(&ipsec_alg_lock); list_del(&ixt->ixt_list); write_unlock_bh(&ipsec_alg_lock); return 0;}/* * here @user context (read-only when @kernel bh context) * -> no bh disabling * * called from ipsec_sa_init() -> ipsec_alg_sa_init() */static struct ipsec_alg *ipsec_alg_get(int alg_type, int alg_id){ unsigned hashval=ipsec_alg_hashfn(alg_type, alg_id); struct list_head *head= ipsec_alg_hash_table + hashval; struct ipsec_alg *ixt; read_lock(&ipsec_alg_lock); ixt=__ipsec_alg_find(alg_type, alg_id, head); if (ixt) __ipsec_alg_usage_inc(ixt); read_unlock(&ipsec_alg_lock); return ixt;}static void ipsec_alg_put(struct ipsec_alg *ixt) { __ipsec_alg_usage_dec((struct ipsec_alg *)ixt);}/***************************************************************** * * INTERFACE for ENC services: key creation, encrypt function * *****************************************************************//* * main encrypt service entry point * called from ipsec_rcv() with encrypt=IPSEC_ALG_DECRYPT and * ipsec_tunnel_start_xmit with encrypt=IPSEC_ALG_ENCRYPT */int ipsec_alg_esp_encrypt(struct ipsec_sa *sa_p, __u8 * idat, int ilen, const __u8 * iv, int encrypt){ int ret; struct ipsec_alg_enc *ixt_e=sa_p->ips_alg_enc;#ifdef CONFIG_KLIPS_DEBUG int debug_flag = (encrypt==IPSEC_ALG_ENCRYPT ? debug_tunnel : debug_rcv);#endif KLIPS_PRINT(debug_flag, "klips_debug:ipsec_alg_esp_encrypt: " "entering with encalg=%d, ixt_e=%p\n", sa_p->ips_encalg, ixt_e); if (ixt_e == NULL) { KLIPS_PRINT(debug_flag, "klips_debug:ipsec_alg_esp_encrypt: " "NULL ipsec_alg_enc object\n"); return -1; } KLIPS_PRINT(debug_flag, "klips_debug:ipsec_alg_esp_encrypt: " "calling cbc_encrypt encalg=%d " "ips_key_e=%p idat=%p ilen=%d iv=%p, encrypt=%d\n", sa_p->ips_encalg, sa_p->ips_key_e, idat, ilen, iv, encrypt); ret=ixt_e->ixt_e_cbc_encrypt(ixt_e, sa_p->ips_key_e, idat, ilen, iv, encrypt); KLIPS_PRINT(debug_flag, "klips_debug:ipsec_alg_esp_encrypt: " "returned ret=%d\n", ret); return ret;}/* * encryption key context creation function * called from pfkey_v2_parser.c:pfkey_ips_init() */int ipsec_alg_enc_key_create(struct ipsec_sa *sa_p) { int ret=-EINVAL; int keyminbits, keymaxbits; caddr_t ekp; struct ipsec_alg_enc *ixt_e=sa_p->ips_alg_enc; KLIPS_PRINT(debug_pfkey, "klips_debug:ipsec_alg_enc_key_create: " "entering with encalg=%d ixt_e=%p\n", sa_p->ips_encalg, ixt_e); if (!ixt_e) { KLIPS_PRINT(debug_pfkey, "klips_debug:ipsec_alg_enc_key_create: " "NULL ipsec_alg_enc object\n"); return -EPROTO; } /* * grRRR... DES 7bits jurassic stuff ... f*ckk --jjo */ switch(ixt_e->ixt_common.ixt_support.ias_id) { case ESP_3DES: keyminbits=keymaxbits=192;break; case ESP_DES: keyminbits=keymaxbits=64;break; default: keyminbits=ixt_e->ixt_common.ixt_support.ias_keyminbits; keymaxbits=ixt_e->ixt_common.ixt_support.ias_keymaxbits; } if(sa_p->ips_key_bits_e<keyminbits || sa_p->ips_key_bits_e>keymaxbits) { KLIPS_PRINT(debug_pfkey, "klips_debug:ipsec_alg_enc_key_create: " "incorrect encryption key size for id=%d: %d bits -- " "must be between %d,%d bits\n" /*octets (bytes)\n"*/, ixt_e->ixt_common.ixt_support.ias_id, sa_p->ips_key_bits_e, keyminbits, keymaxbits); ret=-EINVAL; goto ixt_out; } /* save encryption key pointer */ ekp = sa_p->ips_key_e; if (ixt_e->ixt_e_new_key) { sa_p->ips_key_e = ixt_e->ixt_e_new_key(ixt_e, ekp, sa_p->ips_key_bits_e/8); ret = (sa_p->ips_key_e)? 0 : -EINVAL; } else { if((sa_p->ips_key_e = (caddr_t) kmalloc((sa_p->ips_key_e_size = ixt_e->ixt_e_ctx_size),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -