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#include <sys/param.h> 11#include <sys/systm.h> 12#include <sys/conf.h> 13#include <sys/file.h> 14#include <sys/stat.h> 15#include <sys/proc.h> 16#include <sys/uio.h> 17#include <sys/kernel.h> 18#include <sys/vnode.h> 19#include <sys/namei.h> 20#include <sys/malloc.h> 21#include <sys/mount.h> 22#include <sys/exec.h> 23#include <sys/mbuf.h> 24#include <net/if.h> 25#include <netinet/in_systm.h> 26#include <netinet/in.h> 27#include <netinet/ip.h> 28#include <net/route.h> 29#include <netinet/ip_var.h> 30#include <netinet/tcp.h> 31#include <netinet/tcpip.h> 32#include <sys/lkm.h> 33#include "ipl.h" 34#include "ip_compat.h" 35#include "ip_fil.h" 36 37#define vn_lock(v,f) VOP_LOCK(v) 38 39#if !defined(VOP_LEASE) && defined(LEASE_CHECK) 40#define VOP_LEASE LEASE_CHECK 41#endif 42 43 44extern int lkmenodev __P((void)); 45 46#if OpenBSD >= 200311 47int if_ipf_lkmentry __P((struct lkm_table *, int, int)); 48#else 49int if_ipf __P((struct lkm_table *, int, int)); 50#endif 51static int ipf_unload __P((void)); 52static int ipf_load __P((void)); 53static int ipf_remove __P((void)); 54static int ipfaction __P((struct lkm_table *, int)); 55static char *ipf_devfiles[] = { IPL_NAME, IPNAT_NAME, IPSTATE_NAME, 56 IPAUTH_NAME, IPSYNC_NAME, IPSCAN_NAME, 57 IPLOOKUP_NAME, NULL }; 58 59 60struct cdevsw ipfdevsw = 61{ 62 ipfopen, /* open */ 63 ipfclose, /* close */ 64 ipfread, /* read */ 65 (void *)nullop, /* write */ 66 ipfioctl, /* ioctl */ 67 (void *)nullop, /* stop */ 68 (void *)NULL, /* tty */ 69 (void *)nullop, /* select */ 70 (void *)nullop, /* mmap */ 71 NULL /* strategy */ 72}; 73 74int ipf_major = 0; 75 76MOD_DEV(IPL_VERSION, LM_DT_CHAR, -1, &ipfdevsw); 77 78extern int vd_unuseddev __P((void)); 79extern struct cdevsw cdevsw[]; 80extern int nchrdev; 81 82 83#if OpenBSD >= 200311 84int if_ipf_lkmentry (lkmtp, cmd, ver) 85#else 86int if_ipf(lkmtp, cmd, ver) 87#endif 88 struct lkm_table *lkmtp; 89 int cmd, ver; 90{ 91 DISPATCH(lkmtp, cmd, ver, ipfaction, ipfaction, ipfaction); 92} 93 94int lkmexists __P((struct lkm_table *)); /* defined in /sys/kern/kern_lkm.c */ 95 96static int ipfaction(lkmtp, cmd) 97 struct lkm_table *lkmtp; 98 int cmd; 99{ 100 int i; 101 struct lkm_dev *args = lkmtp->private.lkm_dev; 102 int err = 0; 103 104 switch (cmd) 105 { 106 case LKM_E_LOAD : 107 if (lkmexists(lkmtp)) 108 return EEXIST; 109 110 for (i = 0; i < nchrdev; i++) 111 if (cdevsw[i].d_open == (dev_type_open((*)))lkmenodev || 112 cdevsw[i].d_open == ipfopen) 113 break; 114 if (i == nchrdev) { 115 printf("IP Filter: No free cdevsw slots\n"); 116 return ENODEV; 117 } 118 119 ipf_major = i; 120 args->lkm_offset = i; /* slot in cdevsw[] */ 121 printf("IP Filter: loaded into slot %d\n", ipf_major); 122 return ipf_load(); 123 case LKM_E_UNLOAD : 124 err = ipf_unload(); 125 if (!err) 126 printf("IP Filter: unloaded from slot %d\n", 127 ipf_major); 128 break; 129 case LKM_E_STAT : 130 break; 131 default: 132 err = EIO; 133 break; 134 } 135 return err; 136} 137 138 139static int ipf_remove() 140{ 141 struct nameidata nd; 142 int error, i; 143 char *name; 144 145 for (i = 0; (name = ipf_devfiles[i]); i++) { 146#if OpenBSD >= 200311 147 NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_SYSSPACE, 148 name, curproc); 149#else 150 NDINIT(&nd, DELETE, LOCKPARENT, UIO_SYSSPACE, name, curproc); 151#endif 152 if ((error = namei(&nd))) 153 return (error); 154 VOP_LEASE(nd.ni_vp, curproc, curproc->p_ucred, LEASE_WRITE); 155#if OpenBSD < 200311 156 VOP_LOCK(nd.ni_vp, LK_EXCLUSIVE | LK_RETRY, curproc); 157 VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE); 158#else 159 (void)uvm_vnp_uncache(nd.ni_vp); 160 161 VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE); 162 VOP_LEASE(nd.ni_vp, curproc, curproc->p_ucred, LEASE_WRITE); 163#endif 164 (void) VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 165 } 166 return 0; 167} 168 169 170static int ipf_unload() 171{ 172 int error = 0; 173 174 /* 175 * Unloading - remove the filter rule check from the IP 176 * input/output stream. 177 */ 178 if (ipf_refcnt) 179 error = EBUSY; 180 else if (ipf_running >= 0) 181 error = ipfdetach(); 182 183 if (error == 0) { 184 ipf_running = -2; 185 error = ipf_remove(); 186 printf("%s unloaded\n", ipfilter_version); 187 } 188 return error; 189} 190 191 192static int ipf_load() 193{ 194 struct nameidata nd; 195 struct vattr vattr; 196 int error = 0, fmode = S_IFCHR|0600, i; 197 char *name; 198 199 /* 200 * XXX Remove existing device nodes prior to creating new ones 201 * XXX using the assigned LKM device slot's major number. In a 202 * XXX perfect world we could use the ones specified by cdevsw[]. 203 */ 204 (void)ipf_remove(); 205 206 error = ipfattach(); 207 208 for (i = 0; (error == 0) && (name = ipf_devfiles[i]); i++) { 209 NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE, name, curproc); 210 if ((error = namei(&nd))) 211 break; 212 if (nd.ni_vp != NULL) { 213 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 214 if (nd.ni_dvp == nd.ni_vp) 215 vrele(nd.ni_dvp); 216 else 217 vput(nd.ni_dvp); 218 vrele(nd.ni_vp); 219 error = EEXIST; 220 break; 221 } 222 VATTR_NULL(&vattr); 223 vattr.va_type = VCHR; 224 vattr.va_mode = (fmode & 07777); 225 vattr.va_rdev = (ipf_major << 8) | i; 226 VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE); 227 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 228 } 229 230 if (error == 0) { 231 char *defpass; 232 233 if (FR_ISPASS(ipf_pass)) 234 defpass = "pass"; 235 else if (FR_ISBLOCK(ipf_pass)) 236 defpass = "block"; 237 else 238 defpass = "no-match -> block"; 239 240 printf("%s initialized. Default = %s all, Logging = %s%s\n", 241 ipfilter_version, defpass, 242#ifdef IPFILTER_LOG 243 "enabled", 244#else 245 "disabled", 246#endif 247#ifdef IPFILTER_COMPILED 248 " (COMPILED)" 249#else 250 "" 251#endif 252 ); 253 ipf_running = 1; 254 } 255 return error; 256} 257 258 259/* 260 * routines below for saving IP headers to buffer 261 */ 262int 263ipfopen(dev, flags, devtype, p) 264 dev_t dev; 265 int flags; 266 int devtype; 267 struct proc *p; 268{ 269 u_int min = GET_MINOR(dev); 270 int error; 271 272 if (IPL_LOGMAX < min) { 273 error = ENXIO; 274 } else { 275 switch (unit) 276 { 277 case IPL_LOGIPF : 278 case IPL_LOGNAT : 279 case IPL_LOGSTATE : 280 case IPL_LOGAUTH : 281 case IPL_LOGLOOKUP : 282 case IPL_LOGSYNC : 283#ifdef IPFILTER_SCAN 284 case IPL_LOGSCAN : 285#endif 286 error = 0; 287 break; 288 default : 289 error = ENXIO; 290 break; 291 } 292 } 293 return error; 294} 295 296 297int 298ipfclose(dev, flags, devtype, p) 299 dev_t dev; 300 int flags; 301 int devtype; 302 struct proc *p; 303{ 304 u_int min = GET_MINOR(dev); 305 306 if (IPL_LOGMAX < min) 307 min = ENXIO; 308 else 309 min = 0; 310 return min; 311} 312 313 314/* 315 * ipfread/ipflog 316 * both of these must operate with at least splnet() lest they be 317 * called during packet processing and cause an inconsistancy to appear in 318 * the filter lists. 319 */ 320int 321ipfread(dev, uio, ioflag) 322 dev_t dev; 323 register struct uio *uio; 324 int ioflag; 325{ 326 327 if (ipf_running < 1) 328 return EIO; 329 330 if (GET_MINOR(dev) == IPL_LOGSYNC) 331 return ipfsync_read(uio); 332 333#ifdef IPFILTER_LOG 334 return ipflog_read(GET_MINOR(dev), uio); 335#else 336 return ENXIO; 337#endif 338} 339 340 341/* 342 * ipfwrite 343 * both of these must operate with at least splnet() lest they be 344 * called during packet processing and cause an inconsistancy to appear in 345 * the filter lists. 346 */ 347int 348#if (BSD >= 199306) 349ipfwrite(dev, uio, ioflag) 350 int ioflag; 351#else 352ipfwrite(dev, uio) 353#endif 354 dev_t dev; 355 register struct uio *uio; 356{ 357 358 if (ipf_running < 1) 359 return EIO; 360 361 if (GET_MINOR(dev) == IPL_LOGSYNC) 362 return ipfsync_write(uio); 363 return ENXIO; 364} 365