diff options
Diffstat (limited to 'mlf_ipl.c')
-rw-r--r-- | mlf_ipl.c | 467 |
1 files changed, 467 insertions, 0 deletions
diff --git a/mlf_ipl.c b/mlf_ipl.c new file mode 100644 index 0000000..b39a14d --- /dev/null +++ b/mlf_ipl.c @@ -0,0 +1,467 @@ +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +/* + * 29/12/94 Added code from Marc Huber <huber@fzi.de> to allow it to allocate + * its own major char number! Way cool patch! + */ + + +#include <sys/param.h> + +#ifdef IPFILTER_LKM +# ifndef __FreeBSD_cc_version +# include <osreldate.h> +# else +# if __FreeBSD_cc_version < 430000 +# include <osreldate.h> +# endif +# endif +# define ACTUALLY_LKM_NOT_KERNEL +#else +# ifndef __FreeBSD_cc_version +# include <sys/osreldate.h> +# else +# if __FreeBSD_cc_version < 430000 +# include <sys/osreldate.h> +# endif +# endif +#endif +#include <sys/systm.h> +#if defined(__FreeBSD_version) && (__FreeBSD_version >= 220000) +# ifndef ACTUALLY_LKM_NOT_KERNEL +# include "opt_devfs.h" +# endif +# include <sys/conf.h> +# include <sys/kernel.h> +# ifdef DEVFS +# include <sys/devfsext.h> +# endif /*DEVFS*/ +#endif +#include <sys/conf.h> +#include <sys/file.h> +#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) +# include <sys/lock.h> +#endif +#include <sys/stat.h> +#include <sys/proc.h> +#include <sys/kernel.h> +#include <sys/vnode.h> +#include <sys/namei.h> +#include <sys/malloc.h> +#include <sys/mount.h> +#include <sys/exec.h> +#include <sys/mbuf.h> +#if BSD >= 199506 +# include <sys/sysctl.h> +#endif +#if (__FreeBSD_version >= 300000) +# include <sys/socket.h> +#endif +#include <net/if.h> +#include <netinet/in_systm.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <net/route.h> +#include <netinet/ip_var.h> +#include <netinet/tcp.h> +#include <netinet/tcpip.h> +#include <sys/sysent.h> +#include <sys/lkm.h> +#include "netinet/ipl.h" +#include "netinet/ip_compat.h" +#include "netinet/ip_fil.h" +#include "netinet/ip_state.h" +#include "netinet/ip_nat.h" +#include "netinet/ip_auth.h" +#include "netinet/ip_frag.h" + + +#if !defined(VOP_LEASE) && defined(LEASE_CHECK) +#define VOP_LEASE LEASE_CHECK +#endif + +int xxxinit __P((struct lkm_table *, int, int)); + +#ifdef SYSCTL_OID +int sysctl_ipf_int SYSCTL_HANDLER_ARGS; +# define SYSCTL_IPF(parent, nbr, name, access, ptr, val, descr) \ + SYSCTL_OID(parent, nbr, name, CTLTYPE_INT|access, \ + ptr, val, sysctl_ipf_int, "I", descr); +# define CTLFLAG_OFF 0x00800000 /* IPFilter must be disabled */ +# define CTLFLAG_RWO (CTLFLAG_RW|CTLFLAG_OFF) +SYSCTL_NODE(_net_inet, OID_AUTO, ipf, CTLFLAG_RW, 0, "IPF"); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_flags, CTLFLAG_RW, &fr_flags, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_pass, CTLFLAG_RW, &fr_pass, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_active, CTLFLAG_RD, &fr_active, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_chksrc, CTLFLAG_RW, &fr_chksrc, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_minttl, CTLFLAG_RW, &fr_minttl, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpidletimeout, CTLFLAG_RWO, + &fr_tcpidletimeout, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcphalfclosed, CTLFLAG_RWO, + &fr_tcphalfclosed, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpclosewait, CTLFLAG_RWO, + &fr_tcpclosewait, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcplastack, CTLFLAG_RWO, + &fr_tcplastack, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcptimeout, CTLFLAG_RWO, + &fr_tcptimeout, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpclosed, CTLFLAG_RWO, + &fr_tcpclosed, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_udptimeout, CTLFLAG_RWO, + &fr_udptimeout, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_icmptimeout, CTLFLAG_RWO, + &fr_icmptimeout, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_defnatage, CTLFLAG_RWO, + &fr_defnatage, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_ipfrttl, CTLFLAG_RW, + &fr_ipfrttl, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_running, CTLFLAG_RD, + &fr_running, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_statesize, CTLFLAG_RWO, + &fr_statesize, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_statemax, CTLFLAG_RWO, + &fr_statemax, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_authsize, CTLFLAG_RWO, + &fr_authsize, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_authused, CTLFLAG_RD, + &fr_authused, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_defaultauthage, CTLFLAG_RW, + &fr_defaultauthage, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ippr_ftp_pasvonly, CTLFLAG_RW, + &ippr_ftp_pasvonly, 0, ""); +#endif + +#ifdef DEVFS +static void *ipf_devfs[IPL_LOGSIZE]; +#endif + +#if !defined(__FreeBSD_version) || (__FreeBSD_version < 220000) +int ipl_major = 0; + +static struct cdevsw ipldevsw = +{ + iplopen, /* open */ + iplclose, /* close */ + iplread, /* read */ + (void *)nullop, /* write */ + iplioctl, /* ioctl */ + (void *)nullop, /* stop */ + (void *)nullop, /* reset */ + (void *)NULL, /* tty */ + (void *)nullop, /* select */ + (void *)nullop, /* mmap */ + NULL /* strategy */ +}; + +MOD_DEV(IPL_VERSION, LM_DT_CHAR, -1, &ipldevsw); + +extern struct cdevsw cdevsw[]; +extern int vd_unuseddev __P((void)); +extern int nchrdev; +#else + +static struct cdevsw ipl_cdevsw = { + iplopen, iplclose, iplread, nowrite, /* 79 */ + iplioctl, nostop, noreset, nodevtotty, +#if (__FreeBSD_version >= 300000) + seltrue, nommap, nostrategy, "ipl", +#else + noselect, nommap, nostrategy, "ipl", +#endif + NULL, -1 +}; +#endif + +static void ipl_drvinit __P((void *)); + +#ifdef ACTUALLY_LKM_NOT_KERNEL +static int if_ipl_unload __P((struct lkm_table *, int)); +static int if_ipl_load __P((struct lkm_table *, int)); +static int if_ipl_remove __P((void)); +static int ipl_major = CDEV_MAJOR; + +static int iplaction __P((struct lkm_table *, int)); +static char *ipf_devfiles[] = { IPL_NAME, IPL_NAT, IPL_STATE, IPL_AUTH, + IPL_SCAN, IPL_SYNC, IPL_POOL, NULL }; + +extern int lkmenodev __P((void)); + +static int iplaction(lkmtp, cmd) +struct lkm_table *lkmtp; +int cmd; +{ +#if !defined(__FreeBSD_version) || (__FreeBSD_version < 220000) + int i = ipl_major; + struct lkm_dev *args = lkmtp->private.lkm_dev; +#endif + int err = 0; + + switch (cmd) + { + case LKM_E_LOAD : + if (lkmexists(lkmtp)) + return EEXIST; + +#if !defined(__FreeBSD_version) || (__FreeBSD_version < 220000) + for (i = 0; i < nchrdev; i++) + if (cdevsw[i].d_open == lkmenodev || + cdevsw[i].d_open == iplopen) + break; + if (i == nchrdev) { + printf("IP Filter: No free cdevsw slots\n"); + return ENODEV; + } + + ipl_major = i; + args->lkm_offset = i; /* slot in cdevsw[] */ +#endif + printf("IP Filter: loaded into slot %d\n", ipl_major); + err = if_ipl_load(lkmtp, cmd); + if (!err) + ipl_drvinit((void *)NULL); + return err; + break; + case LKM_E_UNLOAD : + err = if_ipl_unload(lkmtp, cmd); + if (!err) { + printf("IP Filter: unloaded from slot %d\n", + ipl_major); +#ifdef DEVFS + if (ipf_devfs[IPL_LOGIPF]) + devfs_remove_dev(ipf_devfs[IPL_LOGIPF]); + if (ipf_devfs[IPL_LOGNAT]) + devfs_remove_dev(ipf_devfs[IPL_LOGNAT]); + if (ipf_devfs[IPL_LOGSTATE]) + devfs_remove_dev(ipf_devfs[IPL_LOGSTATE]); + if (ipf_devfs[IPL_LOGAUTH]) + devfs_remove_dev(ipf_devfs[IPL_LOGAUTH]); + if (ipf_devfs[IPL_LOGSCAN]) + devfs_remove_dev(ipf_devfs[IPL_LOGSCAN]); + if (ipf_devfs[IPL_LOGSYNC]) + devfs_remove_dev(ipf_devfs[IPL_LOGSYNC]); + if (ipf_devfs[IPL_LOGLOOKUP]) + devfs_remove_dev(ipf_devfs[IPL_LOGLOOKUP]); +#endif + } + return err; + case LKM_E_STAT : + break; + default: + err = EIO; + break; + } + return 0; +} + + +static int if_ipl_remove __P((void)) +{ + char *name; + struct nameidata nd; + int error, i; + + for (i = 0; (name = ipf_devfiles[i]); i++) { + NDINIT(&nd, DELETE, LOCKPARENT, UIO_SYSSPACE, name, curproc); + if ((error = namei(&nd))) + return (error); + VOP_LEASE(nd.ni_vp, curproc, curproc->p_ucred, LEASE_WRITE); +#if (__FreeBSD_version >= 300000) + VOP_LOCK(nd.ni_vp, LK_RETRY | LK_EXCLUSIVE, curproc); + VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE); + (void) VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); + + if (nd.ni_dvp == nd.ni_vp) + vrele(nd.ni_dvp); + else + vput(nd.ni_dvp); + if (nd.ni_vp != NULLVP) + vput(nd.ni_vp); +#else + VOP_LOCK(nd.ni_vp); + VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE); + (void) VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); +#endif + } + + return 0; +} + + +static int if_ipl_unload(lkmtp, cmd) +struct lkm_table *lkmtp; +int cmd; +{ + int error = 0; + + error = ipldetach(); + if (!error) + error = if_ipl_remove(); + return error; +} + + +static int if_ipl_load(lkmtp, cmd) +struct lkm_table *lkmtp; +int cmd; +{ + struct nameidata nd; + struct vattr vattr; + int error = 0, fmode = S_IFCHR|0600, i; + char *name; + + error = iplattach(); + if (error) + return error; + (void) if_ipl_remove(); + + for (i = 0; (name = ipf_devfiles[i]); i++) { + NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE, name, curproc); + if ((error = namei(&nd))) + return error; + if (nd.ni_vp != NULL) { + VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); + if (nd.ni_dvp == nd.ni_vp) + vrele(nd.ni_dvp); + else + vput(nd.ni_dvp); + vrele(nd.ni_vp); + return (EEXIST); + } + VATTR_NULL(&vattr); + vattr.va_type = VCHR; + vattr.va_mode = (fmode & 07777); + vattr.va_rdev = (ipl_major << 8) | i; + VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE); + error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); +#if (__FreeBSD_version >= 300000) + vput(nd.ni_dvp); +#endif + if (error) + return error; + } + return 0; +} + +#endif /* actually LKM */ + +#if defined(__FreeBSD_version) && (__FreeBSD_version < 220000) +/* + * strlen isn't present in 2.1.* kernels. + */ +size_t strlen(string) +char *string; +{ + register char *s; + + for (s = string; *s; s++) + ; + return (size_t)(s - string); +} + + +int xxxinit(lkmtp, cmd, ver) +struct lkm_table *lkmtp; +int cmd, ver; +{ + DISPATCH(lkmtp, cmd, ver, iplaction, iplaction, iplaction); +} +#else /* __FREEBSD_version >= 220000 */ +# ifdef IPFILTER_LKM +# include <sys/exec.h> + +# if (__FreeBSD_version >= 300000) +MOD_DEV(if_ipl, LM_DT_CHAR, CDEV_MAJOR, &ipl_cdevsw); +# else +MOD_DECL(if_ipl); + + +static struct lkm_dev _module = { + LM_DEV, + LKM_VERSION, + IPL_VERSION, + CDEV_MAJOR, + LM_DT_CHAR, + { (void *)&ipl_cdevsw } +}; +# endif + + +int if_ipl __P((struct lkm_table *, int, int)); + + +int if_ipl(lkmtp, cmd, ver) +struct lkm_table *lkmtp; +int cmd, ver; +{ +# if (__FreeBSD_version >= 300000) + MOD_DISPATCH(if_ipl, lkmtp, cmd, ver, iplaction, iplaction, iplaction); +# else + DISPATCH(lkmtp, cmd, ver, iplaction, iplaction, iplaction); +# endif +} +# endif /* IPFILTER_LKM */ +static ipl_devsw_installed = 0; + +static void ipl_drvinit __P((void *unused)) +{ + dev_t dev; +# ifdef DEVFS + void **tp = ipf_devfs; +# endif + + if (!ipl_devsw_installed ) { + dev = makedev(CDEV_MAJOR, 0); + cdevsw_add(&dev, &ipl_cdevsw, NULL); + ipl_devsw_installed = 1; + +# ifdef DEVFS + tp[IPL_LOGIPF] = devfs_add_devswf(&ipl_cdevsw, IPL_LOGIPF, + DV_CHR, 0, 0, 0600, "ipf"); + tp[IPL_LOGNAT] = devfs_add_devswf(&ipl_cdevsw, IPL_LOGNAT, + DV_CHR, 0, 0, 0600, "ipnat"); + tp[IPL_LOGSTATE] = devfs_add_devswf(&ipl_cdevsw, IPL_LOGSTATE, + DV_CHR, 0, 0, 0600, + "ipstate"); + tp[IPL_LOGAUTH] = devfs_add_devswf(&ipl_cdevsw, IPL_LOGAUTH, + DV_CHR, 0, 0, 0600, + "ipauth"); +# endif + } +} + + +#ifdef SYSCTL_IPF +int +sysctl_ipf_int SYSCTL_HANDLER_ARGS +{ + int error = 0; + + if (arg1) + error = SYSCTL_OUT(req, arg1, sizeof(int)); + else + error = SYSCTL_OUT(req, &arg2, sizeof(int)); + + if (error || !req->newptr) + return (error); + + if (!arg1) + error = EPERM; + else { + if ((oidp->oid_kind & CTLFLAG_OFF) && (fr_running > 0)) + error = EBUSY; + else + error = SYSCTL_IN(req, arg1, sizeof(int)); + } + return (error); +} +#endif + + +# if defined(IPFILTER_LKM) || \ + defined(__FreeBSD_version) && (__FreeBSD_version >= 220000) +SYSINIT(ipldev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,ipl_drvinit,NULL) +# endif /* IPFILTER_LKM */ +#endif /* _FreeBSD_version */ |