1255332Scy/* $FreeBSD$ */ 2255332Scy 3255332Scy/* 4255332Scy * Copyright (C) 2012 by Darren Reed. 5255332Scy * 6255332Scy * See the IPFILTER.LICENCE file for details on licencing. 7255332Scy * 8255332Scy */ 9255332Scy/* 10255332Scy * 29/12/94 Added code from Marc Huber <huber@fzi.de> to allow it to allocate 11255332Scy * its own major char number! Way cool patch! 12255332Scy */ 13255332Scy 14255332Scy 15255332Scy#include <sys/param.h> 16255332Scy 17255332Scy/* 18255332Scy * Post NetBSD 1.2 has the PFIL interface for packet filters. This turns 19255332Scy * on those hooks. We don't need any special mods with this! 20255332Scy */ 21255332Scy#if (defined(NetBSD) && (NetBSD > 199609) && (NetBSD <= 1991011)) || \ 22255332Scy (defined(NetBSD1_2) && NetBSD1_2 > 1) 23255332Scy# define NETBSD_PF 24255332Scy#endif 25255332Scy 26255332Scy#include <sys/systm.h> 27255332Scy#include <sys/conf.h> 28255332Scy#include <sys/file.h> 29255332Scy#include <sys/stat.h> 30255332Scy#include <sys/proc.h> 31255332Scy#include <sys/uio.h> 32255332Scy#include <sys/kernel.h> 33255332Scy#include <sys/vnode.h> 34255332Scy#include <sys/namei.h> 35255332Scy#include <sys/malloc.h> 36255332Scy#include <sys/mount.h> 37255332Scy#include <sys/exec.h> 38255332Scy#include <sys/mbuf.h> 39255332Scy#include <net/if.h> 40255332Scy#include <netinet/in_systm.h> 41255332Scy#include <netinet/in.h> 42255332Scy#include <netinet/ip.h> 43255332Scy#include <net/route.h> 44255332Scy#include <netinet/ip_var.h> 45255332Scy#include <netinet/tcp.h> 46255332Scy#include <netinet/tcpip.h> 47255332Scy#include <sys/lkm.h> 48255332Scy#include <sys/poll.h> 49255332Scy#include <sys/select.h> 50255332Scy#include "ipl.h" 51255332Scy#include "ip_compat.h" 52255332Scy#include "ip_fil.h" 53255332Scy#include "ip_auth.h" 54255332Scy#include "ip_state.h" 55255332Scy#include "ip_nat.h" 56255332Scy#include "ip_sync.h" 57255332Scy 58255332Scy#if !defined(__NetBSD_Version__) || __NetBSD_Version__ < 103050000 59255332Scy#define vn_lock(v,f) VOP_LOCK(v) 60255332Scy#endif 61255332Scy 62255332Scy#if !defined(VOP_LEASE) && defined(LEASE_CHECK) 63255332Scy#define VOP_LEASE LEASE_CHECK 64255332Scy#endif 65255332Scy 66255332Scy 67255332Scyextern int lkmenodev __P((void)); 68255332Scy 69255332Scy#if NetBSD >= 199706 70255332Scyint ipflkm_lkmentry __P((struct lkm_table *, int, int)); 71255332Scy#else 72255332Scyint xxxinit __P((struct lkm_table *, int, int)); 73255332Scy#endif 74255332Scystatic int ipf_unload __P((void)); 75255332Scystatic int ipf_load __P((void)); 76255332Scystatic int ipf_remove __P((void)); 77255332Scystatic int ipfaction __P((struct lkm_table *, int)); 78255332Scystatic char *ipf_devfiles[] = { IPL_NAME, IPNAT_NAME, IPSTATE_NAME, 79255332Scy IPAUTH_NAME, IPSYNC_NAME, IPSCAN_NAME, 80255332Scy IPLOOKUP_NAME, NULL }; 81255332Scy 82255332Scyint ipf_major = 0; 83255332Scyextern ipf_main_softc_t ipfmain; 84255332Scyextern const struct cdevsw ipl_cdevsw; 85255332Scy 86255332Scy#if defined(__NetBSD__) && (__NetBSD_Version__ >= 106080000) 87255332ScyMOD_DEV(IPL_VERSION, "ipf", NULL, -1, &ipl_cdevsw, -1); 88255332Scy#else 89255332ScyMOD_DEV(IPL_VERSION, LM_DT_CHAR, -1, &ipldevsw); 90255332Scy#endif 91255332Scy 92255332Scyextern int vd_unuseddev __P((void)); 93255332Scyextern struct cdevsw cdevsw[]; 94255332Scyextern int nchrdev; 95255332Scy 96255332Scy 97255332Scyint 98255332Scy#if NetBSD >= 199706 99255332Scyipflkm_lkmentry(lkmtp, cmd, ver) 100255332Scy#else 101255332Scyxxxinit(lkmtp, cmd, ver) 102255332Scy#endif 103255332Scy struct lkm_table *lkmtp; 104255332Scy int cmd, ver; 105255332Scy{ 106255332Scy DISPATCH(lkmtp, cmd, ver, ipfaction, ipfaction, ipfaction); 107255332Scy} 108255332Scy 109255332Scy 110255332Scystatic int 111255332Scyipfaction(lkmtp, cmd) 112255332Scy struct lkm_table *lkmtp; 113255332Scy int cmd; 114255332Scy{ 115255332Scy#if !defined(__NetBSD__) || (__NetBSD_Version__ < 106080000) 116255332Scy int i; 117255332Scy#endif 118255332Scy struct lkm_dev *args = lkmtp->private.lkm_dev; 119255332Scy int err = 0; 120255332Scy 121255332Scy switch (cmd) 122255332Scy { 123255332Scy case LKM_E_LOAD : 124255332Scy if (lkmexists(lkmtp)) 125255332Scy return EEXIST; 126255332Scy 127255332Scy#if defined(__NetBSD__) && (__NetBSD_Version__ >= 106080000) 128255332Scy# if (__NetBSD_Version__ < 200000000) 129255332Scy err = devsw_attach(args->lkm_devname, 130255332Scy args->lkm_bdev, &args->lkm_bdevmaj, 131255332Scy args->lkm_cdev, &args->lkm_cdevmaj); 132255332Scy if (err != 0) 133255332Scy return (err); 134255332Scy# endif 135255332Scy ipf_major = args->lkm_cdevmaj; 136255332Scy#else 137255332Scy for (i = 0; i < nchrdev; i++) 138255332Scy if (cdevsw[i].d_open == (dev_type_open((*)))lkmenodev || 139255332Scy cdevsw[i].d_open == ipfopen) 140255332Scy break; 141255332Scy if (i == nchrdev) { 142255332Scy printf("IP Filter: No free cdevsw slots\n"); 143255332Scy return ENODEV; 144255332Scy } 145255332Scy 146255332Scy ipf_major = i; 147255332Scy args->lkm_offset = i; /* slot in cdevsw[] */ 148255332Scy#endif 149255332Scy printf("IP Filter: loaded into slot %d\n", ipf_major); 150255332Scy return ipf_load(); 151255332Scy case LKM_E_UNLOAD : 152255332Scy#if defined(__NetBSD__) && (__NetBSD_Version__ >= 106080000) 153255332Scy devsw_detach(args->lkm_bdev, args->lkm_cdev); 154255332Scy args->lkm_bdevmaj = -1; 155255332Scy args->lkm_cdevmaj = -1; 156255332Scy#endif 157255332Scy err = ipf_unload(); 158255332Scy if (!err) 159255332Scy printf("IP Filter: unloaded from slot %d\n", 160255332Scy ipf_major); 161255332Scy break; 162255332Scy case LKM_E_STAT : 163255332Scy break; 164255332Scy default: 165255332Scy err = EIO; 166255332Scy break; 167255332Scy } 168255332Scy return err; 169255332Scy} 170255332Scy 171255332Scy 172255332Scystatic int 173255332Scyipf_remove() 174255332Scy{ 175255332Scy char *name; 176255332Scy struct nameidata nd; 177255332Scy int error, i; 178255332Scy 179255332Scy for (i = 0; (name = ipf_devfiles[i]); i++) { 180255332Scy#if (__NetBSD_Version__ > 106009999) 181255332Scy# if (__NetBSD_Version__ > 399001400) 182255332Scy# if (__NetBSD_Version__ > 499001400) 183255332Scy NDINIT(&nd, DELETE, LOCKPARENT|LOCKLEAF, UIO_SYSSPACE, 184255332Scy name); 185255332Scy# else 186255332Scy NDINIT(&nd, DELETE, LOCKPARENT|LOCKLEAF, UIO_SYSSPACE, 187255332Scy name, curlwp); 188255332Scy# endif 189255332Scy# else 190255332Scy NDINIT(&nd, DELETE, LOCKPARENT|LOCKLEAF, UIO_SYSSPACE, 191255332Scy name, curproc); 192255332Scy# endif 193255332Scy#else 194255332Scy NDINIT(&nd, DELETE, LOCKPARENT, UIO_SYSSPACE, name, curproc); 195255332Scy#endif 196255332Scy if ((error = namei(&nd))) 197255332Scy return (error); 198255332Scy#if (__NetBSD_Version__ > 399001400) 199255332Scy# if (__NetBSD_Version__ > 399002000) 200255332Scy# if (__NetBSD_Version__ < 499001400) 201255332Scy VOP_LEASE(nd.ni_dvp, curlwp, curlwp->l_cred, LEASE_WRITE); 202255332Scy# endif 203255332Scy# else 204255332Scy VOP_LEASE(nd.ni_dvp, curlwp, curlwp->l_proc->p_ucred, LEASE_WRITE); 205255332Scy# endif 206255332Scy#else 207255332Scy VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE); 208255332Scy#endif 209255332Scy#if !defined(__NetBSD_Version__) || (__NetBSD_Version__ < 106000000) 210255332Scy vn_lock(nd.ni_vp, LK_EXCLUSIVE | LK_RETRY); 211255332Scy#endif 212255332Scy#if (__NetBSD_Version__ >= 399002000) 213255332Scy# if (__NetBSD_Version__ < 499001400) 214255332Scy VOP_LEASE(nd.ni_vp, curlwp, curlwp->l_cred, LEASE_WRITE); 215255332Scy# endif 216255332Scy#else 217255332Scy# if (__NetBSD_Version__ > 399001400) 218255332Scy VOP_LEASE(nd.ni_vp, curlwp, curlwp->l_proc->p_ucred, LEASE_WRITE); 219255332Scy# else 220255332Scy VOP_LEASE(nd.ni_vp, curproc, curproc->p_ucred, LEASE_WRITE); 221255332Scy# endif 222255332Scy#endif 223255332Scy (void) VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 224255332Scy } 225255332Scy return 0; 226255332Scy} 227255332Scy 228255332Scy 229255332Scystatic int 230255332Scyipf_unload() 231255332Scy{ 232255332Scy int error = 0; 233255332Scy 234255332Scy /* 235255332Scy * Unloading - remove the filter rule check from the IP 236255332Scy * input/output stream. 237255332Scy */ 238255332Scy if (ipfmain.ipf_refcnt) 239255332Scy error = EBUSY; 240255332Scy else if (ipfmain.ipf_running >= 0) { 241255332Scy error = ipfdetach(&ipfmain); 242255332Scy if (error == 0) { 243255332Scy ipf_destroy_all(&ipfmain); 244255332Scy ipf_unload_all(); 245255332Scy } 246255332Scy } 247255332Scy 248255332Scy if (error == 0) { 249255332Scy ipfmain.ipf_running = -2; 250255332Scy error = ipf_remove(); 251255332Scy printf("%s unloaded\n", ipfilter_version); 252255332Scy } 253255332Scy return error; 254255332Scy} 255255332Scy 256255332Scy 257255332Scystatic int 258255332Scyipf_load() 259255332Scy{ 260255332Scy struct nameidata nd; 261255332Scy struct vattr vattr; 262255332Scy int error = 0, fmode = S_IFCHR|0600, i; 263255332Scy char *name; 264255332Scy 265255332Scy /* 266255332Scy * XXX Remove existing device nodes prior to creating new ones 267255332Scy * XXX using the assigned LKM device slot's major number. In a 268255332Scy * XXX perfect world we could use the ones specified by cdevsw[]. 269255332Scy */ 270255332Scy (void)ipf_remove(); 271255332Scy 272255332Scy bzero((char *)&ipfmain, sizeof(ipfmain)); 273255332Scy error = ipf_load_all(); 274255332Scy if (error != 0) 275255332Scy return error; 276255332Scy if (ipf_create_all(&ipfmain) == NULL) { 277255332Scy ipf_unload_all(); 278255332Scy return EIO; 279255332Scy } 280255332Scy 281255332Scy error = ipfattach(&ipfmain); 282255332Scy if (error != 0) { 283255332Scy (void) ipf_unload(); 284255332Scy return error; 285255332Scy } 286255332Scy 287255332Scy for (i = 0; (error == 0) && (name = ipf_devfiles[i]); i++) { 288255332Scy#if (__NetBSD_Version__ > 399001400) 289255332Scy# if (__NetBSD_Version__ > 499001400) 290255332Scy NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE, name); 291255332Scy# else 292255332Scy NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE, name, curlwp); 293255332Scy# endif 294255332Scy#else 295255332Scy NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE, name, curproc); 296255332Scy#endif 297255332Scy if ((error = namei(&nd))) 298255332Scy break; 299255332Scy if (nd.ni_vp != NULL) { 300255332Scy VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 301255332Scy if (nd.ni_dvp == nd.ni_vp) 302255332Scy vrele(nd.ni_dvp); 303255332Scy else 304255332Scy vput(nd.ni_dvp); 305255332Scy vrele(nd.ni_vp); 306255332Scy error = EEXIST; 307255332Scy break; 308255332Scy } 309255332Scy VATTR_NULL(&vattr); 310255332Scy vattr.va_type = VCHR; 311255332Scy vattr.va_mode = (fmode & 07777); 312255332Scy vattr.va_rdev = (ipf_major << 8) | i; 313255332Scy#if (__NetBSD_Version__ > 399001400) 314255332Scy# if (__NetBSD_Version__ >= 399002000) 315255332Scy# if (__NetBSD_Version__ < 499001400) 316255332Scy VOP_LEASE(nd.ni_dvp, curlwp, curlwp->l_cred, LEASE_WRITE); 317255332Scy# endif 318255332Scy# else 319255332Scy VOP_LEASE(nd.ni_dvp, curlwp, curlwp->l_proc->p_ucred, LEASE_WRITE); 320255332Scy# endif 321255332Scy#else 322255332Scy VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE); 323255332Scy#endif 324255332Scy error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 325255332Scy if (error == 0) 326255332Scy vput(nd.ni_vp); 327255332Scy } 328255332Scy 329255332Scy if (error == 0) { 330255332Scy char *defpass; 331255332Scy 332255332Scy if (FR_ISPASS(ipfmain.ipf_pass)) 333255332Scy defpass = "pass"; 334255332Scy else if (FR_ISBLOCK(ipfmain.ipf_pass)) 335255332Scy defpass = "block"; 336255332Scy else 337255332Scy defpass = "no-match -> block"; 338255332Scy 339255332Scy printf("%s initialized. Default = %s all, Logging = %s%s\n", 340255332Scy ipfilter_version, defpass, 341255332Scy#ifdef IPFILTER_LOG 342255332Scy "enabled", 343255332Scy#else 344255332Scy "disabled", 345255332Scy#endif 346255332Scy#ifdef IPFILTER_COMPILED 347255332Scy " (COMPILED)" 348255332Scy#else 349255332Scy "" 350255332Scy#endif 351255332Scy ); 352255332Scy ipfmain.ipf_running = 1; 353255332Scy } 354255332Scy return error; 355255332Scy} 356