1 /*	$FreeBSD: stable/9/contrib/ipfilter/mlf_ipl.c 145519 2005-04-25 18:20:15Z darrenr $	*/
2 
3 /*
4  * Copyright (C) 1993-2001 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, &fr_flags, 0, "");
99 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_pass, CTLFLAG_RW, &fr_pass, 0, "");
100 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_active, CTLFLAG_RD, &fr_active, 0, "");
101 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_chksrc, CTLFLAG_RW, &fr_chksrc, 0, "");
102 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_minttl, CTLFLAG_RW, &fr_minttl, 0, "");
103 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpidletimeout, CTLFLAG_RWO,
104 	   &fr_tcpidletimeout, 0, "");
105 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcphalfclosed, CTLFLAG_RWO,
106 	   &fr_tcphalfclosed, 0, "");
107 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpclosewait, CTLFLAG_RWO,
108 	   &fr_tcpclosewait, 0, "");
109 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcplastack, CTLFLAG_RWO,
110 	   &fr_tcplastack, 0, "");
111 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcptimeout, CTLFLAG_RWO,
112 	   &fr_tcptimeout, 0, "");
113 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpclosed, CTLFLAG_RWO,
114 	   &fr_tcpclosed, 0, "");
115 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_udptimeout, CTLFLAG_RWO,
116 	   &fr_udptimeout, 0, "");
117 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_icmptimeout, CTLFLAG_RWO,
118 	   &fr_icmptimeout, 0, "");
119 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_defnatage, CTLFLAG_RWO,
120 	   &fr_defnatage, 0, "");
121 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_ipfrttl, CTLFLAG_RW,
122 	   &fr_ipfrttl, 0, "");
123 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_running, CTLFLAG_RD,
124 	   &fr_running, 0, "");
125 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_statesize, CTLFLAG_RWO,
126 	   &fr_statesize, 0, "");
127 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_statemax, CTLFLAG_RWO,
128 	   &fr_statemax, 0, "");
129 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_authsize, CTLFLAG_RWO,
130 	   &fr_authsize, 0, "");
131 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_authused, CTLFLAG_RD,
132 	   &fr_authused, 0, "");
133 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_defaultauthage, CTLFLAG_RW,
134 	   &fr_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	ipl_major = 0;
145 
146 static struct   cdevsw  ipldevsw =
147 {
148 	iplopen,		/* open */
149 	iplclose,		/* close */
150 	iplread,		/* read */
151 	(void *)nullop,		/* write */
152 	iplioctl,		/* 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, &ipldevsw);
162 
163 extern struct cdevsw cdevsw[];
164 extern int vd_unuseddev __P((void));
165 extern int nchrdev;
166 #else
167 
168 static struct cdevsw ipl_cdevsw = {
169 	iplopen,	iplclose,	iplread,	nowrite, /* 79 */
170 	iplioctl,	nostop,		noreset,	nodevtotty,
171 #if (__FreeBSD_version >= 300000)
172 	seltrue,	nommap,		nostrategy,	"ipl",
173 #else
174 	noselect,	nommap,		nostrategy,	"ipl",
175 #endif
176 	NULL,	-1
177 };
178 #endif
179 
180 static void ipl_drvinit __P((void *));
181 
182 #ifdef ACTUALLY_LKM_NOT_KERNEL
183 static  int     if_ipl_unload __P((struct lkm_table *, int));
184 static  int     if_ipl_load __P((struct lkm_table *, int));
185 static  int     if_ipl_remove __P((void));
186 static  int     ipl_major = CDEV_MAJOR;
187 
188 static int iplaction __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 
iplaction(lkmtp,cmd)194 static int iplaction(lkmtp, cmd)
195 struct lkm_table *lkmtp;
196 int cmd;
197 {
198 #if !defined(__FreeBSD_version) || (__FreeBSD_version < 220000)
199 	int i = ipl_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 == iplopen)
214 				break;
215 		if (i == nchrdev) {
216 			printf("IP Filter: No free cdevsw slots\n");
217 			return ENODEV;
218 		}
219 
220 		ipl_major = i;
221 		args->lkm_offset = i;   /* slot in cdevsw[] */
222 #endif
223 		printf("IP Filter: loaded into slot %d\n", ipl_major);
224 		err = if_ipl_load(lkmtp, cmd);
225 		if (!err)
226 			ipl_drvinit((void *)NULL);
227 		return err;
228 		break;
229 	case LKM_E_UNLOAD :
230 		err = if_ipl_unload(lkmtp, cmd);
231 		if (!err) {
232 			printf("IP Filter: unloaded from slot %d\n",
233 				ipl_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 
if_ipl_remove(void)262 static int if_ipl_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 
if_ipl_unload(lkmtp,cmd)295 static int if_ipl_unload(lkmtp, cmd)
296 struct lkm_table *lkmtp;
297 int cmd;
298 {
299 	int error = 0;
300 
301 	error = ipldetach();
302 	if (!error)
303 		error = if_ipl_remove();
304 	return error;
305 }
306 
307 
if_ipl_load(lkmtp,cmd)308 static int if_ipl_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 = iplattach();
318 	if (error)
319 		return error;
320 	(void) if_ipl_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 = (ipl_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  */
strlen(string)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 
xxxinit(lkmtp,cmd,ver)367 int xxxinit(lkmtp, cmd, ver)
368 struct lkm_table *lkmtp;
369 int cmd, ver;
370 {
371 	DISPATCH(lkmtp, cmd, ver, iplaction, iplaction, iplaction);
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_ipl, LM_DT_CHAR, CDEV_MAJOR, &ipl_cdevsw);
379 #  else
380 MOD_DECL(if_ipl);
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 *)&ipl_cdevsw }
390 };
391 #  endif
392 
393 
394 int if_ipl __P((struct lkm_table *, int, int));
395 
396 
if_ipl(lkmtp,cmd,ver)397 int if_ipl(lkmtp, cmd, ver)
398 struct lkm_table *lkmtp;
399 int cmd, ver;
400 {
401 #  if (__FreeBSD_version >= 300000)
402 	MOD_DISPATCH(if_ipl, lkmtp, cmd, ver, iplaction, iplaction, iplaction);
403 #  else
404 	DISPATCH(lkmtp, cmd, ver, iplaction, iplaction, iplaction);
405 #  endif
406 }
407 # endif /* IPFILTER_LKM */
408 static ipl_devsw_installed = 0;
409 
ipl_drvinit(void * unused)410 static void ipl_drvinit __P((void *unused))
411 {
412 	dev_t dev;
413 # ifdef	DEVFS
414 	void **tp = ipf_devfs;
415 # endif
416 
417 	if (!ipl_devsw_installed ) {
418 		dev = makedev(CDEV_MAJOR, 0);
419 		cdevsw_add(&dev, &ipl_cdevsw, NULL);
420 		ipl_devsw_installed = 1;
421 
422 # ifdef	DEVFS
423 		tp[IPL_LOGIPF] = devfs_add_devswf(&ipl_cdevsw, IPL_LOGIPF,
424 						  DV_CHR, 0, 0, 0600, "ipf");
425 		tp[IPL_LOGNAT] = devfs_add_devswf(&ipl_cdevsw, IPL_LOGNAT,
426 						  DV_CHR, 0, 0, 0600, "ipnat");
427 		tp[IPL_LOGSTATE] = devfs_add_devswf(&ipl_cdevsw, IPL_LOGSTATE,
428 						    DV_CHR, 0, 0, 0600,
429 						    "ipstate");
430 		tp[IPL_LOGAUTH] = devfs_add_devswf(&ipl_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) && (fr_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(ipldev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,ipl_drvinit,NULL)
468 # endif /* IPFILTER_LKM */
469 #endif /* _FreeBSD_version */
470