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