/* $FreeBSD$ */ /* * Copyright (C) 2000 by Darren Reed. * * $FreeBSD$ * See the IPFILTER.LICENCE file for details on licencing. */ #include #include #include #include #include #include #include #include #if __FreeBSD_version >= 500000 # include #endif #include #include #include #include #include #include #include #include #include #include #include #if __FreeBSD_version >= 502116 static struct cdev *ipf_devs[IPL_LOGSIZE]; #else static dev_t ipf_devs[IPL_LOGSIZE]; #endif static int sysctl_ipf_int ( SYSCTL_HANDLER_ARGS ); static int ipf_modload(void); static int ipf_modunload(void); SYSCTL_DECL(_net_inet); #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_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_udpacktimeout, CTLFLAG_RWO, &fr_udpacktimeout, 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, ipf_nattable_sz, CTLFLAG_RWO, &ipf_nattable_sz, 0, ""); SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_natrules_sz, CTLFLAG_RWO, &ipf_natrules_sz, 0, ""); SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_rdrrules_sz, CTLFLAG_RWO, &ipf_rdrrules_sz, 0, ""); SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_hostmap_sz, CTLFLAG_RWO, &ipf_hostmap_sz, 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, fr_chksrc, CTLFLAG_RW, &fr_chksrc, 0, ""); SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_minttl, CTLFLAG_RW, &fr_minttl, 0, ""); #define CDEV_MAJOR 79 #include #if __FreeBSD_version >= 500043 # include static int iplpoll(struct cdev *dev, int events, struct thread *td); static struct cdevsw ipl_cdevsw = { # if __FreeBSD_version >= 502103 .d_version = D_VERSION, .d_flags = 0, /* D_NEEDGIANT - Should be SMP safe */ # endif .d_open = iplopen, .d_close = iplclose, .d_read = iplread, .d_write = iplwrite, .d_ioctl = iplioctl, .d_name = "ipl", # if __FreeBSD_version >= 500043 .d_poll = iplpoll, # endif # if __FreeBSD_version < 600000 .d_maj = CDEV_MAJOR, # endif }; #else static int iplpoll(dev_t dev, int events, struct proc *p); static struct cdevsw ipl_cdevsw = { /* open */ iplopen, /* close */ iplclose, /* read */ iplread, /* write */ iplwrite, /* ioctl */ iplioctl, /* poll */ iplpoll, /* mmap */ nommap, /* strategy */ nostrategy, /* name */ "ipl", /* maj */ CDEV_MAJOR, /* dump */ nodump, /* psize */ nopsize, /* flags */ 0, # if (__FreeBSD_version < 500043) /* bmaj */ -1, # endif # if (__FreeBSD_version > 430000) /* kqfilter */ NULL # endif }; #endif static char *ipf_devfiles[] = { IPL_NAME, IPNAT_NAME, IPSTATE_NAME, IPAUTH_NAME, IPSYNC_NAME, IPSCAN_NAME, IPLOOKUP_NAME, NULL }; static int ipfilter_modevent(module_t mod, int type, void *unused) { int error = 0; switch (type) { case MOD_LOAD : error = ipf_modload(); break; case MOD_UNLOAD : error = ipf_modunload(); break; default: error = EINVAL; break; } return error; } static int ipf_modload() { char *defpass, *c, *str; int i, j, error; RWLOCK_INIT(&ipf_global, "ipf filter load/unload mutex"); RWLOCK_INIT(&ipf_mutex, "ipf filter rwlock"); RWLOCK_INIT(&ipf_frcache, "ipf cache rwlock"); error = ipfattach(); if (error) { RW_DESTROY(&ipf_global); RW_DESTROY(&ipf_mutex); RW_DESTROY(&ipf_frcache); return error; } for (i = 0; i < IPL_LOGSIZE; i++) ipf_devs[i] = NULL; for (i = 0; (str = ipf_devfiles[i]); i++) { c = NULL; for(j = strlen(str); j > 0; j--) if (str[j] == '/') { c = str + j + 1; break; } if (!c) c = str; ipf_devs[i] = make_dev(&ipl_cdevsw, i, 0, 0, 0600, "%s", c); } error = ipf_pfil_hook(); if (error != 0) return error; ipf_event_reg(); if (FR_ISPASS(fr_pass)) defpass = "pass"; else if (FR_ISBLOCK(fr_pass)) defpass = "block"; else defpass = "no-match -> block"; printf("%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 ); return 0; } static int ipf_modunload() { int error, i; if (fr_refcnt) return EBUSY; if (fr_running >= 0) { ipf_pfil_unhook(); ipf_event_dereg(); WRITE_ENTER(&ipf_global); error = ipfdetach(); RWLOCK_EXIT(&ipf_global); if (error != 0) return error; } else error = 0; RW_DESTROY(&ipf_global); RW_DESTROY(&ipf_mutex); RW_DESTROY(&ipf_frcache); fr_running = -2; for (i = 0; ipf_devfiles[i]; i++) { if (ipf_devs[i] != NULL) destroy_dev(ipf_devs[i]); } printf("%s unloaded\n", ipfilter_version); return error; } static moduledata_t ipfiltermod = { "ipfilter", ipfilter_modevent, 0 }; DECLARE_MODULE(ipfilter, ipfiltermod, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY); #ifdef MODULE_VERSION MODULE_VERSION(ipfilter, 1); #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 static int #if __FreeBSD_version >= 500043 iplpoll(struct cdev *dev, int events, struct thread *td) #else iplpoll(dev_t dev, int events, struct proc *td) #endif { u_int xmin = GET_MINOR(dev); int revents; if (xmin < 0 || xmin > IPL_LOGMAX) return 0; revents = 0; switch (xmin) { case IPL_LOGIPF : case IPL_LOGNAT : case IPL_LOGSTATE : #ifdef IPFILTER_LOG if ((events & (POLLIN | POLLRDNORM)) && ipflog_canread(xmin)) revents |= events & (POLLIN | POLLRDNORM); #endif break; case IPL_LOGAUTH : if ((events & (POLLIN | POLLRDNORM)) && fr_auth_waiting()) revents |= events & (POLLIN | POLLRDNORM); break; case IPL_LOGSYNC : #ifdef IPFILTER_SYNC if ((events & (POLLIN | POLLRDNORM)) && ipfsync_canread()) revents |= events & (POLLIN | POLLRDNORM); if ((events & (POLLOUT | POLLWRNORM)) && ipfsync_canwrite()) revents |= events & (POLLOUT | POLLWRNORM); #endif break; case IPL_LOGSCAN : case IPL_LOGLOOKUP : default : break; } if ((revents == 0) && ((events & (POLLIN|POLLRDNORM)) != 0)) selrecord(td, &ipfselwait[xmin]); return revents; }