1/*	$FreeBSD$	*/
2
3/*
4 * Copyright (C) 2000 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
36#if __FreeBSD_version >= 502116
37static struct cdev *ipf_devs[IPL_LOGSIZE];
38#else
39static dev_t ipf_devs[IPL_LOGSIZE];
40#endif
41
42static int sysctl_ipf_int ( SYSCTL_HANDLER_ARGS );
43static int ipf_modload(void);
44static int ipf_modunload(void);
45
46SYSCTL_DECL(_net_inet);
47#define SYSCTL_IPF(parent, nbr, name, access, ptr, val, descr) \
48	SYSCTL_OID(parent, nbr, name, CTLTYPE_INT|access, \
49		   ptr, val, sysctl_ipf_int, "I", descr);
50#define	CTLFLAG_OFF	0x00800000	/* IPFilter must be disabled */
51#define	CTLFLAG_RWO	(CTLFLAG_RW|CTLFLAG_OFF)
52SYSCTL_NODE(_net_inet, OID_AUTO, ipf, CTLFLAG_RW, 0, "IPF");
53SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_flags, CTLFLAG_RW, &fr_flags, 0, "");
54SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_pass, CTLFLAG_RW, &fr_pass, 0, "");
55SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_active, CTLFLAG_RD, &fr_active, 0, "");
56SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpidletimeout, CTLFLAG_RWO,
57	   &fr_tcpidletimeout, 0, "");
58SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcphalfclosed, CTLFLAG_RWO,
59	   &fr_tcphalfclosed, 0, "");
60SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpclosewait, CTLFLAG_RWO,
61	   &fr_tcpclosewait, 0, "");
62SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcplastack, CTLFLAG_RWO,
63	   &fr_tcplastack, 0, "");
64SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcptimeout, CTLFLAG_RWO,
65	   &fr_tcptimeout, 0, "");
66SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpclosed, CTLFLAG_RWO,
67	   &fr_tcpclosed, 0, "");
68SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_udptimeout, CTLFLAG_RWO,
69	   &fr_udptimeout, 0, "");
70SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_udpacktimeout, CTLFLAG_RWO,
71	   &fr_udpacktimeout, 0, "");
72SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_icmptimeout, CTLFLAG_RWO,
73	   &fr_icmptimeout, 0, "");
74SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_defnatage, CTLFLAG_RWO,
75	   &fr_defnatage, 0, "");
76SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_ipfrttl, CTLFLAG_RW,
77	   &fr_ipfrttl, 0, "");
78SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_running, CTLFLAG_RD,
79	   &fr_running, 0, "");
80SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_statesize, CTLFLAG_RWO,
81	   &fr_statesize, 0, "");
82SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_statemax, CTLFLAG_RWO,
83	   &fr_statemax, 0, "");
84SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_nattable_sz, CTLFLAG_RWO,
85	   &ipf_nattable_sz, 0, "");
86SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_natrules_sz, CTLFLAG_RWO,
87	   &ipf_natrules_sz, 0, "");
88SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_rdrrules_sz, CTLFLAG_RWO,
89	   &ipf_rdrrules_sz, 0, "");
90SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_hostmap_sz, CTLFLAG_RWO,
91	   &ipf_hostmap_sz, 0, "");
92SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_authsize, CTLFLAG_RWO,
93	   &fr_authsize, 0, "");
94SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_authused, CTLFLAG_RD,
95	   &fr_authused, 0, "");
96SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_defaultauthage, CTLFLAG_RW,
97	   &fr_defaultauthage, 0, "");
98SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_chksrc, CTLFLAG_RW, &fr_chksrc, 0, "");
99SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_minttl, CTLFLAG_RW, &fr_minttl, 0, "");
100
101#define CDEV_MAJOR 79
102#include <sys/poll.h>
103#if __FreeBSD_version >= 500043
104# include <sys/select.h>
105static int iplpoll(struct cdev *dev, int events, struct thread *td);
106
107static struct cdevsw ipl_cdevsw = {
108# if __FreeBSD_version >= 502103
109	.d_version =	D_VERSION,
110	.d_flags =	0,	/* D_NEEDGIANT - Should be SMP safe */
111# endif
112	.d_open =	iplopen,
113	.d_close =	iplclose,
114	.d_read =	iplread,
115	.d_write =	iplwrite,
116	.d_ioctl =	iplioctl,
117	.d_name =	"ipl",
118# if __FreeBSD_version >= 500043
119	.d_poll =	iplpoll,
120# endif
121# if __FreeBSD_version < 600000
122	.d_maj =	CDEV_MAJOR,
123# endif
124};
125#else
126static int iplpoll(dev_t dev, int events, struct proc *p);
127
128static struct cdevsw ipl_cdevsw = {
129	/* open */	iplopen,
130	/* close */	iplclose,
131	/* read */	iplread,
132	/* write */	iplwrite,
133	/* ioctl */	iplioctl,
134	/* poll */	iplpoll,
135	/* mmap */	nommap,
136	/* strategy */	nostrategy,
137	/* name */	"ipl",
138	/* maj */	CDEV_MAJOR,
139	/* dump */	nodump,
140	/* psize */	nopsize,
141	/* flags */	0,
142# if (__FreeBSD_version < 500043)
143	/* bmaj */	-1,
144# endif
145# if (__FreeBSD_version > 430000)
146	/* kqfilter */	NULL
147# endif
148};
149#endif
150
151static char *ipf_devfiles[] = {	IPL_NAME, IPNAT_NAME, IPSTATE_NAME, IPAUTH_NAME,
152				IPSYNC_NAME, IPSCAN_NAME, IPLOOKUP_NAME, NULL };
153
154
155static int
156ipfilter_modevent(module_t mod, int type, void *unused)
157{
158	int error = 0;
159
160	switch (type)
161	{
162	case MOD_LOAD :
163		error = ipf_modload();
164		break;
165
166	case MOD_UNLOAD :
167		error = ipf_modunload();
168		break;
169	default:
170		error = EINVAL;
171		break;
172	}
173	return error;
174}
175
176
177static int
178ipf_modload()
179{
180	char *defpass, *c, *str;
181	int i, j, error;
182
183	RWLOCK_INIT(&ipf_global, "ipf filter load/unload mutex");
184	RWLOCK_INIT(&ipf_mutex, "ipf filter rwlock");
185	RWLOCK_INIT(&ipf_frcache, "ipf cache rwlock");
186
187	error = ipfattach();
188	if (error) {
189		RW_DESTROY(&ipf_global);
190		RW_DESTROY(&ipf_mutex);
191		RW_DESTROY(&ipf_frcache);
192		return error;
193	}
194
195	for (i = 0; i < IPL_LOGSIZE; i++)
196		ipf_devs[i] = NULL;
197
198	for (i = 0; (str = ipf_devfiles[i]); i++) {
199		c = NULL;
200		for(j = strlen(str); j > 0; j--)
201			if (str[j] == '/') {
202				c = str + j + 1;
203				break;
204			}
205		if (!c)
206			c = str;
207		ipf_devs[i] = make_dev(&ipl_cdevsw, i, 0, 0, 0600, "%s", c);
208	}
209
210	error = ipf_pfil_hook();
211	if (error != 0)
212		return error;
213	ipf_event_reg();
214
215	if (FR_ISPASS(fr_pass))
216		defpass = "pass";
217	else if (FR_ISBLOCK(fr_pass))
218		defpass = "block";
219	else
220		defpass = "no-match -> block";
221
222	printf("%s initialized.  Default = %s all, Logging = %s%s\n",
223		ipfilter_version, defpass,
224#ifdef IPFILTER_LOG
225		"enabled",
226#else
227		"disabled",
228#endif
229#ifdef IPFILTER_COMPILED
230		" (COMPILED)"
231#else
232		""
233#endif
234		);
235	return 0;
236}
237
238
239static int
240ipf_modunload()
241{
242	int error, i;
243
244	if (fr_refcnt)
245		return EBUSY;
246
247	if (fr_running >= 0) {
248		ipf_pfil_unhook();
249		ipf_event_dereg();
250		WRITE_ENTER(&ipf_global);
251		error = ipfdetach();
252		RWLOCK_EXIT(&ipf_global);
253		if (error != 0)
254			return error;
255	} else
256		error = 0;
257
258	RW_DESTROY(&ipf_global);
259	RW_DESTROY(&ipf_mutex);
260	RW_DESTROY(&ipf_frcache);
261
262	fr_running = -2;
263
264	for (i = 0; ipf_devfiles[i]; i++) {
265		if (ipf_devs[i] != NULL)
266			destroy_dev(ipf_devs[i]);
267	}
268
269	printf("%s unloaded\n", ipfilter_version);
270
271	return error;
272}
273
274
275static moduledata_t ipfiltermod = {
276	"ipfilter",
277	ipfilter_modevent,
278	0
279};
280
281
282DECLARE_MODULE(ipfilter, ipfiltermod, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY);
283#ifdef	MODULE_VERSION
284MODULE_VERSION(ipfilter, 1);
285#endif
286
287
288#ifdef SYSCTL_IPF
289int
290sysctl_ipf_int ( SYSCTL_HANDLER_ARGS )
291{
292	int error = 0;
293
294	if (arg1)
295		error = SYSCTL_OUT(req, arg1, sizeof(int));
296	else
297		error = SYSCTL_OUT(req, &arg2, sizeof(int));
298
299	if (error || !req->newptr)
300		return (error);
301
302	if (!arg1)
303		error = EPERM;
304	else {
305		if ((oidp->oid_kind & CTLFLAG_OFF) && (fr_running > 0))
306			error = EBUSY;
307		else
308			error = SYSCTL_IN(req, arg1, sizeof(int));
309	}
310	return (error);
311}
312#endif
313
314
315static int
316#if __FreeBSD_version >= 500043
317iplpoll(struct cdev *dev, int events, struct thread *td)
318#else
319iplpoll(dev_t dev, int events, struct proc *td)
320#endif
321{
322	u_int xmin = GET_MINOR(dev);
323	int revents;
324
325	if (xmin < 0 || xmin > IPL_LOGMAX)
326		return 0;
327
328	revents = 0;
329
330	switch (xmin)
331	{
332	case IPL_LOGIPF :
333	case IPL_LOGNAT :
334	case IPL_LOGSTATE :
335#ifdef IPFILTER_LOG
336		if ((events & (POLLIN | POLLRDNORM)) && ipflog_canread(xmin))
337			revents |= events & (POLLIN | POLLRDNORM);
338#endif
339		break;
340	case IPL_LOGAUTH :
341		if ((events & (POLLIN | POLLRDNORM)) && fr_auth_waiting())
342			revents |= events & (POLLIN | POLLRDNORM);
343		break;
344	case IPL_LOGSYNC :
345#ifdef IPFILTER_SYNC
346		if ((events & (POLLIN | POLLRDNORM)) && ipfsync_canread())
347			revents |= events & (POLLIN | POLLRDNORM);
348		if ((events & (POLLOUT | POLLWRNORM)) && ipfsync_canwrite())
349			revents |= events & (POLLOUT | POLLWRNORM);
350#endif
351		break;
352	case IPL_LOGSCAN :
353	case IPL_LOGLOOKUP :
354	default :
355		break;
356	}
357
358	if ((revents == 0) && ((events & (POLLIN|POLLRDNORM)) != 0))
359		selrecord(td, &ipfselwait[xmin]);
360
361	return revents;
362}
363