/* $Id$ */ /*** 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 #include #include #include #include struct in_device; #include #include #include #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, const struct net_device *in, const struct net_device *out, unsigned int hooknum, const void *_ti, void *userinfo) { const struct ipt_crypt_info *ti = _ti; struct iphdr *ih; unsigned d, new_l, crypt_l, ihl; struct seppl_uncrypt_hdr *uh; struct seppl_crypt_hdr *ch; u8 *iv, *pl; int ivs = ti->key->ivsize; int bs = ti->key->blocksize; struct scatterlist sg[1]; if (!skb_ip_make_writable(pskb, (*pskb)->len)) { if (net_ratelimit()) printk(KERN_ERR "ipt_DECRYPT: Failed to make skb writable.\n"); return NF_DROP; } ih = (*pskb)->nh.iph; ihl = ih->ihl<<2; // 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); // Encrypt to make it randomish sg[0].page = virt_to_page((void*) iv); sg[0].offset = (((long) (void *) iv) & ~PAGE_MASK); sg[0].length = ivs; crypto_cipher_encrypt(ti->key->tfm_ecb, sg, sg, sg[0].length ); // 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_check, ipt_CRYPT_destroy, ipt_CRYPT_target, 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);