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