1145522Sdarrenr/* $FreeBSD$ */ 2145522Sdarrenr 354221Sguido/* 4145522Sdarrenr * Copyright (C) 2000 by Darren Reed. 554221Sguido * 654221Sguido * $FreeBSD$ 7145522Sdarrenr * See the IPFILTER.LICENCE file for details on licencing. 854221Sguido */ 954221Sguido 1060857Sdarrenr 1154221Sguido#include <sys/param.h> 1254221Sguido#include <sys/systm.h> 1354221Sguido#include <sys/kernel.h> 1454221Sguido#include <sys/module.h> 1554221Sguido#include <sys/conf.h> 1654221Sguido#include <sys/socket.h> 1754221Sguido#include <sys/sysctl.h> 18161356Sguido#include <sys/select.h> 19161356Sguido#if __FreeBSD_version >= 500000 20161356Sguido# include <sys/selinfo.h> 21161356Sguido#endif 2254221Sguido#include <net/if.h> 2354221Sguido#include <netinet/in_systm.h> 2454221Sguido#include <netinet/in.h> 2554221Sguido 2654221Sguido 2754221Sguido#include <netinet/ipl.h> 2854221Sguido#include <netinet/ip_compat.h> 2954221Sguido#include <netinet/ip_fil.h> 3054221Sguido#include <netinet/ip_state.h> 3154221Sguido#include <netinet/ip_nat.h> 3254221Sguido#include <netinet/ip_auth.h> 3354221Sguido#include <netinet/ip_frag.h> 34161356Sguido#include <netinet/ip_sync.h> 3554221Sguido 36145522Sdarrenr#if __FreeBSD_version >= 502116 37145522Sdarrenrstatic struct cdev *ipf_devs[IPL_LOGSIZE]; 38145522Sdarrenr#else 39145522Sdarrenrstatic dev_t ipf_devs[IPL_LOGSIZE]; 40145522Sdarrenr#endif 4154221Sguido 42145522Sdarrenrstatic int sysctl_ipf_int ( SYSCTL_HANDLER_ARGS ); 43145522Sdarrenrstatic int ipf_modload(void); 44145522Sdarrenrstatic int ipf_modunload(void); 45145522Sdarrenr 4654221SguidoSYSCTL_DECL(_net_inet); 47145522Sdarrenr#define SYSCTL_IPF(parent, nbr, name, access, ptr, val, descr) \ 48145522Sdarrenr SYSCTL_OID(parent, nbr, name, CTLTYPE_INT|access, \ 49145522Sdarrenr ptr, val, sysctl_ipf_int, "I", descr); 50145522Sdarrenr#define CTLFLAG_OFF 0x00800000 /* IPFilter must be disabled */ 51145522Sdarrenr#define CTLFLAG_RWO (CTLFLAG_RW|CTLFLAG_OFF) 5254221SguidoSYSCTL_NODE(_net_inet, OID_AUTO, ipf, CTLFLAG_RW, 0, "IPF"); 53145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_flags, CTLFLAG_RW, &fr_flags, 0, ""); 54145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_pass, CTLFLAG_RW, &fr_pass, 0, ""); 55145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_active, CTLFLAG_RD, &fr_active, 0, ""); 56145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpidletimeout, CTLFLAG_RWO, 5754221Sguido &fr_tcpidletimeout, 0, ""); 58145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcphalfclosed, CTLFLAG_RWO, 59145522Sdarrenr &fr_tcphalfclosed, 0, ""); 60145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpclosewait, CTLFLAG_RWO, 6154221Sguido &fr_tcpclosewait, 0, ""); 62145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcplastack, CTLFLAG_RWO, 6354221Sguido &fr_tcplastack, 0, ""); 64145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcptimeout, CTLFLAG_RWO, 6554221Sguido &fr_tcptimeout, 0, ""); 66145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpclosed, CTLFLAG_RWO, 6754221Sguido &fr_tcpclosed, 0, ""); 68145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_udptimeout, CTLFLAG_RWO, 6954221Sguido &fr_udptimeout, 0, ""); 70145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_udpacktimeout, CTLFLAG_RWO, 7192685Sdarrenr &fr_udpacktimeout, 0, ""); 72145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_icmptimeout, CTLFLAG_RWO, 7354221Sguido &fr_icmptimeout, 0, ""); 74145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_defnatage, CTLFLAG_RWO, 7554221Sguido &fr_defnatage, 0, ""); 76145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_ipfrttl, CTLFLAG_RW, 7754221Sguido &fr_ipfrttl, 0, ""); 78145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_running, CTLFLAG_RD, 7957096Sguido &fr_running, 0, ""); 80145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_statesize, CTLFLAG_RWO, 81145522Sdarrenr &fr_statesize, 0, ""); 82145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_statemax, CTLFLAG_RWO, 83145522Sdarrenr &fr_statemax, 0, ""); 84145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_nattable_sz, CTLFLAG_RWO, 85145522Sdarrenr &ipf_nattable_sz, 0, ""); 86145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_natrules_sz, CTLFLAG_RWO, 87145522Sdarrenr &ipf_natrules_sz, 0, ""); 88145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_rdrrules_sz, CTLFLAG_RWO, 89145522Sdarrenr &ipf_rdrrules_sz, 0, ""); 90145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_hostmap_sz, CTLFLAG_RWO, 91145522Sdarrenr &ipf_hostmap_sz, 0, ""); 92145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_authsize, CTLFLAG_RWO, 9354221Sguido &fr_authsize, 0, ""); 94145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_authused, CTLFLAG_RD, 9554221Sguido &fr_authused, 0, ""); 96145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_defaultauthage, CTLFLAG_RW, 9754221Sguido &fr_defaultauthage, 0, ""); 98145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_chksrc, CTLFLAG_RW, &fr_chksrc, 0, ""); 99145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_minttl, CTLFLAG_RW, &fr_minttl, 0, ""); 10054221Sguido 101145522Sdarrenr#define CDEV_MAJOR 79 102170268Sdarrenr#include <sys/poll.h> 103170268Sdarrenr#if __FreeBSD_version >= 500043 104161356Sguido# include <sys/select.h> 105161356Sguidostatic int iplpoll(struct cdev *dev, int events, struct thread *td); 106161356Sguido 10754221Sguidostatic struct cdevsw ipl_cdevsw = { 108145522Sdarrenr# if __FreeBSD_version >= 502103 109126080Sphk .d_version = D_VERSION, 110145522Sdarrenr .d_flags = 0, /* D_NEEDGIANT - Should be SMP safe */ 111145522Sdarrenr# endif 112111815Sphk .d_open = iplopen, 113111815Sphk .d_close = iplclose, 114111815Sphk .d_read = iplread, 115153876Sguido .d_write = iplwrite, 116111815Sphk .d_ioctl = iplioctl, 117111815Sphk .d_name = "ipl", 118170268Sdarrenr# if __FreeBSD_version >= 500043 119161356Sguido .d_poll = iplpoll, 120170268Sdarrenr# endif 121145522Sdarrenr# if __FreeBSD_version < 600000 122145522Sdarrenr .d_maj = CDEV_MAJOR, 123145522Sdarrenr# endif 12454221Sguido}; 125145522Sdarrenr#else 126170268Sdarrenrstatic int iplpoll(dev_t dev, int events, struct proc *p); 127170268Sdarrenr 128145522Sdarrenrstatic struct cdevsw ipl_cdevsw = { 129145522Sdarrenr /* open */ iplopen, 130145522Sdarrenr /* close */ iplclose, 131145522Sdarrenr /* read */ iplread, 132145522Sdarrenr /* write */ iplwrite, 133145522Sdarrenr /* ioctl */ iplioctl, 134161356Sguido /* poll */ iplpoll, 135145522Sdarrenr /* mmap */ nommap, 136145522Sdarrenr /* strategy */ nostrategy, 137145522Sdarrenr /* name */ "ipl", 138145522Sdarrenr /* maj */ CDEV_MAJOR, 139145522Sdarrenr /* dump */ nodump, 140145522Sdarrenr /* psize */ nopsize, 141145522Sdarrenr /* flags */ 0, 142145522Sdarrenr# if (__FreeBSD_version < 500043) 143145522Sdarrenr /* bmaj */ -1, 144145522Sdarrenr# endif 145170268Sdarrenr# if (__FreeBSD_version > 430000) 146145522Sdarrenr /* kqfilter */ NULL 147170268Sdarrenr# endif 148145522Sdarrenr}; 149139255Sdarrenr#endif 150139255Sdarrenr 151145522Sdarrenrstatic char *ipf_devfiles[] = { IPL_NAME, IPNAT_NAME, IPSTATE_NAME, IPAUTH_NAME, 152145522Sdarrenr IPSYNC_NAME, IPSCAN_NAME, IPLOOKUP_NAME, NULL }; 153145522Sdarrenr 154145522Sdarrenr 15554221Sguidostatic int 15654221Sguidoipfilter_modevent(module_t mod, int type, void *unused) 15754221Sguido{ 158145522Sdarrenr int error = 0; 15954221Sguido 160145522Sdarrenr switch (type) 161145522Sdarrenr { 16254221Sguido case MOD_LOAD : 163145522Sdarrenr error = ipf_modload(); 164145522Sdarrenr break; 16560857Sdarrenr 166145522Sdarrenr case MOD_UNLOAD : 167145522Sdarrenr error = ipf_modunload(); 168145522Sdarrenr break; 169145522Sdarrenr default: 170145522Sdarrenr error = EINVAL; 171145522Sdarrenr break; 172145522Sdarrenr } 173145522Sdarrenr return error; 174145522Sdarrenr} 17554221Sguido 17654221Sguido 177145522Sdarrenrstatic int 178145522Sdarrenripf_modload() 179145522Sdarrenr{ 180145522Sdarrenr char *defpass, *c, *str; 181145522Sdarrenr int i, j, error; 18254221Sguido 183170268Sdarrenr RWLOCK_INIT(&ipf_global, "ipf filter load/unload mutex"); 184170268Sdarrenr RWLOCK_INIT(&ipf_mutex, "ipf filter rwlock"); 185170268Sdarrenr RWLOCK_INIT(&ipf_frcache, "ipf cache rwlock"); 186170268Sdarrenr 187170268Sdarrenr error = ipfattach(); 188170268Sdarrenr if (error) { 189170268Sdarrenr RW_DESTROY(&ipf_global); 190170268Sdarrenr RW_DESTROY(&ipf_mutex); 191170268Sdarrenr RW_DESTROY(&ipf_frcache); 192145522Sdarrenr return error; 193170268Sdarrenr } 19454221Sguido 195145522Sdarrenr for (i = 0; i < IPL_LOGSIZE; i++) 196145522Sdarrenr ipf_devs[i] = NULL; 197145522Sdarrenr 198145522Sdarrenr for (i = 0; (str = ipf_devfiles[i]); i++) { 19954221Sguido c = NULL; 200145522Sdarrenr for(j = strlen(str); j > 0; j--) 201145522Sdarrenr if (str[j] == '/') { 202145522Sdarrenr c = str + j + 1; 20354221Sguido break; 20454221Sguido } 20554221Sguido if (!c) 206145522Sdarrenr c = str; 207213782Srpaulo ipf_devs[i] = make_dev(&ipl_cdevsw, i, 0, 0, 0600, "%s", c); 208145522Sdarrenr } 20954221Sguido 210172776Sdarrenr error = ipf_pfil_hook(); 211172776Sdarrenr if (error != 0) 212172776Sdarrenr return error; 213172776Sdarrenr ipf_event_reg(); 214172776Sdarrenr 215145522Sdarrenr if (FR_ISPASS(fr_pass)) 216145522Sdarrenr defpass = "pass"; 217145522Sdarrenr else if (FR_ISBLOCK(fr_pass)) 218145522Sdarrenr defpass = "block"; 219145522Sdarrenr else 220145522Sdarrenr defpass = "no-match -> block"; 221145522Sdarrenr 222145522Sdarrenr printf("%s initialized. Default = %s all, Logging = %s%s\n", 223145522Sdarrenr ipfilter_version, defpass, 224145522Sdarrenr#ifdef IPFILTER_LOG 225145522Sdarrenr "enabled", 226145522Sdarrenr#else 227145522Sdarrenr "disabled", 228145522Sdarrenr#endif 229145522Sdarrenr#ifdef IPFILTER_COMPILED 230145522Sdarrenr " (COMPILED)" 231145522Sdarrenr#else 232145522Sdarrenr "" 233145522Sdarrenr#endif 234145522Sdarrenr ); 235145522Sdarrenr return 0; 236145522Sdarrenr} 237145522Sdarrenr 238145522Sdarrenr 239145522Sdarrenrstatic int 240145522Sdarrenripf_modunload() 241145522Sdarrenr{ 242145522Sdarrenr int error, i; 243145522Sdarrenr 244145522Sdarrenr if (fr_refcnt) 245145522Sdarrenr return EBUSY; 246145522Sdarrenr 247145522Sdarrenr if (fr_running >= 0) { 248172776Sdarrenr ipf_pfil_unhook(); 249172776Sdarrenr ipf_event_dereg(); 250172776Sdarrenr WRITE_ENTER(&ipf_global); 251170268Sdarrenr error = ipfdetach(); 252172776Sdarrenr RWLOCK_EXIT(&ipf_global); 253145522Sdarrenr if (error != 0) 254145522Sdarrenr return error; 255145522Sdarrenr } else 256145522Sdarrenr error = 0; 257145522Sdarrenr 258170268Sdarrenr RW_DESTROY(&ipf_global); 259170268Sdarrenr RW_DESTROY(&ipf_mutex); 260170268Sdarrenr RW_DESTROY(&ipf_frcache); 261170268Sdarrenr 262145522Sdarrenr fr_running = -2; 263145522Sdarrenr 264145522Sdarrenr for (i = 0; ipf_devfiles[i]; i++) { 265145522Sdarrenr if (ipf_devs[i] != NULL) 266145522Sdarrenr destroy_dev(ipf_devs[i]); 26754221Sguido } 268145522Sdarrenr 269145522Sdarrenr printf("%s unloaded\n", ipfilter_version); 270145522Sdarrenr 27154221Sguido return error; 27254221Sguido} 27354221Sguido 274145522Sdarrenr 27554221Sguidostatic moduledata_t ipfiltermod = { 276145522Sdarrenr "ipfilter", 27754221Sguido ipfilter_modevent, 278145522Sdarrenr 0 27954221Sguido}; 280145522Sdarrenr 281145522Sdarrenr 28254221SguidoDECLARE_MODULE(ipfilter, ipfiltermod, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY); 283145522Sdarrenr#ifdef MODULE_VERSION 284145522SdarrenrMODULE_VERSION(ipfilter, 1); 285145522Sdarrenr#endif 286145522Sdarrenr 287145522Sdarrenr 288145522Sdarrenr#ifdef SYSCTL_IPF 289145522Sdarrenrint 290145522Sdarrenrsysctl_ipf_int ( SYSCTL_HANDLER_ARGS ) 291145522Sdarrenr{ 292145522Sdarrenr int error = 0; 293145522Sdarrenr 294145522Sdarrenr if (arg1) 295145522Sdarrenr error = SYSCTL_OUT(req, arg1, sizeof(int)); 296145522Sdarrenr else 297145522Sdarrenr error = SYSCTL_OUT(req, &arg2, sizeof(int)); 298145522Sdarrenr 299145522Sdarrenr if (error || !req->newptr) 300145522Sdarrenr return (error); 301145522Sdarrenr 302145522Sdarrenr if (!arg1) 303145522Sdarrenr error = EPERM; 304145522Sdarrenr else { 305145522Sdarrenr if ((oidp->oid_kind & CTLFLAG_OFF) && (fr_running > 0)) 306145522Sdarrenr error = EBUSY; 307145522Sdarrenr else 308145522Sdarrenr error = SYSCTL_IN(req, arg1, sizeof(int)); 309145522Sdarrenr } 310145522Sdarrenr return (error); 311145522Sdarrenr} 312145522Sdarrenr#endif 313161356Sguido 314161356Sguido 315161356Sguidostatic int 316170268Sdarrenr#if __FreeBSD_version >= 500043 317161356Sguidoiplpoll(struct cdev *dev, int events, struct thread *td) 318170268Sdarrenr#else 319170268Sdarrenriplpoll(dev_t dev, int events, struct proc *td) 320170268Sdarrenr#endif 321161356Sguido{ 322161356Sguido u_int xmin = GET_MINOR(dev); 323161356Sguido int revents; 324161356Sguido 325161356Sguido if (xmin < 0 || xmin > IPL_LOGMAX) 326161356Sguido return 0; 327161356Sguido 328161356Sguido revents = 0; 329161356Sguido 330161356Sguido switch (xmin) 331161356Sguido { 332161356Sguido case IPL_LOGIPF : 333161356Sguido case IPL_LOGNAT : 334161356Sguido case IPL_LOGSTATE : 335161356Sguido#ifdef IPFILTER_LOG 336161356Sguido if ((events & (POLLIN | POLLRDNORM)) && ipflog_canread(xmin)) 337161356Sguido revents |= events & (POLLIN | POLLRDNORM); 338161356Sguido#endif 339161356Sguido break; 340161356Sguido case IPL_LOGAUTH : 341161356Sguido if ((events & (POLLIN | POLLRDNORM)) && fr_auth_waiting()) 342161356Sguido revents |= events & (POLLIN | POLLRDNORM); 343161356Sguido break; 344161356Sguido case IPL_LOGSYNC : 345161356Sguido#ifdef IPFILTER_SYNC 346161356Sguido if ((events & (POLLIN | POLLRDNORM)) && ipfsync_canread()) 347161356Sguido revents |= events & (POLLIN | POLLRDNORM); 348161356Sguido if ((events & (POLLOUT | POLLWRNORM)) && ipfsync_canwrite()) 349161356Sguido revents |= events & (POLLOUT | POLLWRNORM); 350161356Sguido#endif 351161356Sguido break; 352161356Sguido case IPL_LOGSCAN : 353161356Sguido case IPL_LOGLOOKUP : 354161356Sguido default : 355161356Sguido break; 356161356Sguido } 357161356Sguido 358161356Sguido if ((revents == 0) && ((events & (POLLIN|POLLRDNORM)) != 0)) 359161356Sguido selrecord(td, &ipfselwait[xmin]); 360161356Sguido 361161356Sguido return revents; 362161356Sguido} 363