mlfk_ipl.c revision 259128
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
10#include <sys/param.h>
11#include <sys/systm.h>
12#include <sys/kernel.h>
13#include <sys/module.h>
14#include <sys/conf.h>
15#include <sys/socket.h>
16#include <sys/sysctl.h>
17#include <sys/select.h>
18#if __FreeBSD_version >= 500000
19# include <sys/selinfo.h>
20#endif
21#include <net/if.h>
22#include <netinet/in_systm.h>
23#include <netinet/in.h>
24
25
26#include "netinet/ipl.h"
27#include "netinet/ip_compat.h"
28#include "netinet/ip_fil.h"
29#include "netinet/ip_state.h"
30#include "netinet/ip_nat.h"
31#include "netinet/ip_auth.h"
32#include "netinet/ip_frag.h"
33#include "netinet/ip_sync.h"
34
35extern ipf_main_softc_t ipfmain;
36
37#if __FreeBSD_version >= 502116
38static struct cdev *ipf_devs[IPL_LOGSIZE];
39#else
40static dev_t ipf_devs[IPL_LOGSIZE];
41#endif
42
43#if 0
44static int sysctl_ipf_int ( SYSCTL_HANDLER_ARGS );
45#endif
46static int ipf_modload(void);
47static int ipf_modunload(void);
48
49#if (__FreeBSD_version >= 500024)
50# if (__FreeBSD_version >= 502116)
51static	int	ipfopen __P((struct cdev*, int, int, struct thread *));
52static	int	ipfclose __P((struct cdev*, int, int, struct thread *));
53# else
54static	int	ipfopen __P((dev_t, int, int, struct thread *));
55static	int	ipfclose __P((dev_t, int, int, struct thread *));
56# endif /* __FreeBSD_version >= 502116 */
57#else
58static	int	ipfopen __P((dev_t, int, int, struct proc *));
59static	int	ipfclose __P((dev_t, int, int, struct proc *));
60#endif
61#if (__FreeBSD_version >= 502116)
62static	int	ipfread __P((struct cdev*, struct uio *, int));
63static	int	ipfwrite __P((struct cdev*, struct uio *, int));
64#else
65static	int	ipfread __P((dev_t, struct uio *, int));
66static	int	ipfwrite __P((dev_t, struct uio *, int));
67#endif /* __FreeBSD_version >= 502116 */
68
69
70
71SYSCTL_DECL(_net_inet);
72#define SYSCTL_IPF(parent, nbr, name, access, ptr, val, descr) \
73	SYSCTL_OID(parent, nbr, name, CTLTYPE_INT|access, \
74		   ptr, val, sysctl_ipf_int, "I", descr);
75#define	CTLFLAG_OFF	0x00800000	/* IPFilter must be disabled */
76#define	CTLFLAG_RWO	(CTLFLAG_RW|CTLFLAG_OFF)
77SYSCTL_NODE(_net_inet, OID_AUTO, ipf, CTLFLAG_RW, 0, "IPF");
78#if 0
79SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_flags, CTLFLAG_RW, &ipf_flags, 0, "");
80SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_pass, CTLFLAG_RW, &ipf_pass, 0, "");
81SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_active, CTLFLAG_RD, &ipf_active, 0, "");
82SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpidletimeout, CTLFLAG_RWO,
83	   &ipf_tcpidletimeout, 0, "");
84SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcphalfclosed, CTLFLAG_RWO,
85	   &ipf_tcphalfclosed, 0, "");
86SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpclosewait, CTLFLAG_RWO,
87	   &ipf_tcpclosewait, 0, "");
88SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcplastack, CTLFLAG_RWO,
89	   &ipf_tcplastack, 0, "");
90SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcptimeout, CTLFLAG_RWO,
91	   &ipf_tcptimeout, 0, "");
92SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpclosed, CTLFLAG_RWO,
93	   &ipf_tcpclosed, 0, "");
94SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_udptimeout, CTLFLAG_RWO,
95	   &ipf_udptimeout, 0, "");
96SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_udpacktimeout, CTLFLAG_RWO,
97	   &ipf_udpacktimeout, 0, "");
98SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_icmptimeout, CTLFLAG_RWO,
99	   &ipf_icmptimeout, 0, "");
100SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_defnatage, CTLFLAG_RWO,
101	   &ipf_nat_defage, 0, "");
102SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_ipfrttl, CTLFLAG_RW,
103	   &ipf_ipfrttl, 0, "");
104SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_running, CTLFLAG_RD,
105	   &ipf_running, 0, "");
106SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_statesize, CTLFLAG_RWO,
107	   &ipf_state_size, 0, "");
108SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_statemax, CTLFLAG_RWO,
109	   &ipf_state_max, 0, "");
110SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_nattable_sz, CTLFLAG_RWO,
111	   &ipf_nat_table_sz, 0, "");
112SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_natrules_sz, CTLFLAG_RWO,
113	   &ipf_nat_maprules_sz, 0, "");
114SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_rdrrules_sz, CTLFLAG_RWO,
115	   &ipf_nat_rdrrules_sz, 0, "");
116SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_hostmap_sz, CTLFLAG_RWO,
117	   &ipf_nat_hostmap_sz, 0, "");
118SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_authsize, CTLFLAG_RWO,
119	   &ipf_auth_size, 0, "");
120SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_authused, CTLFLAG_RD,
121	   &ipf_auth_used, 0, "");
122SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_defaultauthage, CTLFLAG_RW,
123	   &ipf_auth_defaultage, 0, "");
124SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_chksrc, CTLFLAG_RW, &ipf_chksrc, 0, "");
125SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_minttl, CTLFLAG_RW, &ipf_minttl, 0, "");
126#endif
127
128#define CDEV_MAJOR 79
129#include <sys/poll.h>
130#if __FreeBSD_version >= 500043
131# include <sys/select.h>
132static int ipfpoll(struct cdev *dev, int events, struct thread *td);
133
134static struct cdevsw ipf_cdevsw = {
135#if __FreeBSD_version >= 502103
136	.d_version =	D_VERSION,
137	.d_flags =	0,	/* D_NEEDGIANT - Should be SMP safe */
138#endif
139	.d_open =	ipfopen,
140	.d_close =	ipfclose,
141	.d_read =	ipfread,
142	.d_write =	ipfwrite,
143	.d_ioctl =	ipfioctl,
144	.d_poll =	ipfpoll,
145	.d_name =	"ipf",
146#if __FreeBSD_version < 600000
147	.d_maj =	CDEV_MAJOR,
148#endif
149};
150#else
151static int ipfpoll(dev_t dev, int events, struct proc *td);
152
153static struct cdevsw ipf_cdevsw = {
154	/* open */	ipfopen,
155	/* close */	ipfclose,
156	/* read */	ipfread,
157	/* write */	ipfwrite,
158	/* ioctl */	ipfioctl,
159	/* poll */	ipfpoll,
160	/* mmap */	nommap,
161	/* strategy */	nostrategy,
162	/* name */	"ipf",
163	/* maj */	CDEV_MAJOR,
164	/* dump */	nodump,
165	/* psize */	nopsize,
166	/* flags */	0,
167# if (__FreeBSD_version < 500043)
168	/* bmaj */	-1,
169# endif
170# if (__FreeBSD_version >= 430000)
171	/* kqfilter */	NULL
172# endif
173};
174#endif
175
176static char *ipf_devfiles[] = {	IPL_NAME, IPNAT_NAME, IPSTATE_NAME, IPAUTH_NAME,
177				IPSYNC_NAME, IPSCAN_NAME, IPLOOKUP_NAME, NULL };
178
179
180static int
181ipfilter_modevent(module_t mod, int type, void *unused)
182{
183	int error = 0;
184
185	switch (type)
186	{
187	case MOD_LOAD :
188		error = ipf_modload();
189		break;
190
191	case MOD_UNLOAD :
192		error = ipf_modunload();
193		break;
194	default:
195		error = EINVAL;
196		break;
197	}
198	return error;
199}
200
201
202static int
203ipf_modload()
204{
205	char *defpass, *c, *str;
206	int i, j, error;
207
208	if (ipf_load_all() != 0)
209		return EIO;
210
211	if (ipf_create_all(&ipfmain) == NULL)
212		return EIO;
213
214	error = ipfattach(&ipfmain);
215	if (error)
216		return error;
217
218	for (i = 0; i < IPL_LOGSIZE; i++)
219		ipf_devs[i] = NULL;
220
221	for (i = 0; (str = ipf_devfiles[i]); i++) {
222		c = NULL;
223		for(j = strlen(str); j > 0; j--)
224			if (str[j] == '/') {
225				c = str + j + 1;
226				break;
227			}
228		if (!c)
229			c = str;
230		ipf_devs[i] = make_dev(&ipf_cdevsw, i, 0, 0, 0600, c);
231	}
232
233	error = ipf_pfil_hook();
234	if (error != 0)
235		return error;
236	ipf_event_reg();
237
238	if (FR_ISPASS(ipfmain.ipf_pass))
239		defpass = "pass";
240	else if (FR_ISBLOCK(ipfmain.ipf_pass))
241		defpass = "block";
242	else
243		defpass = "no-match -> block";
244
245	printf("%s initialized.  Default = %s all, Logging = %s%s\n",
246		ipfilter_version, defpass,
247#ifdef IPFILTER_LOG
248		"enabled",
249#else
250		"disabled",
251#endif
252#ifdef IPFILTER_COMPILED
253		" (COMPILED)"
254#else
255		""
256#endif
257		);
258	return 0;
259}
260
261
262static int
263ipf_modunload()
264{
265	int error, i;
266
267	if (ipfmain.ipf_refcnt)
268		return EBUSY;
269
270	error = ipf_pfil_unhook();
271	if (error != 0)
272		return error;
273
274	if (ipfmain.ipf_running >= 0) {
275		error = ipfdetach(&ipfmain);
276		if (error != 0)
277			return error;
278
279		ipf_destroy_all(&ipfmain);
280		ipf_unload_all();
281	} else
282		error = 0;
283
284	ipfmain.ipf_running = -2;
285
286	for (i = 0; ipf_devfiles[i]; i++) {
287		if (ipf_devs[i] != NULL)
288			destroy_dev(ipf_devs[i]);
289	}
290
291	printf("%s unloaded\n", ipfilter_version);
292
293	return error;
294}
295
296
297static moduledata_t ipfiltermod = {
298	"ipfilter",
299	ipfilter_modevent,
300	0
301};
302
303
304DECLARE_MODULE(ipfilter, ipfiltermod, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY);
305#ifdef	MODULE_VERSION
306MODULE_VERSION(ipfilter, 1);
307#endif
308
309
310#if 0
311#ifdef SYSCTL_IPF
312int
313sysctl_ipf_int ( SYSCTL_HANDLER_ARGS )
314{
315	int error = 0;
316
317	if (arg1)
318		error = SYSCTL_OUT(req, arg1, sizeof(int));
319	else
320		error = SYSCTL_OUT(req, &arg2, sizeof(int));
321
322	if (error || !req->newptr)
323		return (error);
324
325	if (!arg1)
326		error = EPERM;
327	else {
328		if ((oidp->oid_kind & CTLFLAG_OFF) && (ipfmain.ipf_running > 0))
329			error = EBUSY;
330		else
331			error = SYSCTL_IN(req, arg1, sizeof(int));
332	}
333	return (error);
334}
335#endif
336#endif
337
338
339static int
340#if __FreeBSD_version >= 500043
341ipfpoll(struct cdev *dev, int events, struct thread *td)
342#else
343ipfpoll(dev_t dev, int events, struct proc *td)
344#endif
345{
346	u_int unit = GET_MINOR(dev);
347	int revents;
348
349	if (unit < 0 || unit > IPL_LOGMAX)
350		return 0;
351
352	revents = 0;
353
354	switch (unit)
355	{
356	case IPL_LOGIPF :
357	case IPL_LOGNAT :
358	case IPL_LOGSTATE :
359#ifdef IPFILTER_LOG
360		if ((events & (POLLIN | POLLRDNORM)) && ipf_log_canread(&ipfmain, unit))
361			revents |= events & (POLLIN | POLLRDNORM);
362#endif
363		break;
364	case IPL_LOGAUTH :
365		if ((events & (POLLIN | POLLRDNORM)) && ipf_auth_waiting(&ipfmain))
366			revents |= events & (POLLIN | POLLRDNORM);
367		break;
368	case IPL_LOGSYNC :
369		if ((events & (POLLIN | POLLRDNORM)) && ipf_sync_canread(&ipfmain))
370			revents |= events & (POLLIN | POLLRDNORM);
371		if ((events & (POLLOUT | POLLWRNORM)) && ipf_sync_canwrite(&ipfmain))
372			revents |= events & (POLLOUT | POLLWRNORM);
373		break;
374	case IPL_LOGSCAN :
375	case IPL_LOGLOOKUP :
376	default :
377		break;
378	}
379
380	if ((revents == 0) && ((events & (POLLIN|POLLRDNORM)) != 0))
381		selrecord(td, &ipfmain.ipf_selwait[unit]);
382
383	return revents;
384}
385
386
387/*
388 * routines below for saving IP headers to buffer
389 */
390static int ipfopen(dev, flags
391#if ((BSD >= 199506) || (__FreeBSD_version >= 220000))
392, devtype, p)
393	int devtype;
394# if (__FreeBSD_version >= 500024)
395	struct thread *p;
396# else
397	struct proc *p;
398# endif /* __FreeBSD_version >= 500024 */
399#else
400)
401#endif
402#if (__FreeBSD_version >= 502116)
403	struct cdev *dev;
404#else
405	dev_t dev;
406#endif
407	int flags;
408{
409	u_int unit = GET_MINOR(dev);
410	int error;
411
412	if (IPL_LOGMAX < unit)
413		error = ENXIO;
414	else {
415		switch (unit)
416		{
417		case IPL_LOGIPF :
418		case IPL_LOGNAT :
419		case IPL_LOGSTATE :
420		case IPL_LOGAUTH :
421		case IPL_LOGLOOKUP :
422		case IPL_LOGSYNC :
423#ifdef IPFILTER_SCAN
424		case IPL_LOGSCAN :
425#endif
426			error = 0;
427			break;
428		default :
429			error = ENXIO;
430			break;
431		}
432	}
433	return error;
434}
435
436
437static int ipfclose(dev, flags
438#if ((BSD >= 199506) || (__FreeBSD_version >= 220000))
439, devtype, p)
440	int devtype;
441# if (__FreeBSD_version >= 500024)
442	struct thread *p;
443# else
444	struct proc *p;
445# endif /* __FreeBSD_version >= 500024 */
446#else
447)
448#endif
449#if (__FreeBSD_version >= 502116)
450	struct cdev *dev;
451#else
452	dev_t dev;
453#endif
454	int flags;
455{
456	u_int	unit = GET_MINOR(dev);
457
458	if (IPL_LOGMAX < unit)
459		unit = ENXIO;
460	else
461		unit = 0;
462	return unit;
463}
464
465/*
466 * ipfread/ipflog
467 * both of these must operate with at least splnet() lest they be
468 * called during packet processing and cause an inconsistancy to appear in
469 * the filter lists.
470 */
471#if (BSD >= 199306)
472static int ipfread(dev, uio, ioflag)
473	int ioflag;
474#else
475static int ipfread(dev, uio)
476#endif
477#if (__FreeBSD_version >= 502116)
478	struct cdev *dev;
479#else
480	dev_t dev;
481#endif
482	struct uio *uio;
483{
484	u_int	unit = GET_MINOR(dev);
485
486	if (unit < 0)
487		return ENXIO;
488
489	if (ipfmain.ipf_running < 1)
490		return EIO;
491
492	if (unit == IPL_LOGSYNC)
493		return ipf_sync_read(&ipfmain, uio);
494
495#ifdef IPFILTER_LOG
496	return ipf_log_read(&ipfmain, unit, uio);
497#else
498	return ENXIO;
499#endif
500}
501
502
503/*
504 * ipfwrite
505 * both of these must operate with at least splnet() lest they be
506 * called during packet processing and cause an inconsistancy to appear in
507 * the filter lists.
508 */
509#if (BSD >= 199306)
510static int ipfwrite(dev, uio, ioflag)
511	int ioflag;
512#else
513static int ipfwrite(dev, uio)
514#endif
515#if (__FreeBSD_version >= 502116)
516	struct cdev *dev;
517#else
518	dev_t dev;
519#endif
520	struct uio *uio;
521{
522
523	if (ipfmain.ipf_running < 1)
524		return EIO;
525
526	if (GET_MINOR(dev) == IPL_LOGSYNC)
527		return ipf_sync_write(&ipfmain, uio);
528	return ENXIO;
529}
530