summaryrefslogtreecommitdiffstats
path: root/kernel/ipt_CRYPT.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/ipt_CRYPT.c')
-rw-r--r--kernel/ipt_CRYPT.c190
1 files changed, 190 insertions, 0 deletions
diff --git a/kernel/ipt_CRYPT.c b/kernel/ipt_CRYPT.c
new file mode 100644
index 0000000..9f7d055
--- /dev/null
+++ b/kernel/ipt_CRYPT.c
@@ -0,0 +1,190 @@
+/* $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_CRYPT.h"
+
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+#ifdef MODULE_DESCRIPTION
+MODULE_DESCRIPTION("SEPPL iptables Encryption Target");
+#endif
+#ifdef MODULE_AUTHOR
+MODULE_AUTHOR("Lennart Poettering <"PACKAGE_BUGREPORT">");
+#endif
+
+static unsigned int ipt_CRYPT_target(struct sk_buff **pskb, unsigned int hooknum, const struct net_device *in, const struct net_device *out, const void *_ti, void *userinfo) {
+ const struct ipt_crypt_info *ti = _ti;
+ struct iphdr *ih = (*pskb)->nh.iph;
+ unsigned d, new_l, crypt_l, ihl = ih->ihl<<2;
+ struct seppl_uncrypt_hdr *uh;
+ struct seppl_crypt_hdr *ch;
+ u8 *iv, *pl;
+ int ivs = ti->key->ivsize;
+ int bs = ti->key->blocksize;
+ struct sock *sk;
+ struct scatterlist sg[1];
+
+ // Calculate new packet size
+ new_l = ihl + sizeof(struct seppl_uncrypt_hdr) + ivs + ((sizeof(struct seppl_crypt_hdr) + ntohs(ih->tot_len) - ihl + bs - 1) / bs) * bs;
+ d = new_l - htons(ih->tot_len);
+ crypt_l = new_l - ihl - sizeof(struct seppl_uncrypt_hdr) - ivs;
+
+ //DEBUGP("CRYPT: tot_len=%i, new_l=%i, d=%i, crypt_l=%i\n", htons(ih->tot_len), new_l, d, crypt_l);
+
+ // Copy the skb if needed and increase it correctly
+ if (skb_tailroom(*pskb) < d || skb_cloned(*pskb)) {
+ struct sk_buff *n;
+
+ if (!(n = skb_copy_expand(*pskb, skb_headroom(*pskb), d, GFP_ATOMIC))) {
+ if (net_ratelimit())
+ printk(KERN_ERR "ipt_CRYPT: Unable to allocate larger skb, dropping packet.\n");
+
+ return NF_DROP;
+ }
+
+ if ((*pskb)->sk)
+ skb_set_owner_w(n, (*pskb)->sk);
+
+ kfree_skb(*pskb);
+ *pskb = n;
+ ih = (*pskb)->nh.iph;
+ }
+
+ skb_put(*pskb, d);
+
+ // Calculate some pointers
+ //ih = ... /* IP-Header */
+ uh = (struct seppl_uncrypt_hdr*) ((u8*) ih + ihl); /* Unencrypted header */
+ 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 */
+
+ // Copy the payload
+ memmove(pl, uh, ntohs(ih->tot_len) - ihl);
+
+ // Fill the uncrypted header
+ uh->algorithm = ti->key->algorithm;
+ strncpy(uh->key_name, ti->key->name, 7);
+
+ // Copy the IV
+ seppl_copy_iv(ti->key, iv);
+
+ // Fill the crypted header
+ ch->ident = 0x00;
+ ch->saved_protocol = ih->protocol;
+ ch->saved_tot_len = ih->tot_len;
+ ch->saved_frag_off = ih->frag_off;
+
+ // Fill the IP header
+ ih->protocol = SEPPL_PROTOCOL;
+ ih->tot_len = htons(new_l);
+ ih->frag_off = 0;
+
+ // Checksum FIXME: Is this really needed?
+ ih->check = 0;
+ ih->check = ip_fast_csum((char *) ih, ih->ihl);
+
+ // Crypt
+ sg[0].page = virt_to_page((void*) ch);
+ sg[0].offset = (((long) (void *) ch) & ~PAGE_MASK);
+ sg[0].length = crypt_l;
+
+ crypto_cipher_set_iv(ti->key->tfm, iv, ti->key->ivsize);
+
+ if (crypto_cipher_encrypt(ti->key->tfm, sg, sg, sg[0].length)) {
+ if (net_ratelimit())
+ printk(KERN_ERR "ipt_CRYPT: encrypt() failure\n");
+ return NF_DROP;
+ }
+
+ // Finish
+ (*pskb)->ip_summed = CHECKSUM_NONE;
+ (*pskb)->nfcache |= NFC_UNKNOWN | NFC_ALTERED;
+
+ return IPT_CONTINUE;
+}
+
+static int ipt_CRYPT_check(const char *table, const struct ipt_entry *e, void *_ti, unsigned int ti_size, unsigned int hook_mask) {
+ struct ipt_crypt_info *ti = _ti;
+
+ if (ti_size != IPT_ALIGN(sizeof(struct ipt_crypt_info))) {
+ printk(KERN_ERR "ipt_CRYPT: Structure too small\n");
+ return 0;
+ }
+
+ if (strcmp(table, "mangle") != 0) {
+ printk(KERN_ERR "ipt_CRYPT: Not in mangle table\n");
+ return 0;
+ }
+
+ if ((hook_mask & ~(1 << NF_IP_POST_ROUTING)) != 0) {
+ printk(KERN_ERR "ipt_CRYPT: Not in POSTROUTING chain\n");
+ return 0;
+ }
+
+ if (!(ti->key = seppl_claim_key(ti->algorithm, ti->name))) {
+ printk(KERN_ERR "ipt_CRYPT: Cannot find key\n");
+ return 0;
+ }
+
+ return 1;
+}
+
+static void ipt_CRYPT_destroy(void *_ti, unsigned int ti_size) {
+ struct ipt_crypt_info *ti = _ti;
+
+ seppl_release_key(ti->key);
+}
+
+static struct ipt_target ipt_CRYPT_reg = {
+ { NULL, NULL },
+ "CRYPT",
+ ipt_CRYPT_target,
+ ipt_CRYPT_check,
+ ipt_CRYPT_destroy,
+ THIS_MODULE
+};
+
+static int __init init(void) {
+ return ipt_register_target(&ipt_CRYPT_reg);
+}
+
+static void __exit fini(void) {
+ ipt_unregister_target(&ipt_CRYPT_reg);
+}
+
+module_init(init);
+module_exit(fini);
+
+EXPORT_NO_SYMBOLS;