| |
| #include "ipf-linux.h" |
| #include <linux/devfs_fs_kernel.h> |
| |
| #ifdef CONFIG_PROC_FS |
| #include <linux/proc_fs.h> |
| #endif |
| |
| extern wait_queue_head_t iplh_linux[IPL_LOGSIZE]; |
| |
| #ifdef MODULE |
| MODULE_SUPPORTED_DEVICE("ipf"); |
| MODULE_AUTHOR("Darren Reed"); |
| MODULE_DESCRIPTION("IP-Filter Firewall"); |
| MODULE_LICENSE("(C)Copyright 2003-2004 Darren Reed"); |
| |
| MODULE_PARM(ipf_flags, "i"); |
| MODULE_PARM(fr_control_forwarding, "i"); |
| MODULE_PARM(fr_update_ipid, "i"); |
| MODULE_PARM(fr_chksrc, "i"); |
| MODULE_PARM(fr_pass, "i"); |
| MODULE_PARM(ipstate_logging, "i"); |
| MODULE_PARM(nat_logging, "i"); |
| MODULE_PARM(ipl_suppress, "i"); |
| MODULE_PARM(ipl_logall, "i"); |
| #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; |
| |
| |
| |
| 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 : |
| #ifdef IPFILTER_LOOKUP |
| case IPL_LOGLOOKUP : |
| #endif |
| #ifdef IPFILTER_SYNC |
| case IPL_LOGSYNC : |
| #endif |
| #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) |
| { |
| #ifdef IPFILTER_SYNC |
| 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 = ipfsync_write(&uio); |
| if (err > 0) |
| err = -err; |
| return err; |
| #else |
| return -ENXIO; |
| #endif |
| } |
| |
| |
| 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) |
| { |
| #ifdef IPFILTER_SYNC |
| case IPL_LOGSYNC : |
| err = ipfsync_read(&uio); |
| break; |
| #endif |
| default : |
| err = ipflog_read(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, &iplh_linux[unit], wait); |
| |
| switch (unit) |
| { |
| case IPL_LOGIPF : |
| case IPL_LOGNAT : |
| case IPL_LOGSTATE : |
| # ifdef IPFILTER_LOG |
| if (ipflog_canread(unit)) |
| revents = (POLLIN | POLLRDNORM); |
| # endif |
| break; |
| case IPL_LOGAUTH : |
| if (fr_auth_waiting()) |
| revents = (POLLIN | POLLRDNORM); |
| break; |
| case IPL_LOGSYNC : |
| # ifdef IPFILTER_SYNC |
| if (ipfsync_canread()) |
| revents = (POLLIN | POLLRDNORM); |
| # endif |
| break; |
| case IPL_LOGSCAN : |
| case IPL_LOGLOOKUP : |
| default : |
| break; |
| } |
| |
| return revents; |
| } |
| #endif |
| |
| |
| #ifdef CONFIG_PROC_FS |
| static int ipf_proc_info(char *buffer, char **start, off_t offset, int len) |
| { |
| snprintf(buffer, len, "ipfmajor %d", ipfmajor); |
| buffer[len - 1] = '\0'; |
| return strlen(buffer); |
| } |
| #endif |
| |
| static int ipfilter_init(void) |
| { |
| #ifdef CONFIG_DEVFS_FS |
| char *s; |
| #endif |
| 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++) { |
| 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 |
| |
| RWLOCK_INIT(&ipf_global, "ipf global rwlock"); |
| RWLOCK_INIT(&ipf_mutex, "ipf global mutex rwlock"); |
| RWLOCK_INIT(&ipf_frcache, "ipf cache mutex rwlock"); |
| |
| i = ipfattach(); |
| |
| #ifdef CONFIG_PROC_FS |
| if (i == 0) { |
| struct proc_dir_entry *ipfproc; |
| char *defpass; |
| |
| ipfproc = proc_net_create("ipfilter", 0, ipf_proc_info); |
| # ifndef __GENKSYMS__ |
| if (ipfproc != NULL) |
| ipfproc->owner = THIS_MODULE; |
| # endif |
| if (FR_ISPASS(fr_pass)) |
| defpass = "pass"; |
| else if (FR_ISBLOCK(fr_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 |
| ); |
| |
| fr_running = 1; |
| } |
| #else |
| printf("IPFilter: device major number: %d\n", ipfmajor); |
| #endif /* CONFIG_PROC_FS */ |
| |
| if (i != 0) { |
| RW_DESTROY(&ipf_global); |
| RW_DESTROY(&ipf_mutex); |
| RW_DESTROY(&ipf_frcache); |
| } |
| |
| return i; |
| } |
| |
| |
| static int ipfilter_fini(void) |
| { |
| int result; |
| #ifdef CONFIG_DEVFS_FS |
| char *s; |
| int i; |
| #endif |
| |
| if (ipf_refcnt) |
| return EBUSY; |
| |
| if (fr_running >= 0) { |
| result = ipfdetach(); |
| if (result != 0) { |
| if (result > 0) |
| result = -result; |
| return result; |
| } |
| } |
| |
| RW_DESTROY(&ipf_global); |
| RW_DESTROY(&ipf_mutex); |
| RW_DESTROY(&ipf_frcache); |
| |
| fr_running = -2; |
| #ifdef CONFIG_PROC_FS |
| proc_net_remove("ipfilter"); |
| #endif |
| |
| |
| #ifdef CONFIG_DEVFS_FS |
| for (i = 0; ipf_devfiles[i] != NULL; i++) { |
| 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) |