mln_ipl.c revision 259128
1/* $FreeBSD$ */ 2 3/* 4 * Copyright (C) 2012 by Darren Reed. 5 * 6 * See the IPFILTER.LICENCE file for details on licencing. 7 * 8 */ 9/* 10 * 29/12/94 Added code from Marc Huber <huber@fzi.de> to allow it to allocate 11 * its own major char number! Way cool patch! 12 */ 13 14 15#include <sys/param.h> 16 17/* 18 * Post NetBSD 1.2 has the PFIL interface for packet filters. This turns 19 * on those hooks. We don't need any special mods with this! 20 */ 21#if (defined(NetBSD) && (NetBSD > 199609) && (NetBSD <= 1991011)) || \ 22 (defined(NetBSD1_2) && NetBSD1_2 > 1) 23# define NETBSD_PF 24#endif 25 26#include <sys/systm.h> 27#include <sys/conf.h> 28#include <sys/file.h> 29#include <sys/stat.h> 30#include <sys/proc.h> 31#include <sys/uio.h> 32#include <sys/kernel.h> 33#include <sys/vnode.h> 34#include <sys/namei.h> 35#include <sys/malloc.h> 36#include <sys/mount.h> 37#include <sys/exec.h> 38#include <sys/mbuf.h> 39#include <net/if.h> 40#include <netinet/in_systm.h> 41#include <netinet/in.h> 42#include <netinet/ip.h> 43#include <net/route.h> 44#include <netinet/ip_var.h> 45#include <netinet/tcp.h> 46#include <netinet/tcpip.h> 47#include <sys/lkm.h> 48#include <sys/poll.h> 49#include <sys/select.h> 50#include "ipl.h" 51#include "ip_compat.h" 52#include "ip_fil.h" 53#include "ip_auth.h" 54#include "ip_state.h" 55#include "ip_nat.h" 56#include "ip_sync.h" 57 58#if !defined(__NetBSD_Version__) || __NetBSD_Version__ < 103050000 59#define vn_lock(v,f) VOP_LOCK(v) 60#endif 61 62#if !defined(VOP_LEASE) && defined(LEASE_CHECK) 63#define VOP_LEASE LEASE_CHECK 64#endif 65 66 67extern int lkmenodev __P((void)); 68 69#if NetBSD >= 199706 70int ipflkm_lkmentry __P((struct lkm_table *, int, int)); 71#else 72int xxxinit __P((struct lkm_table *, int, int)); 73#endif 74static int ipf_unload __P((void)); 75static int ipf_load __P((void)); 76static int ipf_remove __P((void)); 77static int ipfaction __P((struct lkm_table *, int)); 78static char *ipf_devfiles[] = { IPL_NAME, IPNAT_NAME, IPSTATE_NAME, 79 IPAUTH_NAME, IPSYNC_NAME, IPSCAN_NAME, 80 IPLOOKUP_NAME, NULL }; 81 82int ipf_major = 0; 83extern ipf_main_softc_t ipfmain; 84extern const struct cdevsw ipl_cdevsw; 85 86#if defined(__NetBSD__) && (__NetBSD_Version__ >= 106080000) 87MOD_DEV(IPL_VERSION, "ipf", NULL, -1, &ipl_cdevsw, -1); 88#else 89MOD_DEV(IPL_VERSION, LM_DT_CHAR, -1, &ipldevsw); 90#endif 91 92extern int vd_unuseddev __P((void)); 93extern struct cdevsw cdevsw[]; 94extern int nchrdev; 95 96 97int 98#if NetBSD >= 199706 99ipflkm_lkmentry(lkmtp, cmd, ver) 100#else 101xxxinit(lkmtp, cmd, ver) 102#endif 103 struct lkm_table *lkmtp; 104 int cmd, ver; 105{ 106 DISPATCH(lkmtp, cmd, ver, ipfaction, ipfaction, ipfaction); 107} 108 109 110static int 111ipfaction(lkmtp, cmd) 112 struct lkm_table *lkmtp; 113 int cmd; 114{ 115#if !defined(__NetBSD__) || (__NetBSD_Version__ < 106080000) 116 int i; 117#endif 118 struct lkm_dev *args = lkmtp->private.lkm_dev; 119 int err = 0; 120 121 switch (cmd) 122 { 123 case LKM_E_LOAD : 124 if (lkmexists(lkmtp)) 125 return EEXIST; 126 127#if defined(__NetBSD__) && (__NetBSD_Version__ >= 106080000) 128# if (__NetBSD_Version__ < 200000000) 129 err = devsw_attach(args->lkm_devname, 130 args->lkm_bdev, &args->lkm_bdevmaj, 131 args->lkm_cdev, &args->lkm_cdevmaj); 132 if (err != 0) 133 return (err); 134# endif 135 ipf_major = args->lkm_cdevmaj; 136#else 137 for (i = 0; i < nchrdev; i++) 138 if (cdevsw[i].d_open == (dev_type_open((*)))lkmenodev || 139 cdevsw[i].d_open == ipfopen) 140 break; 141 if (i == nchrdev) { 142 printf("IP Filter: No free cdevsw slots\n"); 143 return ENODEV; 144 } 145 146 ipf_major = i; 147 args->lkm_offset = i; /* slot in cdevsw[] */ 148#endif 149 printf("IP Filter: loaded into slot %d\n", ipf_major); 150 return ipf_load(); 151 case LKM_E_UNLOAD : 152#if defined(__NetBSD__) && (__NetBSD_Version__ >= 106080000) 153 devsw_detach(args->lkm_bdev, args->lkm_cdev); 154 args->lkm_bdevmaj = -1; 155 args->lkm_cdevmaj = -1; 156#endif 157 err = ipf_unload(); 158 if (!err) 159 printf("IP Filter: unloaded from slot %d\n", 160 ipf_major); 161 break; 162 case LKM_E_STAT : 163 break; 164 default: 165 err = EIO; 166 break; 167 } 168 return err; 169} 170 171 172static int 173ipf_remove() 174{ 175 char *name; 176 struct nameidata nd; 177 int error, i; 178 179 for (i = 0; (name = ipf_devfiles[i]); i++) { 180#if (__NetBSD_Version__ > 106009999) 181# if (__NetBSD_Version__ > 399001400) 182# if (__NetBSD_Version__ > 499001400) 183 NDINIT(&nd, DELETE, LOCKPARENT|LOCKLEAF, UIO_SYSSPACE, 184 name); 185# else 186 NDINIT(&nd, DELETE, LOCKPARENT|LOCKLEAF, UIO_SYSSPACE, 187 name, curlwp); 188# endif 189# else 190 NDINIT(&nd, DELETE, LOCKPARENT|LOCKLEAF, UIO_SYSSPACE, 191 name, curproc); 192# endif 193#else 194 NDINIT(&nd, DELETE, LOCKPARENT, UIO_SYSSPACE, name, curproc); 195#endif 196 if ((error = namei(&nd))) 197 return (error); 198#if (__NetBSD_Version__ > 399001400) 199# if (__NetBSD_Version__ > 399002000) 200# if (__NetBSD_Version__ < 499001400) 201 VOP_LEASE(nd.ni_dvp, curlwp, curlwp->l_cred, LEASE_WRITE); 202# endif 203# else 204 VOP_LEASE(nd.ni_dvp, curlwp, curlwp->l_proc->p_ucred, LEASE_WRITE); 205# endif 206#else 207 VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE); 208#endif 209#if !defined(__NetBSD_Version__) || (__NetBSD_Version__ < 106000000) 210 vn_lock(nd.ni_vp, LK_EXCLUSIVE | LK_RETRY); 211#endif 212#if (__NetBSD_Version__ >= 399002000) 213# if (__NetBSD_Version__ < 499001400) 214 VOP_LEASE(nd.ni_vp, curlwp, curlwp->l_cred, LEASE_WRITE); 215# endif 216#else 217# if (__NetBSD_Version__ > 399001400) 218 VOP_LEASE(nd.ni_vp, curlwp, curlwp->l_proc->p_ucred, LEASE_WRITE); 219# else 220 VOP_LEASE(nd.ni_vp, curproc, curproc->p_ucred, LEASE_WRITE); 221# endif 222#endif 223 (void) VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 224 } 225 return 0; 226} 227 228 229static int 230ipf_unload() 231{ 232 int error = 0; 233 234 /* 235 * Unloading - remove the filter rule check from the IP 236 * input/output stream. 237 */ 238 if (ipfmain.ipf_refcnt) 239 error = EBUSY; 240 else if (ipfmain.ipf_running >= 0) { 241 error = ipfdetach(&ipfmain); 242 if (error == 0) { 243 ipf_destroy_all(&ipfmain); 244 ipf_unload_all(); 245 } 246 } 247 248 if (error == 0) { 249 ipfmain.ipf_running = -2; 250 error = ipf_remove(); 251 printf("%s unloaded\n", ipfilter_version); 252 } 253 return error; 254} 255 256 257static int 258ipf_load() 259{ 260 struct nameidata nd; 261 struct vattr vattr; 262 int error = 0, fmode = S_IFCHR|0600, i; 263 char *name; 264 265 /* 266 * XXX Remove existing device nodes prior to creating new ones 267 * XXX using the assigned LKM device slot's major number. In a 268 * XXX perfect world we could use the ones specified by cdevsw[]. 269 */ 270 (void)ipf_remove(); 271 272 bzero((char *)&ipfmain, sizeof(ipfmain)); 273 error = ipf_load_all(); 274 if (error != 0) 275 return error; 276 if (ipf_create_all(&ipfmain) == NULL) { 277 ipf_unload_all(); 278 return EIO; 279 } 280 281 error = ipfattach(&ipfmain); 282 if (error != 0) { 283 (void) ipf_unload(); 284 return error; 285 } 286 287 for (i = 0; (error == 0) && (name = ipf_devfiles[i]); i++) { 288#if (__NetBSD_Version__ > 399001400) 289# if (__NetBSD_Version__ > 499001400) 290 NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE, name); 291# else 292 NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE, name, curlwp); 293# endif 294#else 295 NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE, name, curproc); 296#endif 297 if ((error = namei(&nd))) 298 break; 299 if (nd.ni_vp != NULL) { 300 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 301 if (nd.ni_dvp == nd.ni_vp) 302 vrele(nd.ni_dvp); 303 else 304 vput(nd.ni_dvp); 305 vrele(nd.ni_vp); 306 error = EEXIST; 307 break; 308 } 309 VATTR_NULL(&vattr); 310 vattr.va_type = VCHR; 311 vattr.va_mode = (fmode & 07777); 312 vattr.va_rdev = (ipf_major << 8) | i; 313#if (__NetBSD_Version__ > 399001400) 314# if (__NetBSD_Version__ >= 399002000) 315# if (__NetBSD_Version__ < 499001400) 316 VOP_LEASE(nd.ni_dvp, curlwp, curlwp->l_cred, LEASE_WRITE); 317# endif 318# else 319 VOP_LEASE(nd.ni_dvp, curlwp, curlwp->l_proc->p_ucred, LEASE_WRITE); 320# endif 321#else 322 VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE); 323#endif 324 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 325 if (error == 0) 326 vput(nd.ni_vp); 327 } 328 329 if (error == 0) { 330 char *defpass; 331 332 if (FR_ISPASS(ipfmain.ipf_pass)) 333 defpass = "pass"; 334 else if (FR_ISBLOCK(ipfmain.ipf_pass)) 335 defpass = "block"; 336 else 337 defpass = "no-match -> block"; 338 339 printf("%s initialized. Default = %s all, Logging = %s%s\n", 340 ipfilter_version, defpass, 341#ifdef IPFILTER_LOG 342 "enabled", 343#else 344 "disabled", 345#endif 346#ifdef IPFILTER_COMPILED 347 " (COMPILED)" 348#else 349 "" 350#endif 351 ); 352 ipfmain.ipf_running = 1; 353 } 354 return error; 355} 356