summaryrefslogtreecommitdiffstats
path: root/kernel/ipt_DECRYPT.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/ipt_DECRYPT.c')
-rw-r--r--kernel/ipt_DECRYPT.c197
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;