Add regression test infrastructure.
[dragonfly.git] / contrib / ipfilter / mlf_ipl.c
1 /*
2  * Copyright (C) 1993-2001 by Darren Reed.
3  *
4  * See the IPFILTER.LICENCE file for details on licencing.
5  */
6 /*
7  * 29/12/94 Added code from Marc Huber <huber@fzi.de> to allow it to allocate
8  * its own major char number! Way cool patch!
9  */
10
11
12 #include <sys/param.h>
13
14 #if defined(__FreeBSD__)
15 # ifndef __FreeBSD_version
16 #  ifdef IPFILTER_LKM
17 #   include <osreldate.h>
18 #  else
19 #   include <sys/osreldate.h>
20 #  endif
21 # endif
22 # ifdef IPFILTER_LKM
23 #  define       ACTUALLY_LKM_NOT_KERNEL
24 # endif
25 #endif
26 #include <sys/systm.h>
27 #if defined(__FreeBSD_version) && (__FreeBSD_version >= 220000)
28 # ifndef ACTUALLY_LKM_NOT_KERNEL
29 #  include "opt_devfs.h"
30 # endif
31 # include <sys/conf.h>
32 # include <sys/kernel.h>
33 # ifdef DEVFS
34 #  include <sys/devfsext.h>
35 # endif /*DEVFS*/
36 #endif
37 #include <sys/conf.h>
38 #include <sys/file.h>
39 #if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
40 # include <sys/lock.h>
41 #endif
42 #include <sys/stat.h>
43 #include <sys/proc.h>
44 #include <sys/uio.h>
45 #include <sys/kernel.h>
46 #include <sys/vnode.h>
47 #include <sys/namei.h>
48 #include <sys/malloc.h>
49 #include <sys/mount.h>
50 #include <sys/exec.h>
51 #include <sys/mbuf.h>
52 #if     BSD >= 199506
53 # include <sys/sysctl.h>
54 #endif
55 #if (__FreeBSD_version >= 300000)
56 # include <sys/socket.h>
57 #endif
58 #include <net/if.h>
59 #include <netinet/in_systm.h>
60 #include <netinet/in.h>
61 #include <netinet/ip.h>
62 #include <net/route.h>
63 #include <net/if.h>
64 #include <netinet/ip_var.h>
65 #include <netinet/tcp.h>
66 #include <netinet/tcpip.h>
67 #include <sys/sysent.h>
68 #include <sys/lkm.h>
69 #include "netinet/ipl.h"
70 #include "netinet/ip_compat.h"
71 #include "netinet/ip_fil.h"
72 #include "netinet/ip_state.h"
73 #include "netinet/ip_nat.h"
74 #include "netinet/ip_auth.h"
75 #include "netinet/ip_frag.h"
76 #include "netinet/ip_proxy.h"
77
78
79 #if !defined(VOP_LEASE) && defined(LEASE_CHECK)
80 #define VOP_LEASE       LEASE_CHECK
81 #endif
82
83 #ifndef MIN
84 #define MIN(a,b)        (((a)<(b))?(a):(b))
85 #endif
86
87 int     xxxinit __P((struct lkm_table *, int, int));
88
89 #ifdef  SYSCTL_INT
90 SYSCTL_NODE(_net_inet, OID_AUTO, ipf, CTLFLAG_RW, 0, "IPF");
91 SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_flags, CTLFLAG_RW, &fr_flags, 0, "");
92 SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_pass, CTLFLAG_RW, &fr_pass, 0, "");
93 SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_active, CTLFLAG_RD, &fr_active, 0, "");
94 SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_chksrc, CTLFLAG_RW, &fr_chksrc, 0, "");
95 SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_minttl, CTLFLAG_RW, &fr_minttl, 0, "");
96 SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_minttllog, CTLFLAG_RW,
97            &fr_minttllog, 0, "");
98 SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcpidletimeout, CTLFLAG_RW,
99            &fr_tcpidletimeout, 0, "");
100 SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcphalfclosed, CTLFLAG_RW,
101            &fr_tcphalfclosed, 0, "");
102 SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcpclosewait, CTLFLAG_RW,
103            &fr_tcpclosewait, 0, "");
104 SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcplastack, CTLFLAG_RW,
105            &fr_tcplastack, 0, "");
106 SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcptimeout, CTLFLAG_RW,
107            &fr_tcptimeout, 0, "");
108 SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcpclosed, CTLFLAG_RW,
109            &fr_tcpclosed, 0, "");
110 SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_udptimeout, CTLFLAG_RW,
111            &fr_udptimeout, 0, "");
112 SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_udpacktimeout, CTLFLAG_RW,
113            &fr_udpacktimeout, 0, "");
114 SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_icmptimeout, CTLFLAG_RW,
115            &fr_icmptimeout, 0, "");
116 SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_icmpacktimeout, CTLFLAG_RW,
117            &fr_icmpacktimeout, 0, "");
118 SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_defnatage, CTLFLAG_RW,
119            &fr_defnatage, 0, "");
120 SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_ipfrttl, CTLFLAG_RW,
121            &fr_ipfrttl, 0, "");
122 SYSCTL_INT(_net_inet_ipf, OID_AUTO, ipl_unreach, CTLFLAG_RW,
123            &ipl_unreach, 0, "");
124 SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_running, CTLFLAG_RD,
125            &fr_running, 0, "");
126 SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_authsize, CTLFLAG_RD,
127            &fr_authsize, 0, "");
128 SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_authused, CTLFLAG_RD,
129            &fr_authused, 0, "");
130 SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_defaultauthage, CTLFLAG_RW,
131            &fr_defaultauthage, 0, "");
132 SYSCTL_INT(_net_inet_ipf, OID_AUTO, ippr_ftp_pasvonly, CTLFLAG_RW,
133            &ippr_ftp_pasvonly, 0, "");
134 #endif
135
136 #ifdef DEVFS
137 static void *ipf_devfs[IPL_LOGMAX + 1];
138 #endif
139
140 #if !defined(__FreeBSD_version) || (__FreeBSD_version < 220000)
141 int     ipl_major = 0;
142
143 static struct   cdevsw  ipldevsw =
144 {
145         iplopen,                /* open */
146         iplclose,               /* close */
147         iplread,                /* read */
148         (void *)nullop,         /* write */
149         iplioctl,               /* ioctl */
150         (void *)nullop,         /* stop */
151         (void *)nullop,         /* reset */
152         (void *)NULL,           /* tty */
153         (void *)nullop,         /* select */
154         (void *)nullop,         /* mmap */
155         NULL                    /* strategy */
156 };
157
158 MOD_DEV(IPL_VERSION, LM_DT_CHAR, -1, &ipldevsw);
159
160 extern struct cdevsw cdevsw[];
161 extern int vd_unuseddev __P((void));
162 extern int nchrdev;
163 #else
164
165 static struct cdevsw ipl_cdevsw = {
166         iplopen,        iplclose,       iplread,        nowrite, /* 79 */
167         iplioctl,       nostop,         noreset,        nodevtotty,
168 #if (__FreeBSD_version >= 300000)
169         seltrue,        nommap,         nostrategy,     "ipl",
170 #else
171         noselect,       nommap,         nostrategy,     "ipl",
172 #endif
173         NULL,   -1
174 };
175 #endif
176
177 static void ipl_drvinit __P((void *));
178
179 #ifdef ACTUALLY_LKM_NOT_KERNEL
180 static  int     if_ipl_unload __P((struct lkm_table *, int));
181 static  int     if_ipl_load __P((struct lkm_table *, int));
182 static  int     if_ipl_remove __P((void));
183 static  int     ipl_major = CDEV_MAJOR;
184
185 static int iplaction __P((struct lkm_table *, int));
186 static char *ipf_devfiles[] = { IPL_NAME, IPL_NAT, IPL_STATE, IPL_AUTH, NULL };
187
188 extern  int     lkmenodev __P((void));
189
190 static int iplaction(lkmtp, cmd)
191 struct lkm_table *lkmtp;
192 int cmd;
193 {
194 #if !defined(__FreeBSD_version) || (__FreeBSD_version < 220000)
195         int i = ipl_major;
196         struct lkm_dev *args = lkmtp->private.lkm_dev;
197 #endif
198         int err = 0;
199
200         switch (cmd)
201         {
202         case LKM_E_LOAD :
203                 if (lkmexists(lkmtp))
204                         return EEXIST;
205
206 #if !defined(__FreeBSD_version) || (__FreeBSD_version < 220000)
207                 for (i = 0; i < nchrdev; i++)
208                         if (cdevsw[i].d_open == lkmenodev ||
209                             cdevsw[i].d_open == iplopen)
210                                 break;
211                 if (i == nchrdev) {
212                         printf("IP Filter: No free cdevsw slots\n");
213                         return ENODEV;
214                 }
215
216                 ipl_major = i;
217                 args->lkm_offset = i;   /* slot in cdevsw[] */
218 #endif
219                 printf("IP Filter: loaded into slot %d\n", ipl_major);
220                 err = if_ipl_load(lkmtp, cmd);
221                 if (!err)
222                         ipl_drvinit((void *)NULL);
223                 return err;
224                 break;
225         case LKM_E_UNLOAD :
226                 err = if_ipl_unload(lkmtp, cmd);
227                 if (!err) {
228                         printf("IP Filter: unloaded from slot %d\n",
229                                 ipl_major);
230 #ifdef  DEVFS
231                         if (ipf_devfs[IPL_LOGIPF])
232                                 devfs_remove_dev(ipf_devfs[IPL_LOGIPF]);
233                         if (ipf_devfs[IPL_LOGNAT])
234                                 devfs_remove_dev(ipf_devfs[IPL_LOGNAT]);
235                         if (ipf_devfs[IPL_LOGSTATE])
236                                 devfs_remove_dev(ipf_devfs[IPL_LOGSTATE]);
237                         if (ipf_devfs[IPL_LOGAUTH])
238                                 devfs_remove_dev(ipf_devfs[IPL_LOGAUTH]);
239 #endif
240                 }
241                 return err;
242         case LKM_E_STAT :
243                 break;
244         default:
245                 err = EIO;
246                 break;
247         }
248         return 0;
249 }
250
251
252 static int if_ipl_remove __P((void))
253 {
254         char *name;
255         struct nameidata nd;
256         int error, i;
257
258         for (i = 0; (name = ipf_devfiles[i]); i++) {
259                 NDINIT(&nd, DELETE, LOCKPARENT, UIO_SYSSPACE, name, curproc);
260                 if ((error = namei(&nd)))
261                         return (error);
262                 VOP_LEASE(nd.ni_vp, curproc, curproc->p_ucred, LEASE_WRITE);
263 #if (__FreeBSD_version >= 300000)
264                 VOP_LOCK(nd.ni_vp, LK_RETRY | LK_EXCLUSIVE, curproc);
265                 VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE);
266                 (void) VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
267
268                 if (nd.ni_dvp == nd.ni_vp)
269                         vrele(nd.ni_dvp);
270                 else
271                         vput(nd.ni_dvp);
272                 if (nd.ni_vp != NULLVP)
273                         vput(nd.ni_vp);
274 #else
275                 VOP_LOCK(nd.ni_vp);
276                 VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE);
277                 (void) VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
278 #endif
279         }
280
281         return 0;
282 }
283
284
285 static int if_ipl_unload(lkmtp, cmd)
286 struct lkm_table *lkmtp;
287 int cmd;
288 {
289         int error = 0;
290
291         error = ipldetach();
292         if (!error)
293                 error = if_ipl_remove();
294         return error;
295 }
296
297
298 static int if_ipl_load(lkmtp, cmd)
299 struct lkm_table *lkmtp;
300 int cmd;
301 {
302         struct nameidata nd;
303         struct vattr vattr;
304         int error = 0, fmode = S_IFCHR|0600, i;
305         char *name;
306
307         error = iplattach();
308         if (error)
309                 return error;
310         (void) if_ipl_remove();
311
312         for (i = 0; (name = ipf_devfiles[i]); i++) {
313                 NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE, name, curproc);
314                 if ((error = namei(&nd)))
315                         return error;
316                 if (nd.ni_vp != NULL) {
317                         VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
318                         if (nd.ni_dvp == nd.ni_vp)
319                                 vrele(nd.ni_dvp);
320                         else
321                                 vput(nd.ni_dvp);
322                         vrele(nd.ni_vp);
323                         return (EEXIST);
324                 }
325                 VATTR_NULL(&vattr);
326                 vattr.va_type = VCHR;
327                 vattr.va_mode = (fmode & 07777);
328                 vattr.va_rdev = (ipl_major << 8) | i;
329                 VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE);
330                 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
331 #if (__FreeBSD_version >= 300000)
332                 vput(nd.ni_dvp);
333 #endif
334                 if (error)
335                         return error;
336         }
337         return 0;
338 }
339
340 #endif  /* actually LKM */
341
342 #if defined(__FreeBSD_version) && (__FreeBSD_version < 220000)
343 /*
344  * strlen isn't present in 2.1.* kernels.
345  */
346 size_t strlen(string)
347 char *string;
348 {
349         register char *s;
350
351         for (s = string; *s; s++)
352                 ;
353         return (size_t)(s - string);
354 }
355
356
357 int xxxinit(lkmtp, cmd, ver)
358 struct lkm_table *lkmtp;
359 int cmd, ver;
360 {
361         DISPATCH(lkmtp, cmd, ver, iplaction, iplaction, iplaction);
362 }
363 #else   /* __FREEBSD_version >= 220000 */
364 # ifdef IPFILTER_LKM
365 #  include <sys/exec.h>
366
367 #  if (__FreeBSD_version >= 300000)
368 MOD_DEV(if_ipl, LM_DT_CHAR, CDEV_MAJOR, &ipl_cdevsw);
369 #  else
370 MOD_DECL(if_ipl);
371
372
373 static struct lkm_dev _module = {
374         LM_DEV,
375         LKM_VERSION,
376         IPL_VERSION,
377         CDEV_MAJOR,
378         LM_DT_CHAR,
379         { (void *)&ipl_cdevsw }
380 };
381 #  endif
382
383
384 int if_ipl __P((struct lkm_table *, int, int));
385
386
387 int if_ipl(lkmtp, cmd, ver)
388 struct lkm_table *lkmtp;
389 int cmd, ver;
390 {
391 #  if (__FreeBSD_version >= 300000)
392         MOD_DISPATCH(if_ipl, lkmtp, cmd, ver, iplaction, iplaction, iplaction);
393 #  else
394         DISPATCH(lkmtp, cmd, ver, iplaction, iplaction, iplaction);
395 #  endif
396 }
397 # endif /* IPFILTER_LKM */
398 static int      ipl_devsw_installed = 0;
399
400 static void ipl_drvinit __P((void *unused))
401 {
402         dev_t dev;
403 # ifdef DEVFS
404         void **tp = ipf_devfs;
405 # endif
406
407         if (!ipl_devsw_installed ) {
408                 dev = makedev(CDEV_MAJOR, 0);
409                 cdevsw_add(&dev, &ipl_cdevsw, NULL);
410                 ipl_devsw_installed = 1;
411
412 # ifdef DEVFS
413                 tp[IPL_LOGIPF] = devfs_add_devswf(&ipl_cdevsw, IPL_LOGIPF,
414                                                   DV_CHR, 0, 0, 0600, "ipf");
415                 tp[IPL_LOGNAT] = devfs_add_devswf(&ipl_cdevsw, IPL_LOGNAT,
416                                                   DV_CHR, 0, 0, 0600, "ipnat");
417                 tp[IPL_LOGSTATE] = devfs_add_devswf(&ipl_cdevsw, IPL_LOGSTATE,
418                                                     DV_CHR, 0, 0, 0600,
419                                                     "ipstate");
420                 tp[IPL_LOGAUTH] = devfs_add_devswf(&ipl_cdevsw, IPL_LOGAUTH,
421                                                    DV_CHR, 0, 0, 0600,
422                                                    "ipauth");
423 # endif
424         }
425 }
426
427 # if defined(IPFILTER_LKM) || \
428      defined(__FreeBSD_version) && (__FreeBSD_version >= 220000)
429 SYSINIT(ipldev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,ipl_drvinit,NULL)
430 # endif /* IPFILTER_LKM */
431 #endif /* _FreeBSD_version */