mlf_ipl.c revision 60841
185518Sjake/*
285518Sjake * Copyright (C) 1993-2000 by Darren Reed.
385518Sjake *
485518Sjake * Redistribution and use in source and binary forms are permitted
585518Sjake * provided that this notice is preserved and due credit is given
685518Sjake * to the original author and the contributors.
785518Sjake */
885518Sjake/*
985518Sjake * 29/12/94 Added code from Marc Huber <huber@fzi.de> to allow it to allocate
1085518Sjake * its own major char number! Way cool patch!
1185518Sjake */
1285518Sjake
1385518Sjake
1485518Sjake#include <sys/param.h>
1585518Sjake
1685518Sjake#if defined(__FreeBSD__) && (__FreeBSD__ > 1)
1785518Sjake# ifdef	IPFILTER_LKM
1885518Sjake#  include <osreldate.h>
1985518Sjake#  define	ACTUALLY_LKM_NOT_KERNEL
2085518Sjake# else
2185518Sjake#  include <sys/osreldate.h>
2285518Sjake# endif
2385518Sjake#endif
2485518Sjake#include <sys/systm.h>
2585518Sjake#if defined(__FreeBSD_version) && (__FreeBSD_version >= 220000)
2685518Sjake# ifndef ACTUALLY_LKM_NOT_KERNEL
2785518Sjake#  include "opt_devfs.h"
2885518Sjake# endif
2985518Sjake# include <sys/conf.h>
3085518Sjake# include <sys/kernel.h>
3185518Sjake# ifdef DEVFS
3285518Sjake#  include <sys/devfsext.h>
3385518Sjake# endif /*DEVFS*/
3485518Sjake#endif
3585518Sjake#include <sys/conf.h>
3685518Sjake#include <sys/file.h>
3799018Sobrien#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
3885518Sjake# include <sys/lock.h>
3985518Sjake#endif
4085518Sjake#include <sys/stat.h>
4185518Sjake#include <sys/proc.h>
4285518Sjake#include <sys/uio.h>
4399018Sobrien#include <sys/kernel.h>
4485518Sjake#include <sys/vnode.h>
4586534Sjake#include <sys/namei.h>
4686534Sjake#include <sys/malloc.h>
4788609Sjake#include <sys/mount.h>
4888609Sjake#include <sys/exec.h>
4988609Sjake#include <sys/mbuf.h>
5085518Sjake#if	BSD >= 199506
5185518Sjake# include <sys/sysctl.h>
5285518Sjake#endif
5385518Sjake#if (__FreeBSD_version >= 300000)
5485518Sjake# include <sys/socket.h>
5585518Sjake#endif
5685518Sjake#if (__FreeBSD_version >= 199511)
57108738Stmm#include <net/if.h>
5885518Sjake#include <netinet/in_systm.h>
5985518Sjake#include <netinet/in.h>
6085518Sjake#include <netinet/ip.h>
6185518Sjake#include <net/route.h>
6288609Sjake#include <netinet/ip_var.h>
6388609Sjake#include <netinet/tcp.h>
6485518Sjake#include <netinet/tcpip.h>
6586534Sjake#endif
6686534Sjake#if (__FreeBSD__ > 1)
6785518Sjake# include <sys/sysent.h>
68108738Stmm#endif
69108738Stmm#include <sys/lkm.h>
70108738Stmm#include "netinet/ipl.h"
71108738Stmm#include "netinet/ip_compat.h"
72108738Stmm#include "netinet/ip_fil.h"
73108738Stmm#include "netinet/ip_state.h"
74108738Stmm#include "netinet/ip_nat.h"
75108738Stmm#include "netinet/ip_auth.h"
76108738Stmm#include "netinet/ip_frag.h"
77108738Stmm#include "netinet/ip_proxy.h"
78108738Stmm
79108738Stmm
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_tcpclosewait, CTLFLAG_RW,
99	   &fr_tcpclosewait, 0, "");
100SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcplastack, CTLFLAG_RW,
101	   &fr_tcplastack, 0, "");
102SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcptimeout, CTLFLAG_RW,
103	   &fr_tcptimeout, 0, "");
104SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcpclosed, CTLFLAG_RW,
105	   &fr_tcpclosed, 0, "");
106SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_udptimeout, CTLFLAG_RW,
107	   &fr_udptimeout, 0, "");
108SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_icmptimeout, CTLFLAG_RW,
109	   &fr_icmptimeout, 0, "");
110SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_defnatage, CTLFLAG_RW,
111	   &fr_defnatage, 0, "");
112SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_ipfrttl, CTLFLAG_RW,
113	   &fr_ipfrttl, 0, "");
114SYSCTL_INT(_net_inet_ipf, OID_AUTO, ipl_unreach, CTLFLAG_RW,
115	   &ipl_unreach, 0, "");
116SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_running, CTLFLAG_RD,
117	   &fr_running, 0, "");
118SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_authsize, CTLFLAG_RD,
119	   &fr_authsize, 0, "");
120SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_authused, CTLFLAG_RD,
121	   &fr_authused, 0, "");
122SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_defaultauthage, CTLFLAG_RW,
123	   &fr_defaultauthage, 0, "");
124SYSCTL_INT(_net_inet_ipf, OID_AUTO, ippr_ftp_pasvonly, CTLFLAG_RW,
125	   &ippr_ftp_pasvonly, 0, "");
126#endif
127
128#ifdef DEVFS
129static void *ipf_devfs[IPL_LOGMAX + 1];
130#endif
131
132#if !defined(__FreeBSD_version) || (__FreeBSD_version < 220000)
133int	ipl_major = 0;
134
135static struct   cdevsw  ipldevsw =
136{
137        iplopen,                /* open */
138        iplclose,               /* close */
139        iplread,                /* read */
140        (void *)nullop,         /* write */
141        iplioctl,               /* ioctl */
142        (void *)nullop,         /* stop */
143        (void *)nullop,         /* reset */
144        (void *)NULL,           /* tty */
145        (void *)nullop,         /* select */
146        (void *)nullop,         /* mmap */
147        NULL                    /* strategy */
148};
149
150MOD_DEV(IPL_VERSION, LM_DT_CHAR, -1, &ipldevsw);
151
152extern struct cdevsw cdevsw[];
153extern int vd_unuseddev __P((void));
154extern int nchrdev;
155#else
156
157static struct cdevsw ipl_cdevsw = {
158	iplopen,	iplclose,	iplread,	nowrite, /* 79 */
159	iplioctl,	nostop,		noreset,	nodevtotty,
160#if (__FreeBSD_version >= 300000)
161	seltrue,	nommap,		nostrategy,	"ipl",
162#else
163	noselect,	nommap,		nostrategy,	"ipl",
164#endif
165	NULL,	-1
166};
167#endif
168
169static void ipl_drvinit __P((void *));
170
171#ifdef ACTUALLY_LKM_NOT_KERNEL
172static  int     if_ipl_unload __P((struct lkm_table *, int));
173static  int     if_ipl_load __P((struct lkm_table *, int));
174static  int     if_ipl_remove __P((void));
175static  int     ipl_major = CDEV_MAJOR;
176
177static int iplaction __P((struct lkm_table *, int));
178static char *ipf_devfiles[] = { IPL_NAME, IPL_NAT, IPL_STATE, IPL_AUTH, NULL };
179
180extern	int	lkmenodev __P((void));
181
182static int iplaction(lkmtp, cmd)
183struct lkm_table *lkmtp;
184int cmd;
185{
186#if !defined(__FreeBSD_version) || (__FreeBSD_version < 220000)
187	int i = ipl_major;
188	struct lkm_dev *args = lkmtp->private.lkm_dev;
189#endif
190	int err = 0;
191
192	switch (cmd)
193	{
194	case LKM_E_LOAD :
195		if (lkmexists(lkmtp))
196			return EEXIST;
197
198#if !defined(__FreeBSD_version) || (__FreeBSD_version < 220000)
199		for (i = 0; i < nchrdev; i++)
200			if (cdevsw[i].d_open == lkmenodev ||
201			    cdevsw[i].d_open == iplopen)
202				break;
203		if (i == nchrdev) {
204			printf("IP Filter: No free cdevsw slots\n");
205			return ENODEV;
206		}
207
208		ipl_major = i;
209		args->lkm_offset = i;   /* slot in cdevsw[] */
210#endif
211		printf("IP Filter: loaded into slot %d\n", ipl_major);
212		err = if_ipl_load(lkmtp, cmd);
213		if (!err)
214			ipl_drvinit((void *)NULL);
215		return err;
216		break;
217	case LKM_E_UNLOAD :
218		err = if_ipl_unload(lkmtp, cmd);
219		if (!err) {
220			printf("IP Filter: unloaded from slot %d\n",
221				ipl_major);
222#ifdef	DEVFS
223			if (ipf_devfs[IPL_LOGIPF])
224				devfs_remove_dev(ipf_devfs[IPL_LOGIPF]);
225			if (ipf_devfs[IPL_LOGNAT])
226				devfs_remove_dev(ipf_devfs[IPL_LOGNAT]);
227			if (ipf_devfs[IPL_LOGSTATE])
228				devfs_remove_dev(ipf_devfs[IPL_LOGSTATE]);
229			if (ipf_devfs[IPL_LOGAUTH])
230				devfs_remove_dev(ipf_devfs[IPL_LOGAUTH]);
231#endif
232		}
233		return err;
234	case LKM_E_STAT :
235		break;
236	default:
237		err = EIO;
238		break;
239	}
240	return 0;
241}
242
243
244static int if_ipl_remove __P((void))
245{
246	char *name;
247	struct nameidata nd;
248	int error, i;
249
250	for (i = 0; (name = ipf_devfiles[i]); i++) {
251		NDINIT(&nd, DELETE, LOCKPARENT, UIO_SYSSPACE, name, curproc);
252		if ((error = namei(&nd)))
253			return (error);
254		VOP_LEASE(nd.ni_vp, curproc, curproc->p_ucred, LEASE_WRITE);
255#if (__FreeBSD_version >= 300000)
256		VOP_LOCK(nd.ni_vp, LK_RETRY | LK_EXCLUSIVE, curproc);
257		VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE);
258		(void) VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
259
260		if (nd.ni_dvp == nd.ni_vp)
261			vrele(nd.ni_dvp);
262		else
263			vput(nd.ni_dvp);
264		if (nd.ni_vp != NULLVP)
265			vput(nd.ni_vp);
266#else
267		VOP_LOCK(nd.ni_vp);
268		VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE);
269		(void) VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
270#endif
271	}
272
273	return 0;
274}
275
276
277static int if_ipl_unload(lkmtp, cmd)
278struct lkm_table *lkmtp;
279int cmd;
280{
281	int error = 0;
282
283	error = ipldetach();
284	if (!error)
285		error = if_ipl_remove();
286	return error;
287}
288
289
290static int if_ipl_load(lkmtp, cmd)
291struct lkm_table *lkmtp;
292int cmd;
293{
294	struct nameidata nd;
295	struct vattr vattr;
296	int error = 0, fmode = S_IFCHR|0600, i;
297	char *name;
298
299	error = iplattach();
300	if (error)
301		return error;
302	(void) if_ipl_remove();
303
304	for (i = 0; (name = ipf_devfiles[i]); i++) {
305		NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE, name, curproc);
306		if ((error = namei(&nd)))
307			return error;
308		if (nd.ni_vp != NULL) {
309			VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
310			if (nd.ni_dvp == nd.ni_vp)
311				vrele(nd.ni_dvp);
312			else
313				vput(nd.ni_dvp);
314			vrele(nd.ni_vp);
315			return (EEXIST);
316		}
317		VATTR_NULL(&vattr);
318		vattr.va_type = VCHR;
319		vattr.va_mode = (fmode & 07777);
320		vattr.va_rdev = (ipl_major << 8) | i;
321		VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE);
322		error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
323#if (__FreeBSD_version >= 300000)
324                vput(nd.ni_dvp);
325#endif
326		if (error)
327			return error;
328	}
329	return 0;
330}
331
332#endif  /* actually LKM */
333
334#if defined(__FreeBSD_version) && (__FreeBSD_version < 220000)
335/*
336 * strlen isn't present in 2.1.* kernels.
337 */
338size_t strlen(string)
339char *string;
340{
341        register char *s;
342
343        for (s = string; *s; s++)
344		;
345        return (size_t)(s - string);
346}
347
348
349int xxxinit(lkmtp, cmd, ver)
350struct lkm_table *lkmtp;
351int cmd, ver;
352{
353	DISPATCH(lkmtp, cmd, ver, iplaction, iplaction, iplaction);
354}
355#else	/* __FREEBSD_version >= 220000 */
356# ifdef	IPFILTER_LKM
357#  include <sys/exec.h>
358
359#  if (__FreeBSD_version >= 300000)
360MOD_DEV(if_ipl, LM_DT_CHAR, CDEV_MAJOR, &ipl_cdevsw);
361#  else
362MOD_DECL(if_ipl);
363
364
365static struct lkm_dev _module = {
366	LM_DEV,
367	LKM_VERSION,
368	IPL_VERSION,
369	CDEV_MAJOR,
370	LM_DT_CHAR,
371	{ (void *)&ipl_cdevsw }
372};
373#  endif
374
375
376int if_ipl __P((struct lkm_table *, int, int));
377
378
379int if_ipl(lkmtp, cmd, ver)
380struct lkm_table *lkmtp;
381int cmd, ver;
382{
383#  if (__FreeBSD_version >= 300000)
384	MOD_DISPATCH(if_ipl, lkmtp, cmd, ver, iplaction, iplaction, iplaction);
385#  else
386	DISPATCH(lkmtp, cmd, ver, iplaction, iplaction, iplaction);
387#  endif
388}
389# endif /* IPFILTER_LKM */
390static ipl_devsw_installed = 0;
391
392static void ipl_drvinit __P((void *unused))
393{
394	dev_t dev;
395# ifdef	DEVFS
396	void **tp = ipf_devfs;
397# endif
398
399	if (!ipl_devsw_installed ) {
400		dev = makedev(CDEV_MAJOR, 0);
401		cdevsw_add(&dev, &ipl_cdevsw, NULL);
402		ipl_devsw_installed = 1;
403
404# ifdef	DEVFS
405		tp[IPL_LOGIPF] = devfs_add_devswf(&ipl_cdevsw, IPL_LOGIPF,
406						  DV_CHR, 0, 0, 0600, "ipf");
407		tp[IPL_LOGNAT] = devfs_add_devswf(&ipl_cdevsw, IPL_LOGNAT,
408						  DV_CHR, 0, 0, 0600, "ipnat");
409		tp[IPL_LOGSTATE] = devfs_add_devswf(&ipl_cdevsw, IPL_LOGSTATE,
410					            DV_CHR, 0, 0, 0600,
411						    "ipstate");
412		tp[IPL_LOGAUTH] = devfs_add_devswf(&ipl_cdevsw, IPL_LOGAUTH,
413					           DV_CHR, 0, 0, 0600,
414						   "ipauth");
415# endif
416	}
417}
418
419# if defined(IPFILTER_LKM) || \
420     defined(__FreeBSD_version) && (__FreeBSD_version >= 220000)
421SYSINIT(ipldev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,ipl_drvinit,NULL)
422# endif /* IPFILTER_LKM */
423#endif /* _FreeBSD_version */
424