]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/ipfilter/mlf_ipl.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / ipfilter / mlf_ipl.c
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  * 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 #ifdef  IPFILTER_LKM
17 # ifndef __FreeBSD_cc_version
18 #  include <osreldate.h>
19 # else
20 #  if __FreeBSD_cc_version < 430000
21 #   include <osreldate.h>
22 #  endif
23 # endif
24 # define        ACTUALLY_LKM_NOT_KERNEL
25 #else
26 # ifndef __FreeBSD_cc_version
27 #  include <sys/osreldate.h>
28 # else
29 #  if __FreeBSD_cc_version < 430000
30 #   include <sys/osreldate.h>
31 #  endif
32 # endif
33 #endif
34 #include <sys/systm.h>
35 #if defined(__FreeBSD_version) && (__FreeBSD_version >= 220000)
36 # ifndef ACTUALLY_LKM_NOT_KERNEL
37 #  include "opt_devfs.h"
38 # endif
39 # include <sys/conf.h>
40 # include <sys/kernel.h>
41 # ifdef DEVFS
42 #  include <sys/devfsext.h>
43 # endif /*DEVFS*/
44 #endif
45 #include <sys/conf.h>
46 #include <sys/file.h>
47 #if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
48 # include <sys/lock.h>
49 #endif
50 #include <sys/stat.h>
51 #include <sys/proc.h>
52 #include <sys/kernel.h>
53 #include <sys/vnode.h>
54 #include <sys/namei.h>
55 #include <sys/malloc.h>
56 #include <sys/mount.h>
57 #include <sys/exec.h>
58 #include <sys/mbuf.h>
59 #if     BSD >= 199506
60 # include <sys/sysctl.h>
61 #endif
62 #if (__FreeBSD_version >= 300000)
63 # include <sys/socket.h>
64 #endif
65 #include <net/if.h>
66 #include <netinet/in_systm.h>
67 #include <netinet/in.h>
68 #include <netinet/ip.h>
69 #include <net/route.h>
70 #include <netinet/ip_var.h>
71 #include <netinet/tcp.h>
72 #include <netinet/tcpip.h>
73 #include <sys/sysent.h>
74 #include <sys/lkm.h>
75 #include "netinet/ipl.h"
76 #include "netinet/ip_compat.h"
77 #include "netinet/ip_fil.h"
78 #include "netinet/ip_state.h"
79 #include "netinet/ip_nat.h"
80 #include "netinet/ip_auth.h"
81 #include "netinet/ip_frag.h"
82
83
84 #if !defined(VOP_LEASE) && defined(LEASE_CHECK)
85 #define VOP_LEASE       LEASE_CHECK
86 #endif
87
88 int     xxxinit __P((struct lkm_table *, int, int));
89
90 #ifdef  SYSCTL_OID
91 int sysctl_ipf_int SYSCTL_HANDLER_ARGS;
92 # define SYSCTL_IPF(parent, nbr, name, access, ptr, val, descr) \
93         SYSCTL_OID(parent, nbr, name, CTLTYPE_INT|access, \
94                    ptr, val, sysctl_ipf_int, "I", descr);
95 # define        CTLFLAG_OFF     0x00800000      /* IPFilter must be disabled */
96 # define        CTLFLAG_RWO     (CTLFLAG_RW|CTLFLAG_OFF)
97 SYSCTL_NODE(_net_inet, OID_AUTO, ipf, CTLFLAG_RW, 0, "IPF");
98 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_flags, CTLFLAG_RW, &ipf_flags, 0, "");
99 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_pass, CTLFLAG_RW, &ipf_pass, 0, "");
100 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_active, CTLFLAG_RD, &ipf_active, 0, "");
101 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_chksrc, CTLFLAG_RW, &ipf_chksrc, 0, "");
102 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_minttl, CTLFLAG_RW, &ipf_minttl, 0, "");
103 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpidletimeout, CTLFLAG_RWO,
104            &ipf_tcpidletimeout, 0, "");
105 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcphalfclosed, CTLFLAG_RWO,
106            &ipf_tcphalfclosed, 0, "");
107 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpclosewait, CTLFLAG_RWO,
108            &ipf_tcpclosewait, 0, "");
109 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcplastack, CTLFLAG_RWO,
110            &ipf_tcplastack, 0, "");
111 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcptimeout, CTLFLAG_RWO,
112            &ipf_tcptimeout, 0, "");
113 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpclosed, CTLFLAG_RWO,
114            &ipf_tcpclosed, 0, "");
115 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_udptimeout, CTLFLAG_RWO,
116            &ipf_udptimeout, 0, "");
117 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_icmptimeout, CTLFLAG_RWO,
118            &ipf_icmptimeout, 0, "");
119 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_defnatage, CTLFLAG_RWO,
120            &ipf_defnatage, 0, "");
121 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_ipfrttl, CTLFLAG_RW,
122            &ipf_ipfrttl, 0, "");
123 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_running, CTLFLAG_RD,
124            &ipf_running, 0, "");
125 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_statesize, CTLFLAG_RWO,
126            &ipf_statesize, 0, "");
127 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_statemax, CTLFLAG_RWO,
128            &ipf_statemax, 0, "");
129 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_authsize, CTLFLAG_RWO,
130            &ipf_authsize, 0, "");
131 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_authused, CTLFLAG_RD,
132            &ipf_authused, 0, "");
133 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_defaultauthage, CTLFLAG_RW,
134            &ipf_defaultauthage, 0, "");
135 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ippr_ftp_pasvonly, CTLFLAG_RW,
136            &ippr_ftp_pasvonly, 0, "");
137 #endif
138
139 #ifdef DEVFS
140 static void *ipf_devfs[IPL_LOGSIZE];
141 #endif
142
143 #if !defined(__FreeBSD_version) || (__FreeBSD_version < 220000)
144 int     ipf_major = 0;
145
146 static struct   cdevsw  ipfdevsw =
147 {
148         ipfopen,                /* open */
149         ipfclose,               /* close */
150         ipfread,                /* read */
151         (void *)nullop,         /* write */
152         ipfioctl,               /* ioctl */
153         (void *)nullop,         /* stop */
154         (void *)nullop,         /* reset */
155         (void *)NULL,           /* tty */
156         (void *)nullop,         /* select */
157         (void *)nullop,         /* mmap */
158         NULL                    /* strategy */
159 };
160
161 MOD_DEV(IPL_VERSION, LM_DT_CHAR, -1, &ipfdevsw);
162
163 extern struct cdevsw cdevsw[];
164 extern int vd_unuseddev __P((void));
165 extern int nchrdev;
166 #else
167
168 static struct cdevsw ipf_cdevsw = {
169         ipfopen,        ipfclose,       ipfread,        nowrite, /* 79 */
170         ipfioctl,       nostop,         noreset,        nodevtotty,
171 #if (__FreeBSD_version >= 300000)
172         seltrue,        nommap,         nostrategy,     "ipf",
173 #else
174         noselect,       nommap,         nostrategy,     "ipf",
175 #endif
176         NULL,   -1
177 };
178 #endif
179
180 static void ipf_drvinit __P((void *));
181
182 #ifdef ACTUALLY_LKM_NOT_KERNEL
183 static  int     if_ipf_unload __P((struct lkm_table *, int));
184 static  int     if_ipf_load __P((struct lkm_table *, int));
185 static  int     if_ipf_remove __P((void));
186 static  int     ipf_major = CDEV_MAJOR;
187
188 static int ipfaction __P((struct lkm_table *, int));
189 static char *ipf_devfiles[] = { IPL_NAME, IPL_NAT, IPL_STATE, IPL_AUTH,
190                                 IPL_SCAN, IPL_SYNC, IPL_POOL, NULL };
191
192 extern  int     lkmenodev __P((void));
193
194 static int ipfaction(lkmtp, cmd)
195         struct lkm_table *lkmtp;
196         int cmd;
197 {
198 #if !defined(__FreeBSD_version) || (__FreeBSD_version < 220000)
199         int i = ipf_major;
200         struct lkm_dev *args = lkmtp->private.lkm_dev;
201 #endif
202         int err = 0;
203
204         switch (cmd)
205         {
206         case LKM_E_LOAD :
207                 if (lkmexists(lkmtp))
208                         return EEXIST;
209
210 #if !defined(__FreeBSD_version) || (__FreeBSD_version < 220000)
211                 for (i = 0; i < nchrdev; i++)
212                         if (cdevsw[i].d_open == lkmenodev ||
213                             cdevsw[i].d_open == ipfopen)
214                                 break;
215                 if (i == nchrdev) {
216                         printf("IP Filter: No free cdevsw slots\n");
217                         return ENODEV;
218                 }
219
220                 ipf_major = i;
221                 args->lkm_offset = i;   /* slot in cdevsw[] */
222 #endif
223                 printf("IP Filter: loaded into slot %d\n", ipf_major);
224                 err = if_ipf_load(lkmtp, cmd);
225                 if (!err)
226                         ipf_drvinit((void *)NULL);
227                 return err;
228                 break;
229         case LKM_E_UNLOAD :
230                 err = if_ipf_unload(lkmtp, cmd);
231                 if (!err) {
232                         printf("IP Filter: unloaded from slot %d\n",
233                                 ipf_major);
234 #ifdef  DEVFS
235                         if (ipf_devfs[IPL_LOGIPF])
236                                 devfs_remove_dev(ipf_devfs[IPL_LOGIPF]);
237                         if (ipf_devfs[IPL_LOGNAT])
238                                 devfs_remove_dev(ipf_devfs[IPL_LOGNAT]);
239                         if (ipf_devfs[IPL_LOGSTATE])
240                                 devfs_remove_dev(ipf_devfs[IPL_LOGSTATE]);
241                         if (ipf_devfs[IPL_LOGAUTH])
242                                 devfs_remove_dev(ipf_devfs[IPL_LOGAUTH]);
243                         if (ipf_devfs[IPL_LOGSCAN])
244                                 devfs_remove_dev(ipf_devfs[IPL_LOGSCAN]);
245                         if (ipf_devfs[IPL_LOGSYNC])
246                                 devfs_remove_dev(ipf_devfs[IPL_LOGSYNC]);
247                         if (ipf_devfs[IPL_LOGLOOKUP])
248                                 devfs_remove_dev(ipf_devfs[IPL_LOGLOOKUP]);
249 #endif
250                 }
251                 return err;
252         case LKM_E_STAT :
253                 break;
254         default:
255                 err = EIO;
256                 break;
257         }
258         return 0;
259 }
260
261
262 static int if_ipf_remove __P((void))
263 {
264         char *name;
265         struct nameidata nd;
266         int error, i;
267
268         for (i = 0; (name = ipf_devfiles[i]); i++) {
269                 NDINIT(&nd, DELETE, LOCKPARENT, UIO_SYSSPACE, name, curproc);
270                 if ((error = namei(&nd)))
271                         return (error);
272                 VOP_LEASE(nd.ni_vp, curproc, curproc->p_ucred, LEASE_WRITE);
273 #if (__FreeBSD_version >= 300000)
274                 VOP_LOCK(nd.ni_vp, LK_RETRY | LK_EXCLUSIVE, curproc);
275                 VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE);
276                 (void) VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
277
278                 if (nd.ni_dvp == nd.ni_vp)
279                         vrele(nd.ni_dvp);
280                 else
281                         vput(nd.ni_dvp);
282                 if (nd.ni_vp != NULLVP)
283                         vput(nd.ni_vp);
284 #else
285                 VOP_LOCK(nd.ni_vp);
286                 VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE);
287                 (void) VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
288 #endif
289         }
290
291         return 0;
292 }
293
294
295 static int if_ipf_unload(lkmtp, cmd)
296         struct lkm_table *lkmtp;
297         int cmd;
298 {
299         int error = 0;
300
301         error = ipfdetach();
302         if (!error)
303                 error = if_ipf_remove();
304         return error;
305 }
306
307
308 static int if_ipf_load(lkmtp, cmd)
309         struct lkm_table *lkmtp;
310         int cmd;
311 {
312         struct nameidata nd;
313         struct vattr vattr;
314         int error = 0, fmode = S_IFCHR|0600, i;
315         char *name;
316
317         error = ipfattach();
318         if (error)
319                 return error;
320         (void) if_ipf_remove();
321
322         for (i = 0; (name = ipf_devfiles[i]); i++) {
323                 NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE, name, curproc);
324                 if ((error = namei(&nd)))
325                         return error;
326                 if (nd.ni_vp != NULL) {
327                         VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
328                         if (nd.ni_dvp == nd.ni_vp)
329                                 vrele(nd.ni_dvp);
330                         else
331                                 vput(nd.ni_dvp);
332                         vrele(nd.ni_vp);
333                         return (EEXIST);
334                 }
335                 VATTR_NULL(&vattr);
336                 vattr.va_type = VCHR;
337                 vattr.va_mode = (fmode & 07777);
338                 vattr.va_rdev = (ipf_major << 8) | i;
339                 VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE);
340                 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
341 #if (__FreeBSD_version >= 300000)
342                 vput(nd.ni_dvp);
343 #endif
344                 if (error)
345                         return error;
346         }
347         return 0;
348 }
349
350 #endif  /* actually LKM */
351
352 #if defined(__FreeBSD_version) && (__FreeBSD_version < 220000)
353 /*
354  * strlen isn't present in 2.1.* kernels.
355  */
356 size_t strlen(string)
357         char *string;
358 {
359         register char *s;
360
361         for (s = string; *s; s++)
362                 ;
363         return (size_t)(s - string);
364 }
365
366
367 int xxxinit(lkmtp, cmd, ver)
368         struct lkm_table *lkmtp;
369         int cmd, ver;
370 {
371         DISPATCH(lkmtp, cmd, ver, ipfaction, ipfaction, ipfaction);
372 }
373 #else   /* __FREEBSD_version >= 220000 */
374 # ifdef IPFILTER_LKM
375 #  include <sys/exec.h>
376
377 #  if (__FreeBSD_version >= 300000)
378 MOD_DEV(if_ipf, LM_DT_CHAR, CDEV_MAJOR, &ipf_cdevsw);
379 #  else
380 MOD_DECL(if_ipf);
381
382
383 static struct lkm_dev _module = {
384         LM_DEV,
385         LKM_VERSION,
386         IPL_VERSION,
387         CDEV_MAJOR,
388         LM_DT_CHAR,
389         { (void *)&ipf_cdevsw }
390 };
391 #  endif
392
393
394 int if_ipf __P((struct lkm_table *, int, int));
395
396
397 int if_ipf(lkmtp, cmd, ver)
398         struct lkm_table *lkmtp;
399         int cmd, ver;
400 {
401 #  if (__FreeBSD_version >= 300000)
402         MOD_DISPATCH(if_ipf, lkmtp, cmd, ver, ipfaction, ipfaction, ipfaction);
403 #  else
404         DISPATCH(lkmtp, cmd, ver, ipfaction, ipfaction, ipfaction);
405 #  endif
406 }
407 # endif /* IPFILTER_LKM */
408 static ipf_devsw_installed = 0;
409
410 static void ipf_drvinit __P((void *unused))
411 {
412         dev_t dev;
413 # ifdef DEVFS
414         void **tp = ipf_devfs;
415 # endif
416
417         if (!ipf_devsw_installed ) {
418                 dev = makedev(CDEV_MAJOR, 0);
419                 cdevsw_add(&dev, &ipf_cdevsw, NULL);
420                 ipf_devsw_installed = 1;
421
422 # ifdef DEVFS
423                 tp[IPL_LOGIPF] = devfs_add_devswf(&ipf_cdevsw, IPL_LOGIPF,
424                                                   DV_CHR, 0, 0, 0600, "ipf");
425                 tp[IPL_LOGNAT] = devfs_add_devswf(&ipf_cdevsw, IPL_LOGNAT,
426                                                   DV_CHR, 0, 0, 0600, "ipnat");
427                 tp[IPL_LOGSTATE] = devfs_add_devswf(&ipf_cdevsw, IPL_LOGSTATE,
428                                                     DV_CHR, 0, 0, 0600,
429                                                     "ipstate");
430                 tp[IPL_LOGAUTH] = devfs_add_devswf(&ipf_cdevsw, IPL_LOGAUTH,
431                                                    DV_CHR, 0, 0, 0600,
432                                                    "ipauth");
433 # endif
434         }
435 }
436
437
438 #ifdef SYSCTL_IPF
439 int
440 sysctl_ipf_int SYSCTL_HANDLER_ARGS
441 {
442         int error = 0;
443
444         if (arg1)
445                 error = SYSCTL_OUT(req, arg1, sizeof(int));
446         else
447                 error = SYSCTL_OUT(req, &arg2, sizeof(int));
448
449         if (error || !req->newptr)
450                 return (error);
451
452         if (!arg1)
453                 error = EPERM;
454         else {
455                 if ((oidp->oid_kind & CTLFLAG_OFF) && (ipf_running > 0))
456                         error = EBUSY;
457                 else
458                         error = SYSCTL_IN(req, arg1, sizeof(int));
459         }
460         return (error);
461 }
462 #endif
463
464
465 # if defined(IPFILTER_LKM) || \
466      defined(__FreeBSD_version) && (__FreeBSD_version >= 220000)
467 SYSINIT(ipfdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,ipf_drvinit,NULL)
468 # endif /* IPFILTER_LKM */
469 #endif /* _FreeBSD_version */
470
471
472 /*
473  * routines below for saving IP headers to buffer
474  */
475 int ipfopen(dev, flags
476 #if ((BSD >= 199506) || (__FreeBSD_version >= 220000))
477 , devtype, p)
478         int devtype;
479 # if (__FreeBSD_version >= 500024)
480         struct thread *p;
481 # else
482         struct proc *p;
483 # endif /* __FreeBSD_version >= 500024 */
484 #else
485 )
486 #endif
487 #if (__FreeBSD_version >= 502116)
488         struct cdev *dev;
489 #else
490         dev_t dev;
491 #endif
492         int flags;
493 {
494         u_int unit = GET_MINOR(dev);
495
496         if (IPL_LOGMAX < unit)
497                 unit = ENXIO;
498         else
499                 unit = 0;
500         return unit;
501 }
502
503
504 int ipfclose(dev, flags
505 #if ((BSD >= 199506) || (__FreeBSD_version >= 220000))
506 , devtype, p)
507         int devtype;
508 # if (__FreeBSD_version >= 500024)
509         struct thread *p;
510 # else
511         struct proc *p;
512 # endif /* __FreeBSD_version >= 500024 */
513 #else
514 )
515 #endif
516 #if (__FreeBSD_version >= 502116)
517         struct cdev *dev;
518 #else
519         dev_t dev;
520 #endif
521         int flags;
522 {
523         u_int   unit = GET_MINOR(dev);
524
525         if (IPL_LOGMAX < unit)
526                 unit = ENXIO;
527         else
528                 unit = 0;
529         return unit;
530 }
531
532 /*
533  * ipfread/ipflog
534  * both of these must operate with at least splnet() lest they be
535  * called during packet processing and cause an inconsistancy to appear in
536  * the filter lists.
537  */
538 #if (BSD >= 199306)
539 int ipfread(dev, uio, ioflag)
540         int ioflag;
541 #else
542 int ipfread(dev, uio)
543 #endif
544 #if (__FreeBSD_version >= 502116)
545         struct cdev *dev;
546 #else
547         dev_t dev;
548 #endif
549         register struct uio *uio;
550 {
551         u_int   unit = GET_MINOR(dev);
552
553         if (unit < 0)
554                 return ENXIO;
555
556         if (ipf_running < 1)
557                 return EIO;
558
559         if (unit == IPL_LOGSYNC)
560                 return ipfsync_read(uio);
561
562 #ifdef IPFILTER_LOG
563         return ipflog_read(unit, uio);
564 #else
565         return ENXIO;
566 #endif
567 }
568
569
570 /*
571  * ipfwrite
572  * both of these must operate with at least splnet() lest they be
573  * called during packet processing and cause an inconsistancy to appear in
574  * the filter lists.
575  */
576 #if (BSD >= 199306)
577 int ipfwrite(dev, uio, ioflag)
578         int ioflag;
579 #else
580 int ipfwrite(dev, uio)
581 #endif
582 #if (__FreeBSD_version >= 502116)
583         struct cdev *dev;
584 #else
585         dev_t dev;
586 #endif
587         register struct uio *uio;
588 {
589
590         if (ipf_running < 1)
591                 return EIO;
592
593         if (GET_MINOR(dev) == IPL_LOGSYNC)
594                 return ipfsync_write(uio);
595         return ENXIO;
596 }