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