diff options
author | Lennart Poettering <lennart@poettering.net> | 2003-11-05 10:44:19 +0000 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2003-11-05 10:44:19 +0000 |
commit | 7ec5099b5f5c79419a54a6cdedea618d98b60569 (patch) | |
tree | f1bed2425e622919435fe4580b15dbfddb3137bf /kernel/ipt_DECRYPT.c | |
parent | 8bc528bfd9d8c17d25eec2ca1686513679ba3e55 (diff) |
Commit initial version
git-svn-id: file:///home/lennart/svn/public/seppl/trunk@2 91a2fd9b-5dcb-0310-a70a-d71e310228e6
Diffstat (limited to 'kernel/ipt_DECRYPT.c')
-rw-r--r-- | kernel/ipt_DECRYPT.c | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/kernel/ipt_DECRYPT.c b/kernel/ipt_DECRYPT.c new file mode 100644 index 0000000..75db2bd --- /dev/null +++ b/kernel/ipt_DECRYPT.c @@ -0,0 +1,197 @@ +/* $Id: newmail.c 31 2003-10-22 22:59:07Z lennart $ */ + +/*** + This file is part of seppl + + seppl 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. + + seppl 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. + + You should have received a copy of the GNU General Public License + along with seppl; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA +***/ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/skbuff.h> +#include <linux/ip.h> +#include <net/ip.h> +#include <net/checksum.h> +struct in_device; +#include <net/route.h> +#include <linux/netfilter_ipv4/ip_tables.h> +#include <asm/scatterlist.h> + +#include "seppl.h" +#include "ipt_DECRYPT.h" + +#ifdef MODULE_LICENSE +MODULE_LICENSE("GPL"); +#endif +#ifdef MODULE_DESCRIPTION +MODULE_DESCRIPTION ("SEPPL iptables Decryption Target"); +#endif +#ifdef MODULE_AUTHOR +MODULE_AUTHOR("Lennart Poettering <"PACKAGE_BUGREPORT">"); +#endif + +static unsigned int ipt_DECRYPT_target(struct sk_buff **pskb, unsigned int hooknum, const struct net_device *in, const struct net_device *out, const void *_ti, void *userinfo) { + struct iphdr *ih = (*pskb)->nh.iph; + unsigned ihl = ih->ihl<<2; + struct seppl_key *key; + struct seppl_uncrypt_hdr *uh; + struct seppl_crypt_hdr *ch; + u8* iv, *pl; + int ivs; + int crypt_l, bs; + struct scatterlist sg[1]; + + if (ih->protocol != SEPPL_PROTOCOL) { + if (net_ratelimit()) + printk(KERN_ERR "ipt_DECRYPT: Incorrect protocol\n"); + return NF_DROP; + } + + if (ntohs(ih->tot_len) <= ihl+sizeof(struct seppl_uncrypt_hdr)) { + if (net_ratelimit()) + printk(KERN_ERR "ipt_DECRYPT: Packet too short (1)\n"); + return NF_DROP; + } + + uh = (struct seppl_uncrypt_hdr*) ((u8*) ih + ihl); /* Unencrypted header */ + + if (!(key = seppl_claim_key(uh->algorithm, uh->key_name))) { + if (net_ratelimit()) + printk(KERN_ERR "ipt_DECRYPT: Recieved packet with unknown decryption key.\n"); + return NF_DROP; + } + + ivs = key->ivsize; + bs = key->blocksize; + + if (ntohs(ih->tot_len) <= ihl+sizeof(struct seppl_uncrypt_hdr)+ivs+sizeof(struct seppl_crypt_hdr)) { + if (net_ratelimit()) + printk(KERN_ERR "ipt_DECRYPT: Packet too short (2)\n"); + seppl_release_key(key); + return NF_DROP; + } + + crypt_l = ntohs(ih->tot_len)-ihl-sizeof(struct seppl_uncrypt_hdr)-ivs; + + if (crypt_l % bs) { + if (net_ratelimit()) + printk(KERN_ERR "ipt_DECRYPT: Packet too short (3)\n"); + seppl_release_key(key); + return NF_DROP; + } + + iv = ((u8*) uh) + sizeof(struct seppl_uncrypt_hdr); /* IV */ + ch = (struct seppl_crypt_hdr*) (iv + ivs); /* Crypted header */ + pl = ((u8*) ch) + sizeof(struct seppl_crypt_hdr); /* Payload */ + + sg[0].page = virt_to_page(ch); + sg[0].offset = ((long) ch & ~PAGE_MASK); + sg[0].length = crypt_l; + + crypto_cipher_set_iv(key->tfm, iv, key->ivsize); + + if (crypto_cipher_decrypt(key->tfm, sg, sg, sg[0].length)) { + if (net_ratelimit()) + printk(KERN_ERR "ipt_DECRYPT: decrypt() failure\n"); + seppl_release_key(key); + return NF_DROP; + } + + seppl_release_key(key); + + if (ch->ident != 0x00) { + if (net_ratelimit()) + printk(KERN_ERR "ipt_DECRYPT: Key not matching\n"); + return NF_DROP; + } + + if (ntohs(ch->saved_tot_len) > + ntohs(ih->tot_len) - + sizeof(struct seppl_uncrypt_hdr)- + ivs- + sizeof(struct seppl_crypt_hdr)) { + + if (net_ratelimit()) + printk(KERN_ERR "ipt_DECRYPT: Packet too short (4)"); + return NF_DROP; + } + + //DEBUGP("DECRYPT: tot_len=%i, real_l=%i, crypt_l=%i\n", htons(ih->tot_len), ntohs(ch->saved_tot_len), crypt_l); + + // Restore the IP header + ih->protocol = ch->saved_protocol; + ih->tot_len = ch->saved_tot_len; + ih->frag_off = ch->saved_frag_off; + + // The pay load + memmove(uh, pl, ntohs(ih->tot_len)-ihl); + + // Checksum + ih->check = 0; + ih->check = ip_fast_csum((char *) ih, ih->ihl); + + skb_trim(*pskb, ntohs(ih->tot_len)); + + // Finish + (*pskb)->ip_summed = CHECKSUM_NONE; + (*pskb)->nfcache |= NFC_UNKNOWN | NFC_ALTERED; + + return IPT_CONTINUE; +} + +static int ipt_DECRYPT_check(const char *table, const struct ipt_entry *e, void *_ti, unsigned int ti_size, unsigned int hook_mask) { + if (ti_size != IPT_ALIGN(sizeof(struct ipt_decrypt_info))) { + printk(KERN_ERR "ipt_DECRYPT: Structure too small"); + return 0; + } + + if (strcmp(table, "mangle") != 0) { + printk(KERN_ERR "ipt_DECRYPT: Not in mangle table\n"); + return 0; + } + + if ((hook_mask & ~(1 << NF_IP_PRE_ROUTING)) != 0) { + printk(KERN_ERR "ipt_DECRYPT: Not in PREROUTING chain"); + return 0; + } + + return 1; +} + +static struct ipt_target ipt_DECRYPT_reg = { + { NULL, NULL }, + "DECRYPT", + ipt_DECRYPT_target, + ipt_DECRYPT_check, + NULL, + THIS_MODULE +}; + +static int __init init(void) { + if (ipt_register_target(&ipt_DECRYPT_reg)) + return -EINVAL; + + return 0; +} + +static void __exit fini(void) { + ipt_unregister_target(&ipt_DECRYPT_reg); +} + +module_init(init); +module_exit(fini); + +EXPORT_NO_SYMBOLS; |