/* This is an conntrack extension loadable kernel module that write finished connections from inside the Linux kernel. Original version By Bryan Henderson, bryanh@giraffe-data.com . I compiled this with: gcc -c filewrite.c -I/usr/src/linux/include -DMODULE -D__KERNEL__ on the resulting It creates the file with name supplied in MODULE_PARM */ #include #include #include #include /* For get_fs() */ #include #include #include #include #include //#include #if 1 /* control */ #define DEBUG(format,args...) printk(KERN_DEBUG "ipt_CONNLOG:"format,##args) #else #define DEBUG(format,args...) #endif void (*ip_conntrack_prev_destroyed)(struct ip_conntrack *conntrack) = NULL; static struct file * fileP; static char* fname; MODULE_PARM(fname, "s"); static void __exit fini(void) { if (!IS_ERR(fileP)) { filp_close(fileP, NULL); } ip_conntrack_destroyed = ip_conntrack_prev_destroyed; return; } static int write_log(const char* buffer, int buffsize) { ssize_t rc=buffsize; mm_segment_t oldfs; //fileP->f_pos = 0; /* As the write operation for this file gets the the data to write from the user's address space (fs), we must switch fs to be the kernel address space while we do this write, and then restore it afterwards. */ DEBUG("Calling filesystem write %s\n", buffer); oldfs = get_fs(); set_fs(get_ds()); rc = fileP->f_op->write(fileP, buffer, buffsize, &fileP->f_pos); set_fs(oldfs); if (rc < 0) { printk("%s: filesystem driver's write() operation for " "returned errno %d.\n", __FUNCTION__, -rc); } else if (rc != buffsize) { printk("%s: write returned only %d bytes instead of %d.\n", __FUNCTION__, rc, buffsize); } else DEBUG("%s: write was successful.\n", __FUNCTION__); return 0; } static int open_log(void) { int error=0; fileP = filp_open(fname, O_CREAT|O_APPEND, 0644); if (IS_ERR(fileP)) { error = -PTR_ERR(fileP); DEBUG("%s: error opening file. errno=%d\n", __FUNCTION__, error); goto out; } else { DEBUG("%s: File successfully opened, with file pointer at %p\n", __FUNCTION__, fileP); if (!fileP->f_op) { printk("%s: File has no file operations registered!\n", __FUNCTION__); error = (-EIO); goto out_err; } else { /* ssize_t (*writeOp) (struct file *, const char *, size_t, loff_t *) = fileP->f_op->write; */ if (fileP->f_op->write == NULL) { printk("%s: File has no write operation registered!\n", __FUNCTION__); error = (-EIO); goto out_err; } } } return error; out_err: filp_close(fileP, NULL); out: return error; } /* * Max length of ip-address in string XXX.XXX.XXX.XXX = 15 * Max lenght of port# and protocol-number in string 65536 = 5 * Max length od Application name ipt_APPCLASS = 32 * TODO: Packets transfered and bytes transfered * SIZE = 15*2 + 5*2 + 5 + 32 + 1 (\n) = 78+2 SPACES-IN-FORMAT */ #define CONN_BUFF_SIZE 80 static void ip_conntrack_log(struct ip_conntrack *conn) { static char appname[] = "Elitecore"; static char conninfo[CONN_BUFF_SIZE]; struct ip_conntrack_tuple tp = conn->tuplehash[IP_CT_DIR_ORIGINAL].tuple; int buffsize; buffsize=snprintf(conninfo, CONN_BUFF_SIZE, "%s: %u %u.%u.%u.%u:%hu %u.%u.%u.%u:%hu\n", \ appname, (tp).dst.protonum, \ NIPQUAD((tp).src.ip), ntohs((tp).src.u.all), \ NIPQUAD((tp).dst.ip), ntohs((tp).dst.u.all)); write_log(conninfo, buffsize); if(ip_conntrack_prev_destroyed != NULL ) ip_conntrack_prev_destroyed(conn); return; } static int __init init(void) { int error=0; DEBUG("%s: function entered. Our address=%p.\n", __FUNCTION__, &init); if(fname == NULL) { return (-EINVAL); } error=open_log(); if (error < 0) return error; /* FIXME: Man, this is a hack. */ if(ip_conntrack_destroyed == NULL) { printk(KERN_WARNING "ipt_CONNLOG: You may not get log if you load nat module after this\n"); } else { ip_conntrack_prev_destroyed = ip_conntrack_destroyed; } ip_conntrack_destroyed = &ip_conntrack_log; return 0; } module_init(init); module_exit(fini); MODULE_LICENSE("GPL");