/* $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 #if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) #define MODVERSIONS #endif #if defined(MODVERSIONS) && !defined(__GENKSYMS__) #include #include "seppl.ver" #endif #include #include #include #include #include struct in_device; #include #include #include #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, const struct net_device *in, const struct net_device *out, unsigned int hooknum, const void *_ti, void *userinfo) { struct iphdr *ih; unsigned ihl; 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 (!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; if (ih->protocol != SEPPL_PROTOCOL) { if (net_ratelimit()) printk(KERN_ERR "ipt_DECRYPT: Incorrect protocol 0x%02x\n", ih->protocol); 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_check, NULL, ipt_DECRYPT_target, 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);