mlf_ipl.c revision 95419
1/* 2 * Copyright (C) 1993-2001 by Darren Reed. 3 * 4 * See the IPFILTER.LICENCE file for details on licencing. 5 */ 6/* 7 * 29/12/94 Added code from Marc Huber <huber@fzi.de> to allow it to allocate 8 * its own major char number! Way cool patch! 9 */ 10 11 12#include <sys/param.h> 13 14#if defined(__FreeBSD__) 15# ifndef __FreeBSD_version 16# include <sys/osreldate.h> 17# endif 18# ifdef IPFILTER_LKM 19# define ACTUALLY_LKM_NOT_KERNEL 20# endif 21#endif 22#include <sys/systm.h> 23#if defined(__FreeBSD_version) && (__FreeBSD_version >= 220000) 24# ifndef ACTUALLY_LKM_NOT_KERNEL 25# include "opt_devfs.h" 26# endif 27# include <sys/conf.h> 28# include <sys/kernel.h> 29# ifdef DEVFS 30# include <sys/devfsext.h> 31# endif /*DEVFS*/ 32#endif 33#include <sys/conf.h> 34#include <sys/file.h> 35#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) 36# include <sys/lock.h> 37#endif 38#include <sys/stat.h> 39#include <sys/proc.h> 40#include <sys/uio.h> 41#include <sys/kernel.h> 42#include <sys/vnode.h> 43#include <sys/namei.h> 44#include <sys/malloc.h> 45#include <sys/mount.h> 46#include <sys/exec.h> 47#include <sys/mbuf.h> 48#if BSD >= 199506 49# include <sys/sysctl.h> 50#endif 51#if (__FreeBSD_version >= 300000) 52# include <sys/socket.h> 53#endif 54#include <net/if.h> 55#include <netinet/in_systm.h> 56#include <netinet/in.h> 57#include <netinet/ip.h> 58#include <net/route.h> 59#include <net/if.h> 60#include <netinet/ip_var.h> 61#include <netinet/tcp.h> 62#include <netinet/tcpip.h> 63#include <sys/sysent.h> 64#include <sys/lkm.h> 65#include "netinet/ipl.h" 66#include "netinet/ip_compat.h" 67#include "netinet/ip_fil.h" 68#include "netinet/ip_state.h" 69#include "netinet/ip_nat.h" 70#include "netinet/ip_auth.h" 71#include "netinet/ip_frag.h" 72#include "netinet/ip_proxy.h" 73 74 75#if !defined(VOP_LEASE) && defined(LEASE_CHECK) 76#define VOP_LEASE LEASE_CHECK 77#endif 78 79#ifndef MIN 80#define MIN(a,b) (((a)<(b))?(a):(b)) 81#endif 82 83int xxxinit __P((struct lkm_table *, int, int)); 84 85#ifdef SYSCTL_INT 86SYSCTL_NODE(_net_inet, OID_AUTO, ipf, CTLFLAG_RW, 0, "IPF"); 87SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_flags, CTLFLAG_RW, &fr_flags, 0, ""); 88SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_pass, CTLFLAG_RW, &fr_pass, 0, ""); 89SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_active, CTLFLAG_RD, &fr_active, 0, ""); 90SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_chksrc, CTLFLAG_RW, &fr_chksrc, 0, ""); 91SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_minttl, CTLFLAG_RW, &fr_minttl, 0, ""); 92SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_minttllog, CTLFLAG_RW, 93 &fr_minttllog, 0, ""); 94SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcpidletimeout, CTLFLAG_RW, 95 &fr_tcpidletimeout, 0, ""); 96SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcphalfclosed, CTLFLAG_RW, 97 &fr_tcphalfclosed, 0, ""); 98SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcpclosewait, CTLFLAG_RW, 99 &fr_tcpclosewait, 0, ""); 100SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcplastack, CTLFLAG_RW, 101 &fr_tcplastack, 0, ""); 102SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcptimeout, CTLFLAG_RW, 103 &fr_tcptimeout, 0, ""); 104SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcpclosed, CTLFLAG_RW, 105 &fr_tcpclosed, 0, ""); 106SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_udptimeout, CTLFLAG_RW, 107 &fr_udptimeout, 0, ""); 108SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_udpacktimeout, CTLFLAG_RW, 109 &fr_udpacktimeout, 0, ""); 110SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_icmptimeout, CTLFLAG_RW, 111 &fr_icmptimeout, 0, ""); 112SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_icmpacktimeout, CTLFLAG_RW, 113 &fr_icmpacktimeout, 0, ""); 114SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_defnatage, CTLFLAG_RW, 115 &fr_defnatage, 0, ""); 116SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_ipfrttl, CTLFLAG_RW, 117 &fr_ipfrttl, 0, ""); 118SYSCTL_INT(_net_inet_ipf, OID_AUTO, ipl_unreach, CTLFLAG_RW, 119 &ipl_unreach, 0, ""); 120SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_running, CTLFLAG_RD, 121 &fr_running, 0, ""); 122SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_authsize, CTLFLAG_RD, 123 &fr_authsize, 0, ""); 124SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_authused, CTLFLAG_RD, 125 &fr_authused, 0, ""); 126SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_defaultauthage, CTLFLAG_RW, 127 &fr_defaultauthage, 0, ""); 128SYSCTL_INT(_net_inet_ipf, OID_AUTO, ippr_ftp_pasvonly, CTLFLAG_RW, 129 &ippr_ftp_pasvonly, 0, ""); 130#endif 131 132#ifdef DEVFS 133static void *ipf_devfs[IPL_LOGMAX + 1]; 134#endif 135 136#if !defined(__FreeBSD_version) || (__FreeBSD_version < 220000) 137int ipl_major = 0; 138 139static struct cdevsw ipldevsw = 140{ 141 iplopen, /* open */ 142 iplclose, /* close */ 143 iplread, /* read */ 144 (void *)nullop, /* write */ 145 iplioctl, /* ioctl */ 146 (void *)nullop, /* stop */ 147 (void *)nullop, /* reset */ 148 (void *)NULL, /* tty */ 149 (void *)nullop, /* select */ 150 (void *)nullop, /* mmap */ 151 NULL /* strategy */ 152}; 153 154MOD_DEV(IPL_VERSION, LM_DT_CHAR, -1, &ipldevsw); 155 156extern struct cdevsw cdevsw[]; 157extern int vd_unuseddev __P((void)); 158extern int nchrdev; 159#else 160 161static struct cdevsw ipl_cdevsw = { 162 iplopen, iplclose, iplread, nowrite, /* 79 */ 163 iplioctl, nostop, noreset, nodevtotty, 164#if (__FreeBSD_version >= 300000) 165 seltrue, nommap, nostrategy, "ipl", 166#else 167 noselect, nommap, nostrategy, "ipl", 168#endif 169 NULL, -1 170}; 171#endif 172 173static void ipl_drvinit __P((void *)); 174 175#ifdef ACTUALLY_LKM_NOT_KERNEL 176static int if_ipl_unload __P((struct lkm_table *, int)); 177static int if_ipl_load __P((struct lkm_table *, int)); 178static int if_ipl_remove __P((void)); 179static int ipl_major = CDEV_MAJOR; 180 181static int iplaction __P((struct lkm_table *, int)); 182static char *ipf_devfiles[] = { IPL_NAME, IPL_NAT, IPL_STATE, IPL_AUTH, NULL }; 183 184extern int lkmenodev __P((void)); 185 186static int iplaction(lkmtp, cmd) 187struct lkm_table *lkmtp; 188int cmd; 189{ 190#if !defined(__FreeBSD_version) || (__FreeBSD_version < 220000) 191 int i = ipl_major; 192 struct lkm_dev *args = lkmtp->private.lkm_dev; 193#endif 194 int err = 0; 195 196 switch (cmd) 197 { 198 case LKM_E_LOAD : 199 if (lkmexists(lkmtp)) 200 return EEXIST; 201 202#if !defined(__FreeBSD_version) || (__FreeBSD_version < 220000) 203 for (i = 0; i < nchrdev; i++) 204 if (cdevsw[i].d_open == lkmenodev || 205 cdevsw[i].d_open == iplopen) 206 break; 207 if (i == nchrdev) { 208 printf("IP Filter: No free cdevsw slots\n"); 209 return ENODEV; 210 } 211 212 ipl_major = i; 213 args->lkm_offset = i; /* slot in cdevsw[] */ 214#endif 215 printf("IP Filter: loaded into slot %d\n", ipl_major); 216 err = if_ipl_load(lkmtp, cmd); 217 if (!err) 218 ipl_drvinit((void *)NULL); 219 return err; 220 break; 221 case LKM_E_UNLOAD : 222 err = if_ipl_unload(lkmtp, cmd); 223 if (!err) { 224 printf("IP Filter: unloaded from slot %d\n", 225 ipl_major); 226#ifdef DEVFS 227 if (ipf_devfs[IPL_LOGIPF]) 228 devfs_remove_dev(ipf_devfs[IPL_LOGIPF]); 229 if (ipf_devfs[IPL_LOGNAT]) 230 devfs_remove_dev(ipf_devfs[IPL_LOGNAT]); 231 if (ipf_devfs[IPL_LOGSTATE]) 232 devfs_remove_dev(ipf_devfs[IPL_LOGSTATE]); 233 if (ipf_devfs[IPL_LOGAUTH]) 234 devfs_remove_dev(ipf_devfs[IPL_LOGAUTH]); 235#endif 236 } 237 return err; 238 case LKM_E_STAT : 239 break; 240 default: 241 err = EIO; 242 break; 243 } 244 return 0; 245} 246 247 248static int if_ipl_remove __P((void)) 249{ 250 char *name; 251 struct nameidata nd; 252 int error, i; 253 254 for (i = 0; (name = ipf_devfiles[i]); i++) { 255 NDINIT(&nd, DELETE, LOCKPARENT, UIO_SYSSPACE, name, curproc); 256 if ((error = namei(&nd))) 257 return (error); 258 VOP_LEASE(nd.ni_vp, curproc, curproc->p_ucred, LEASE_WRITE); 259#if (__FreeBSD_version >= 300000) 260 VOP_LOCK(nd.ni_vp, LK_RETRY | LK_EXCLUSIVE, curproc); 261 VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE); 262 (void) VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 263 264 if (nd.ni_dvp == nd.ni_vp) 265 vrele(nd.ni_dvp); 266 else 267 vput(nd.ni_dvp); 268 if (nd.ni_vp != NULLVP) 269 vput(nd.ni_vp); 270#else 271 VOP_LOCK(nd.ni_vp); 272 VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE); 273 (void) VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 274#endif 275 } 276 277 return 0; 278} 279 280 281static int if_ipl_unload(lkmtp, cmd) 282struct lkm_table *lkmtp; 283int cmd; 284{ 285 int error = 0; 286 287 error = ipldetach(); 288 if (!error) 289 error = if_ipl_remove(); 290 return error; 291} 292 293 294static int if_ipl_load(lkmtp, cmd) 295struct lkm_table *lkmtp; 296int cmd; 297{ 298 struct nameidata nd; 299 struct vattr vattr; 300 int error = 0, fmode = S_IFCHR|0600, i; 301 char *name; 302 303 error = iplattach(); 304 if (error) 305 return error; 306 (void) if_ipl_remove(); 307 308 for (i = 0; (name = ipf_devfiles[i]); i++) { 309 NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE, name, curproc); 310 if ((error = namei(&nd))) 311 return error; 312 if (nd.ni_vp != NULL) { 313 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 314 if (nd.ni_dvp == nd.ni_vp) 315 vrele(nd.ni_dvp); 316 else 317 vput(nd.ni_dvp); 318 vrele(nd.ni_vp); 319 return (EEXIST); 320 } 321 VATTR_NULL(&vattr); 322 vattr.va_type = VCHR; 323 vattr.va_mode = (fmode & 07777); 324 vattr.va_rdev = (ipl_major << 8) | i; 325 VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE); 326 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 327#if (__FreeBSD_version >= 300000) 328 vput(nd.ni_dvp); 329#endif 330 if (error) 331 return error; 332 } 333 return 0; 334} 335 336#endif /* actually LKM */ 337 338#if defined(__FreeBSD_version) && (__FreeBSD_version < 220000) 339/* 340 * strlen isn't present in 2.1.* kernels. 341 */ 342size_t strlen(string) 343char *string; 344{ 345 register char *s; 346 347 for (s = string; *s; s++) 348 ; 349 return (size_t)(s - string); 350} 351 352 353int xxxinit(lkmtp, cmd, ver) 354struct lkm_table *lkmtp; 355int cmd, ver; 356{ 357 DISPATCH(lkmtp, cmd, ver, iplaction, iplaction, iplaction); 358} 359#else /* __FREEBSD_version >= 220000 */ 360# ifdef IPFILTER_LKM 361# include <sys/exec.h> 362 363# if (__FreeBSD_version >= 300000) 364MOD_DEV(if_ipl, LM_DT_CHAR, CDEV_MAJOR, &ipl_cdevsw); 365# else 366MOD_DECL(if_ipl); 367 368 369static struct lkm_dev _module = { 370 LM_DEV, 371 LKM_VERSION, 372 IPL_VERSION, 373 CDEV_MAJOR, 374 LM_DT_CHAR, 375 { (void *)&ipl_cdevsw } 376}; 377# endif 378 379 380int if_ipl __P((struct lkm_table *, int, int)); 381 382 383int if_ipl(lkmtp, cmd, ver) 384struct lkm_table *lkmtp; 385int cmd, ver; 386{ 387# if (__FreeBSD_version >= 300000) 388 MOD_DISPATCH(if_ipl, lkmtp, cmd, ver, iplaction, iplaction, iplaction); 389# else 390 DISPATCH(lkmtp, cmd, ver, iplaction, iplaction, iplaction); 391# endif 392} 393# endif /* IPFILTER_LKM */ 394static int ipl_devsw_installed = 0; 395 396static void ipl_drvinit __P((void *unused)) 397{ 398 dev_t dev; 399# ifdef DEVFS 400 void **tp = ipf_devfs; 401# endif 402 403 if (!ipl_devsw_installed ) { 404 dev = makedev(CDEV_MAJOR, 0); 405 cdevsw_add(&dev, &ipl_cdevsw, NULL); 406 ipl_devsw_installed = 1; 407 408# ifdef DEVFS 409 tp[IPL_LOGIPF] = devfs_add_devswf(&ipl_cdevsw, IPL_LOGIPF, 410 DV_CHR, 0, 0, 0600, "ipf"); 411 tp[IPL_LOGNAT] = devfs_add_devswf(&ipl_cdevsw, IPL_LOGNAT, 412 DV_CHR, 0, 0, 0600, "ipnat"); 413 tp[IPL_LOGSTATE] = devfs_add_devswf(&ipl_cdevsw, IPL_LOGSTATE, 414 DV_CHR, 0, 0, 0600, 415 "ipstate"); 416 tp[IPL_LOGAUTH] = devfs_add_devswf(&ipl_cdevsw, IPL_LOGAUTH, 417 DV_CHR, 0, 0, 0600, 418 "ipauth"); 419# endif 420 } 421} 422 423# if defined(IPFILTER_LKM) || \ 424 defined(__FreeBSD_version) && (__FreeBSD_version >= 220000) 425SYSINIT(ipldev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,ipl_drvinit,NULL) 426# endif /* IPFILTER_LKM */ 427#endif /* _FreeBSD_version */ 428