mlf_ipl.c revision 60841
185518Sjake/* 285518Sjake * Copyright (C) 1993-2000 by Darren Reed. 385518Sjake * 485518Sjake * Redistribution and use in source and binary forms are permitted 585518Sjake * provided that this notice is preserved and due credit is given 685518Sjake * to the original author and the contributors. 785518Sjake */ 885518Sjake/* 985518Sjake * 29/12/94 Added code from Marc Huber <huber@fzi.de> to allow it to allocate 1085518Sjake * its own major char number! Way cool patch! 1185518Sjake */ 1285518Sjake 1385518Sjake 1485518Sjake#include <sys/param.h> 1585518Sjake 1685518Sjake#if defined(__FreeBSD__) && (__FreeBSD__ > 1) 1785518Sjake# ifdef IPFILTER_LKM 1885518Sjake# include <osreldate.h> 1985518Sjake# define ACTUALLY_LKM_NOT_KERNEL 2085518Sjake# else 2185518Sjake# include <sys/osreldate.h> 2285518Sjake# endif 2385518Sjake#endif 2485518Sjake#include <sys/systm.h> 2585518Sjake#if defined(__FreeBSD_version) && (__FreeBSD_version >= 220000) 2685518Sjake# ifndef ACTUALLY_LKM_NOT_KERNEL 2785518Sjake# include "opt_devfs.h" 2885518Sjake# endif 2985518Sjake# include <sys/conf.h> 3085518Sjake# include <sys/kernel.h> 3185518Sjake# ifdef DEVFS 3285518Sjake# include <sys/devfsext.h> 3385518Sjake# endif /*DEVFS*/ 3485518Sjake#endif 3585518Sjake#include <sys/conf.h> 3685518Sjake#include <sys/file.h> 3799018Sobrien#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) 3885518Sjake# include <sys/lock.h> 3985518Sjake#endif 4085518Sjake#include <sys/stat.h> 4185518Sjake#include <sys/proc.h> 4285518Sjake#include <sys/uio.h> 4399018Sobrien#include <sys/kernel.h> 4485518Sjake#include <sys/vnode.h> 4586534Sjake#include <sys/namei.h> 4686534Sjake#include <sys/malloc.h> 4788609Sjake#include <sys/mount.h> 4888609Sjake#include <sys/exec.h> 4988609Sjake#include <sys/mbuf.h> 5085518Sjake#if BSD >= 199506 5185518Sjake# include <sys/sysctl.h> 5285518Sjake#endif 5385518Sjake#if (__FreeBSD_version >= 300000) 5485518Sjake# include <sys/socket.h> 5585518Sjake#endif 5685518Sjake#if (__FreeBSD_version >= 199511) 57108738Stmm#include <net/if.h> 5885518Sjake#include <netinet/in_systm.h> 5985518Sjake#include <netinet/in.h> 6085518Sjake#include <netinet/ip.h> 6185518Sjake#include <net/route.h> 6288609Sjake#include <netinet/ip_var.h> 6388609Sjake#include <netinet/tcp.h> 6485518Sjake#include <netinet/tcpip.h> 6586534Sjake#endif 6686534Sjake#if (__FreeBSD__ > 1) 6785518Sjake# include <sys/sysent.h> 68108738Stmm#endif 69108738Stmm#include <sys/lkm.h> 70108738Stmm#include "netinet/ipl.h" 71108738Stmm#include "netinet/ip_compat.h" 72108738Stmm#include "netinet/ip_fil.h" 73108738Stmm#include "netinet/ip_state.h" 74108738Stmm#include "netinet/ip_nat.h" 75108738Stmm#include "netinet/ip_auth.h" 76108738Stmm#include "netinet/ip_frag.h" 77108738Stmm#include "netinet/ip_proxy.h" 78108738Stmm 79108738Stmm 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_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_icmptimeout, CTLFLAG_RW, 109 &fr_icmptimeout, 0, ""); 110SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_defnatage, CTLFLAG_RW, 111 &fr_defnatage, 0, ""); 112SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_ipfrttl, CTLFLAG_RW, 113 &fr_ipfrttl, 0, ""); 114SYSCTL_INT(_net_inet_ipf, OID_AUTO, ipl_unreach, CTLFLAG_RW, 115 &ipl_unreach, 0, ""); 116SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_running, CTLFLAG_RD, 117 &fr_running, 0, ""); 118SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_authsize, CTLFLAG_RD, 119 &fr_authsize, 0, ""); 120SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_authused, CTLFLAG_RD, 121 &fr_authused, 0, ""); 122SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_defaultauthage, CTLFLAG_RW, 123 &fr_defaultauthage, 0, ""); 124SYSCTL_INT(_net_inet_ipf, OID_AUTO, ippr_ftp_pasvonly, CTLFLAG_RW, 125 &ippr_ftp_pasvonly, 0, ""); 126#endif 127 128#ifdef DEVFS 129static void *ipf_devfs[IPL_LOGMAX + 1]; 130#endif 131 132#if !defined(__FreeBSD_version) || (__FreeBSD_version < 220000) 133int ipl_major = 0; 134 135static struct cdevsw ipldevsw = 136{ 137 iplopen, /* open */ 138 iplclose, /* close */ 139 iplread, /* read */ 140 (void *)nullop, /* write */ 141 iplioctl, /* ioctl */ 142 (void *)nullop, /* stop */ 143 (void *)nullop, /* reset */ 144 (void *)NULL, /* tty */ 145 (void *)nullop, /* select */ 146 (void *)nullop, /* mmap */ 147 NULL /* strategy */ 148}; 149 150MOD_DEV(IPL_VERSION, LM_DT_CHAR, -1, &ipldevsw); 151 152extern struct cdevsw cdevsw[]; 153extern int vd_unuseddev __P((void)); 154extern int nchrdev; 155#else 156 157static struct cdevsw ipl_cdevsw = { 158 iplopen, iplclose, iplread, nowrite, /* 79 */ 159 iplioctl, nostop, noreset, nodevtotty, 160#if (__FreeBSD_version >= 300000) 161 seltrue, nommap, nostrategy, "ipl", 162#else 163 noselect, nommap, nostrategy, "ipl", 164#endif 165 NULL, -1 166}; 167#endif 168 169static void ipl_drvinit __P((void *)); 170 171#ifdef ACTUALLY_LKM_NOT_KERNEL 172static int if_ipl_unload __P((struct lkm_table *, int)); 173static int if_ipl_load __P((struct lkm_table *, int)); 174static int if_ipl_remove __P((void)); 175static int ipl_major = CDEV_MAJOR; 176 177static int iplaction __P((struct lkm_table *, int)); 178static char *ipf_devfiles[] = { IPL_NAME, IPL_NAT, IPL_STATE, IPL_AUTH, NULL }; 179 180extern int lkmenodev __P((void)); 181 182static int iplaction(lkmtp, cmd) 183struct lkm_table *lkmtp; 184int cmd; 185{ 186#if !defined(__FreeBSD_version) || (__FreeBSD_version < 220000) 187 int i = ipl_major; 188 struct lkm_dev *args = lkmtp->private.lkm_dev; 189#endif 190 int err = 0; 191 192 switch (cmd) 193 { 194 case LKM_E_LOAD : 195 if (lkmexists(lkmtp)) 196 return EEXIST; 197 198#if !defined(__FreeBSD_version) || (__FreeBSD_version < 220000) 199 for (i = 0; i < nchrdev; i++) 200 if (cdevsw[i].d_open == lkmenodev || 201 cdevsw[i].d_open == iplopen) 202 break; 203 if (i == nchrdev) { 204 printf("IP Filter: No free cdevsw slots\n"); 205 return ENODEV; 206 } 207 208 ipl_major = i; 209 args->lkm_offset = i; /* slot in cdevsw[] */ 210#endif 211 printf("IP Filter: loaded into slot %d\n", ipl_major); 212 err = if_ipl_load(lkmtp, cmd); 213 if (!err) 214 ipl_drvinit((void *)NULL); 215 return err; 216 break; 217 case LKM_E_UNLOAD : 218 err = if_ipl_unload(lkmtp, cmd); 219 if (!err) { 220 printf("IP Filter: unloaded from slot %d\n", 221 ipl_major); 222#ifdef DEVFS 223 if (ipf_devfs[IPL_LOGIPF]) 224 devfs_remove_dev(ipf_devfs[IPL_LOGIPF]); 225 if (ipf_devfs[IPL_LOGNAT]) 226 devfs_remove_dev(ipf_devfs[IPL_LOGNAT]); 227 if (ipf_devfs[IPL_LOGSTATE]) 228 devfs_remove_dev(ipf_devfs[IPL_LOGSTATE]); 229 if (ipf_devfs[IPL_LOGAUTH]) 230 devfs_remove_dev(ipf_devfs[IPL_LOGAUTH]); 231#endif 232 } 233 return err; 234 case LKM_E_STAT : 235 break; 236 default: 237 err = EIO; 238 break; 239 } 240 return 0; 241} 242 243 244static int if_ipl_remove __P((void)) 245{ 246 char *name; 247 struct nameidata nd; 248 int error, i; 249 250 for (i = 0; (name = ipf_devfiles[i]); i++) { 251 NDINIT(&nd, DELETE, LOCKPARENT, UIO_SYSSPACE, name, curproc); 252 if ((error = namei(&nd))) 253 return (error); 254 VOP_LEASE(nd.ni_vp, curproc, curproc->p_ucred, LEASE_WRITE); 255#if (__FreeBSD_version >= 300000) 256 VOP_LOCK(nd.ni_vp, LK_RETRY | LK_EXCLUSIVE, curproc); 257 VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE); 258 (void) VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 259 260 if (nd.ni_dvp == nd.ni_vp) 261 vrele(nd.ni_dvp); 262 else 263 vput(nd.ni_dvp); 264 if (nd.ni_vp != NULLVP) 265 vput(nd.ni_vp); 266#else 267 VOP_LOCK(nd.ni_vp); 268 VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE); 269 (void) VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 270#endif 271 } 272 273 return 0; 274} 275 276 277static int if_ipl_unload(lkmtp, cmd) 278struct lkm_table *lkmtp; 279int cmd; 280{ 281 int error = 0; 282 283 error = ipldetach(); 284 if (!error) 285 error = if_ipl_remove(); 286 return error; 287} 288 289 290static int if_ipl_load(lkmtp, cmd) 291struct lkm_table *lkmtp; 292int cmd; 293{ 294 struct nameidata nd; 295 struct vattr vattr; 296 int error = 0, fmode = S_IFCHR|0600, i; 297 char *name; 298 299 error = iplattach(); 300 if (error) 301 return error; 302 (void) if_ipl_remove(); 303 304 for (i = 0; (name = ipf_devfiles[i]); i++) { 305 NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE, name, curproc); 306 if ((error = namei(&nd))) 307 return error; 308 if (nd.ni_vp != NULL) { 309 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 310 if (nd.ni_dvp == nd.ni_vp) 311 vrele(nd.ni_dvp); 312 else 313 vput(nd.ni_dvp); 314 vrele(nd.ni_vp); 315 return (EEXIST); 316 } 317 VATTR_NULL(&vattr); 318 vattr.va_type = VCHR; 319 vattr.va_mode = (fmode & 07777); 320 vattr.va_rdev = (ipl_major << 8) | i; 321 VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE); 322 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 323#if (__FreeBSD_version >= 300000) 324 vput(nd.ni_dvp); 325#endif 326 if (error) 327 return error; 328 } 329 return 0; 330} 331 332#endif /* actually LKM */ 333 334#if defined(__FreeBSD_version) && (__FreeBSD_version < 220000) 335/* 336 * strlen isn't present in 2.1.* kernels. 337 */ 338size_t strlen(string) 339char *string; 340{ 341 register char *s; 342 343 for (s = string; *s; s++) 344 ; 345 return (size_t)(s - string); 346} 347 348 349int xxxinit(lkmtp, cmd, ver) 350struct lkm_table *lkmtp; 351int cmd, ver; 352{ 353 DISPATCH(lkmtp, cmd, ver, iplaction, iplaction, iplaction); 354} 355#else /* __FREEBSD_version >= 220000 */ 356# ifdef IPFILTER_LKM 357# include <sys/exec.h> 358 359# if (__FreeBSD_version >= 300000) 360MOD_DEV(if_ipl, LM_DT_CHAR, CDEV_MAJOR, &ipl_cdevsw); 361# else 362MOD_DECL(if_ipl); 363 364 365static struct lkm_dev _module = { 366 LM_DEV, 367 LKM_VERSION, 368 IPL_VERSION, 369 CDEV_MAJOR, 370 LM_DT_CHAR, 371 { (void *)&ipl_cdevsw } 372}; 373# endif 374 375 376int if_ipl __P((struct lkm_table *, int, int)); 377 378 379int if_ipl(lkmtp, cmd, ver) 380struct lkm_table *lkmtp; 381int cmd, ver; 382{ 383# if (__FreeBSD_version >= 300000) 384 MOD_DISPATCH(if_ipl, lkmtp, cmd, ver, iplaction, iplaction, iplaction); 385# else 386 DISPATCH(lkmtp, cmd, ver, iplaction, iplaction, iplaction); 387# endif 388} 389# endif /* IPFILTER_LKM */ 390static ipl_devsw_installed = 0; 391 392static void ipl_drvinit __P((void *unused)) 393{ 394 dev_t dev; 395# ifdef DEVFS 396 void **tp = ipf_devfs; 397# endif 398 399 if (!ipl_devsw_installed ) { 400 dev = makedev(CDEV_MAJOR, 0); 401 cdevsw_add(&dev, &ipl_cdevsw, NULL); 402 ipl_devsw_installed = 1; 403 404# ifdef DEVFS 405 tp[IPL_LOGIPF] = devfs_add_devswf(&ipl_cdevsw, IPL_LOGIPF, 406 DV_CHR, 0, 0, 0600, "ipf"); 407 tp[IPL_LOGNAT] = devfs_add_devswf(&ipl_cdevsw, IPL_LOGNAT, 408 DV_CHR, 0, 0, 0600, "ipnat"); 409 tp[IPL_LOGSTATE] = devfs_add_devswf(&ipl_cdevsw, IPL_LOGSTATE, 410 DV_CHR, 0, 0, 0600, 411 "ipstate"); 412 tp[IPL_LOGAUTH] = devfs_add_devswf(&ipl_cdevsw, IPL_LOGAUTH, 413 DV_CHR, 0, 0, 0600, 414 "ipauth"); 415# endif 416 } 417} 418 419# if defined(IPFILTER_LKM) || \ 420 defined(__FreeBSD_version) && (__FreeBSD_version >= 220000) 421SYSINIT(ipldev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,ipl_drvinit,NULL) 422# endif /* IPFILTER_LKM */ 423#endif /* _FreeBSD_version */ 424