blob: 994037abe3f2b1386e324283afa8a67c49c2febf [file] [log] [blame] [raw]
#include "ipf-linux.h"
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
# include <linux/devfs_fs_kernel.h>
#endif
#ifdef MODULE
MODULE_SUPPORTED_DEVICE("ipf");
MODULE_AUTHOR("Darren Reed");
MODULE_DESCRIPTION("IP-Filter Firewall");
MODULE_LICENSE("(C)Copyright (C) 2012 by Darren Reed.");
#endif
static int ipf_open(struct inode *, struct file *);
static ssize_t ipf_write(struct file *, const char *, size_t, loff_t *);
static ssize_t ipf_read(struct file *, char *, size_t, loff_t *);
static u_int ipf_poll(struct file *fp, struct poll_table_struct *wait);
extern int ipf_ioctl(struct inode *, struct file *, u_int, u_long);
#ifdef CONFIG_DEVFS_FS
static char *ipf_devfiles[] = { IPL_NAME, IPNAT_NAME, IPSTATE_NAME,
IPAUTH_NAME, IPSYNC_NAME, IPSCAN_NAME,
IPLOOKUP_NAME, NULL };
#endif
static struct file_operations ipf_fops = {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
.owner = THIS_MODULE,
#endif
open: ipf_open,
read: ipf_read,
write: ipf_write,
ioctl: ipf_ioctl,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
poll: ipf_poll,
#endif
};
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
static devfs_handle_t dh[IPL_LOGSIZE];
#endif
static int ipfmajor = 0;
ipf_main_softc_t ipfmain;
int
uiomove(address, nbytes, rwflag, uiop)
caddr_t address;
size_t nbytes;
int rwflag;
uio_t *uiop;
{
int err = 0;
if (rwflag == UIO_READ) {
err = copy_to_user(uiop->uio_buf, address, nbytes);
if (err == 0) {
uiop->uio_resid -= nbytes;
uiop->uio_buf += nbytes;
}
} else if (rwflag == UIO_WRITE) {
err = copy_from_user(uiop->uio_buf, address, nbytes);
if (err == 0) {
uiop->uio_resid -= nbytes;
uiop->uio_buf += nbytes;
}
}
if (err)
return -EFAULT;
return 0;
}
static int
ipf_open(struct inode *in, struct file *fp)
{
int unit, err;
unit = MINOR(in->i_rdev);
if (unit < 0 || unit > IPL_LOGMAX) {
err = -ENXIO;
} else {
switch (unit)
{
case IPL_LOGIPF :
case IPL_LOGNAT :
case IPL_LOGSTATE :
case IPL_LOGAUTH :
case IPL_LOGLOOKUP :
case IPL_LOGSYNC :
#ifdef IPFILTER_SCAN
case IPL_LOGSCAN :
#endif
err = 0;
break;
default :
err = -ENXIO;
break;
}
}
return err;
}
static ssize_t
ipf_write(struct file *fp, const char *buf, size_t count, loff_t *posp)
{
struct inode *i;
int unit, err;
uio_t uio;
i = fp->f_dentry->d_inode;
unit = MINOR(i->i_rdev);
if (unit != IPL_LOGSYNC)
return -ENXIO;
uio.uio_rw = UIO_WRITE;
uio.uio_iov = NULL;
uio.uio_file = fp;
uio.uio_buf = (char *)buf;
uio.uio_iovcnt = 0;
uio.uio_offset = *posp;
uio.uio_resid = count;
err = ipf_sync_write(&ipfmain, &uio);
if (err > 0)
err = -err;
return err;
}
static ssize_t
ipf_read(struct file *fp, char *buf, size_t count, loff_t *posp)
{
struct inode *i;
int unit, err;
uio_t uio;
i = fp->f_dentry->d_inode;
unit = MINOR(i->i_rdev);
uio.uio_rw = UIO_READ;
uio.uio_iov = NULL;
uio.uio_file = fp;
uio.uio_buf = (char *)buf;
uio.uio_iovcnt = 0;
uio.uio_offset = *posp;
uio.uio_resid = count;
switch (unit)
{
case IPL_LOGSYNC :
err = ipf_sync_read(&ipfmain, &uio);
break;
default :
err = ipf_log_read(&ipfmain, unit, &uio);
if (err == 0)
return count - uio.uio_resid;
break;
}
if (err > 0)
err = -err;
return err;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
static u_int
ipf_poll(struct file *fp, poll_table *wait)
{
struct inode *i;
u_int revents;
int unit;
revents = 0;
i = fp->f_dentry->d_inode;
unit = MINOR(i->i_rdev);
if (unit < 0 || unit > IPL_LOGMAX)
return 0;
poll_wait(fp, &ipfmain.iplh_linux[unit], wait);
switch (unit)
{
case IPL_LOGIPF :
case IPL_LOGNAT :
case IPL_LOGSTATE :
# ifdef IPFILTER_LOG
if (ipf_log_canread(&ipfmain, unit))
revents = (POLLIN | POLLRDNORM);
# endif
break;
case IPL_LOGAUTH :
if (ipf_auth_waiting(&ipfmain))
revents = (POLLIN | POLLRDNORM);
break;
case IPL_LOGSYNC :
if (ipf_sync_canread(&ipfmain))
revents = (POLLIN | POLLRDNORM);
break;
case IPL_LOGSCAN :
case IPL_LOGLOOKUP :
default :
break;
}
return revents;
}
#endif
static int
ipfilter_init(void)
{
char *defpass;
int i;
ipfmajor = register_chrdev(0, "ipf", &ipf_fops);
if (ipfmajor < 0) {
printf("unable to get major for ipf devs (%d)\n", ipfmajor);
return -EINVAL;
}
#ifdef CONFIG_DEVFS_FS
for (i = 0; ipf_devfiles[i] != NULL; i++) {
char *s;
s = strrchr(ipf_devfiles[i], '/');
if (s != NULL) {
# if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
dh[i] = devfs_register(NULL, s + 1, DEVFS_FL_DEFAULT,
ipfmajor, i, 0600|S_IFCHR,
&ipf_fops, NULL);
# else
devfs_mk_cdev(MKDEV(ipfmajor, i),0600|S_IFCHR,s+1);
# endif
}
}
#endif
i = ipf_load_all();
if (i != 0)
return i;
ipf_create_all(&ipfmain);
i = ipfattach(&ipfmain);
if (i != 0) {
ipf_destroy_all(&ipfmain);
ipf_unload_all();
return i;
}
if (FR_ISPASS(ipfmain.ipf_pass))
defpass = "pass";
else if (FR_ISBLOCK(ipfmain.ipf_pass))
defpass = "block";
else
defpass = "no-match -> block";
printk(KERN_INFO "%s initialized. Default = %s all, Logging = %s%s\n",
ipfilter_version, defpass,
# ifdef IPFILTER_LOG
"enabled",
# else
"disabled",
# endif
# ifdef IPFILTER_COMPILED
" (COMPILED)"
# else
""
# endif
);
ipfmain.ipf_running = 1;
return 0;
}
static int
ipfilter_fini(void)
{
int result;
#ifdef CONFIG_DEVFS_FS
int i;
#endif
if (ipfmain.ipf_refcnt)
return -EBUSY;
if (ipfmain.ipf_running >= 0) {
result = ipfdetach(&ipfmain);
if (result != 0) {
if (result > 0)
result = -result;
return result;
} else {
ipf_destroy_all(&ipfmain);
ipf_unload_all();
}
}
ipfmain.ipf_running = -2;
#ifdef CONFIG_DEVFS_FS
for (i = 0; ipf_devfiles[i] != NULL; i++) {
char *s;
s = strrchr(ipf_devfiles[i], '/');
if (s != NULL)
# if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
devfs_unregister_chrdev(ipfmajor, s + 1);
# else
devfs_remove(s+1);
# endif
}
#endif
if (ipfmajor >= 0)
unregister_chrdev(ipfmajor, "ipf");
printk(KERN_INFO "%s unloaded\n", ipfilter_version);
return 0;
}
static int __init
ipf_init(void)
{
int result;
result = ipfilter_init();
return result;
}
static void __exit ipf_fini(void)
{
(void) ipfilter_fini();
}
module_init(ipf_init)
module_exit(ipf_fini)