1145522Sdarrenr/*	$FreeBSD$	*/
2145522Sdarrenr
354221Sguido/*
4145522Sdarrenr * Copyright (C) 2000 by Darren Reed.
554221Sguido *
654221Sguido * $FreeBSD$
7145522Sdarrenr * See the IPFILTER.LICENCE file for details on licencing.
854221Sguido */
954221Sguido
1060857Sdarrenr
1154221Sguido#include <sys/param.h>
1254221Sguido#include <sys/systm.h>
1354221Sguido#include <sys/kernel.h>
1454221Sguido#include <sys/module.h>
1554221Sguido#include <sys/conf.h>
1654221Sguido#include <sys/socket.h>
1754221Sguido#include <sys/sysctl.h>
18161356Sguido#include <sys/select.h>
19161356Sguido#if __FreeBSD_version >= 500000
20161356Sguido# include <sys/selinfo.h>
21161356Sguido#endif
2254221Sguido#include <net/if.h>
2354221Sguido#include <netinet/in_systm.h>
2454221Sguido#include <netinet/in.h>
2554221Sguido
2654221Sguido
2754221Sguido#include <netinet/ipl.h>
2854221Sguido#include <netinet/ip_compat.h>
2954221Sguido#include <netinet/ip_fil.h>
3054221Sguido#include <netinet/ip_state.h>
3154221Sguido#include <netinet/ip_nat.h>
3254221Sguido#include <netinet/ip_auth.h>
3354221Sguido#include <netinet/ip_frag.h>
34161356Sguido#include <netinet/ip_sync.h>
3554221Sguido
36145522Sdarrenr#if __FreeBSD_version >= 502116
37145522Sdarrenrstatic struct cdev *ipf_devs[IPL_LOGSIZE];
38145522Sdarrenr#else
39145522Sdarrenrstatic dev_t ipf_devs[IPL_LOGSIZE];
40145522Sdarrenr#endif
4154221Sguido
42145522Sdarrenrstatic int sysctl_ipf_int ( SYSCTL_HANDLER_ARGS );
43145522Sdarrenrstatic int ipf_modload(void);
44145522Sdarrenrstatic int ipf_modunload(void);
45145522Sdarrenr
4654221SguidoSYSCTL_DECL(_net_inet);
47145522Sdarrenr#define SYSCTL_IPF(parent, nbr, name, access, ptr, val, descr) \
48145522Sdarrenr	SYSCTL_OID(parent, nbr, name, CTLTYPE_INT|access, \
49145522Sdarrenr		   ptr, val, sysctl_ipf_int, "I", descr);
50145522Sdarrenr#define	CTLFLAG_OFF	0x00800000	/* IPFilter must be disabled */
51145522Sdarrenr#define	CTLFLAG_RWO	(CTLFLAG_RW|CTLFLAG_OFF)
5254221SguidoSYSCTL_NODE(_net_inet, OID_AUTO, ipf, CTLFLAG_RW, 0, "IPF");
53145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_flags, CTLFLAG_RW, &fr_flags, 0, "");
54145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_pass, CTLFLAG_RW, &fr_pass, 0, "");
55145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_active, CTLFLAG_RD, &fr_active, 0, "");
56145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpidletimeout, CTLFLAG_RWO,
5754221Sguido	   &fr_tcpidletimeout, 0, "");
58145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcphalfclosed, CTLFLAG_RWO,
59145522Sdarrenr	   &fr_tcphalfclosed, 0, "");
60145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpclosewait, CTLFLAG_RWO,
6154221Sguido	   &fr_tcpclosewait, 0, "");
62145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcplastack, CTLFLAG_RWO,
6354221Sguido	   &fr_tcplastack, 0, "");
64145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcptimeout, CTLFLAG_RWO,
6554221Sguido	   &fr_tcptimeout, 0, "");
66145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpclosed, CTLFLAG_RWO,
6754221Sguido	   &fr_tcpclosed, 0, "");
68145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_udptimeout, CTLFLAG_RWO,
6954221Sguido	   &fr_udptimeout, 0, "");
70145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_udpacktimeout, CTLFLAG_RWO,
7192685Sdarrenr	   &fr_udpacktimeout, 0, "");
72145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_icmptimeout, CTLFLAG_RWO,
7354221Sguido	   &fr_icmptimeout, 0, "");
74145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_defnatage, CTLFLAG_RWO,
7554221Sguido	   &fr_defnatage, 0, "");
76145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_ipfrttl, CTLFLAG_RW,
7754221Sguido	   &fr_ipfrttl, 0, "");
78145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_running, CTLFLAG_RD,
7957096Sguido	   &fr_running, 0, "");
80145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_statesize, CTLFLAG_RWO,
81145522Sdarrenr	   &fr_statesize, 0, "");
82145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_statemax, CTLFLAG_RWO,
83145522Sdarrenr	   &fr_statemax, 0, "");
84145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_nattable_sz, CTLFLAG_RWO,
85145522Sdarrenr	   &ipf_nattable_sz, 0, "");
86145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_natrules_sz, CTLFLAG_RWO,
87145522Sdarrenr	   &ipf_natrules_sz, 0, "");
88145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_rdrrules_sz, CTLFLAG_RWO,
89145522Sdarrenr	   &ipf_rdrrules_sz, 0, "");
90145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_hostmap_sz, CTLFLAG_RWO,
91145522Sdarrenr	   &ipf_hostmap_sz, 0, "");
92145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_authsize, CTLFLAG_RWO,
9354221Sguido	   &fr_authsize, 0, "");
94145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_authused, CTLFLAG_RD,
9554221Sguido	   &fr_authused, 0, "");
96145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_defaultauthage, CTLFLAG_RW,
9754221Sguido	   &fr_defaultauthage, 0, "");
98145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_chksrc, CTLFLAG_RW, &fr_chksrc, 0, "");
99145522SdarrenrSYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_minttl, CTLFLAG_RW, &fr_minttl, 0, "");
10054221Sguido
101145522Sdarrenr#define CDEV_MAJOR 79
102170268Sdarrenr#include <sys/poll.h>
103170268Sdarrenr#if __FreeBSD_version >= 500043
104161356Sguido# include <sys/select.h>
105161356Sguidostatic int iplpoll(struct cdev *dev, int events, struct thread *td);
106161356Sguido
10754221Sguidostatic struct cdevsw ipl_cdevsw = {
108145522Sdarrenr# if __FreeBSD_version >= 502103
109126080Sphk	.d_version =	D_VERSION,
110145522Sdarrenr	.d_flags =	0,	/* D_NEEDGIANT - Should be SMP safe */
111145522Sdarrenr# endif
112111815Sphk	.d_open =	iplopen,
113111815Sphk	.d_close =	iplclose,
114111815Sphk	.d_read =	iplread,
115153876Sguido	.d_write =	iplwrite,
116111815Sphk	.d_ioctl =	iplioctl,
117111815Sphk	.d_name =	"ipl",
118170268Sdarrenr# if __FreeBSD_version >= 500043
119161356Sguido	.d_poll =	iplpoll,
120170268Sdarrenr# endif
121145522Sdarrenr# if __FreeBSD_version < 600000
122145522Sdarrenr	.d_maj =	CDEV_MAJOR,
123145522Sdarrenr# endif
12454221Sguido};
125145522Sdarrenr#else
126170268Sdarrenrstatic int iplpoll(dev_t dev, int events, struct proc *p);
127170268Sdarrenr
128145522Sdarrenrstatic struct cdevsw ipl_cdevsw = {
129145522Sdarrenr	/* open */	iplopen,
130145522Sdarrenr	/* close */	iplclose,
131145522Sdarrenr	/* read */	iplread,
132145522Sdarrenr	/* write */	iplwrite,
133145522Sdarrenr	/* ioctl */	iplioctl,
134161356Sguido	/* poll */	iplpoll,
135145522Sdarrenr	/* mmap */	nommap,
136145522Sdarrenr	/* strategy */	nostrategy,
137145522Sdarrenr	/* name */	"ipl",
138145522Sdarrenr	/* maj */	CDEV_MAJOR,
139145522Sdarrenr	/* dump */	nodump,
140145522Sdarrenr	/* psize */	nopsize,
141145522Sdarrenr	/* flags */	0,
142145522Sdarrenr# if (__FreeBSD_version < 500043)
143145522Sdarrenr	/* bmaj */	-1,
144145522Sdarrenr# endif
145170268Sdarrenr# if (__FreeBSD_version > 430000)
146145522Sdarrenr	/* kqfilter */	NULL
147170268Sdarrenr# endif
148145522Sdarrenr};
149139255Sdarrenr#endif
150139255Sdarrenr
151145522Sdarrenrstatic char *ipf_devfiles[] = {	IPL_NAME, IPNAT_NAME, IPSTATE_NAME, IPAUTH_NAME,
152145522Sdarrenr				IPSYNC_NAME, IPSCAN_NAME, IPLOOKUP_NAME, NULL };
153145522Sdarrenr
154145522Sdarrenr
15554221Sguidostatic int
15654221Sguidoipfilter_modevent(module_t mod, int type, void *unused)
15754221Sguido{
158145522Sdarrenr	int error = 0;
15954221Sguido
160145522Sdarrenr	switch (type)
161145522Sdarrenr	{
16254221Sguido	case MOD_LOAD :
163145522Sdarrenr		error = ipf_modload();
164145522Sdarrenr		break;
16560857Sdarrenr
166145522Sdarrenr	case MOD_UNLOAD :
167145522Sdarrenr		error = ipf_modunload();
168145522Sdarrenr		break;
169145522Sdarrenr	default:
170145522Sdarrenr		error = EINVAL;
171145522Sdarrenr		break;
172145522Sdarrenr	}
173145522Sdarrenr	return error;
174145522Sdarrenr}
17554221Sguido
17654221Sguido
177145522Sdarrenrstatic int
178145522Sdarrenripf_modload()
179145522Sdarrenr{
180145522Sdarrenr	char *defpass, *c, *str;
181145522Sdarrenr	int i, j, error;
18254221Sguido
183170268Sdarrenr	RWLOCK_INIT(&ipf_global, "ipf filter load/unload mutex");
184170268Sdarrenr	RWLOCK_INIT(&ipf_mutex, "ipf filter rwlock");
185170268Sdarrenr	RWLOCK_INIT(&ipf_frcache, "ipf cache rwlock");
186170268Sdarrenr
187170268Sdarrenr	error = ipfattach();
188170268Sdarrenr	if (error) {
189170268Sdarrenr		RW_DESTROY(&ipf_global);
190170268Sdarrenr		RW_DESTROY(&ipf_mutex);
191170268Sdarrenr		RW_DESTROY(&ipf_frcache);
192145522Sdarrenr		return error;
193170268Sdarrenr	}
19454221Sguido
195145522Sdarrenr	for (i = 0; i < IPL_LOGSIZE; i++)
196145522Sdarrenr		ipf_devs[i] = NULL;
197145522Sdarrenr
198145522Sdarrenr	for (i = 0; (str = ipf_devfiles[i]); i++) {
19954221Sguido		c = NULL;
200145522Sdarrenr		for(j = strlen(str); j > 0; j--)
201145522Sdarrenr			if (str[j] == '/') {
202145522Sdarrenr				c = str + j + 1;
20354221Sguido				break;
20454221Sguido			}
20554221Sguido		if (!c)
206145522Sdarrenr			c = str;
207213782Srpaulo		ipf_devs[i] = make_dev(&ipl_cdevsw, i, 0, 0, 0600, "%s", c);
208145522Sdarrenr	}
20954221Sguido
210172776Sdarrenr	error = ipf_pfil_hook();
211172776Sdarrenr	if (error != 0)
212172776Sdarrenr		return error;
213172776Sdarrenr	ipf_event_reg();
214172776Sdarrenr
215145522Sdarrenr	if (FR_ISPASS(fr_pass))
216145522Sdarrenr		defpass = "pass";
217145522Sdarrenr	else if (FR_ISBLOCK(fr_pass))
218145522Sdarrenr		defpass = "block";
219145522Sdarrenr	else
220145522Sdarrenr		defpass = "no-match -> block";
221145522Sdarrenr
222145522Sdarrenr	printf("%s initialized.  Default = %s all, Logging = %s%s\n",
223145522Sdarrenr		ipfilter_version, defpass,
224145522Sdarrenr#ifdef IPFILTER_LOG
225145522Sdarrenr		"enabled",
226145522Sdarrenr#else
227145522Sdarrenr		"disabled",
228145522Sdarrenr#endif
229145522Sdarrenr#ifdef IPFILTER_COMPILED
230145522Sdarrenr		" (COMPILED)"
231145522Sdarrenr#else
232145522Sdarrenr		""
233145522Sdarrenr#endif
234145522Sdarrenr		);
235145522Sdarrenr	return 0;
236145522Sdarrenr}
237145522Sdarrenr
238145522Sdarrenr
239145522Sdarrenrstatic int
240145522Sdarrenripf_modunload()
241145522Sdarrenr{
242145522Sdarrenr	int error, i;
243145522Sdarrenr
244145522Sdarrenr	if (fr_refcnt)
245145522Sdarrenr		return EBUSY;
246145522Sdarrenr
247145522Sdarrenr	if (fr_running >= 0) {
248172776Sdarrenr		ipf_pfil_unhook();
249172776Sdarrenr		ipf_event_dereg();
250172776Sdarrenr		WRITE_ENTER(&ipf_global);
251170268Sdarrenr		error = ipfdetach();
252172776Sdarrenr		RWLOCK_EXIT(&ipf_global);
253145522Sdarrenr		if (error != 0)
254145522Sdarrenr			return error;
255145522Sdarrenr	} else
256145522Sdarrenr		error = 0;
257145522Sdarrenr
258170268Sdarrenr	RW_DESTROY(&ipf_global);
259170268Sdarrenr	RW_DESTROY(&ipf_mutex);
260170268Sdarrenr	RW_DESTROY(&ipf_frcache);
261170268Sdarrenr
262145522Sdarrenr	fr_running = -2;
263145522Sdarrenr
264145522Sdarrenr	for (i = 0; ipf_devfiles[i]; i++) {
265145522Sdarrenr		if (ipf_devs[i] != NULL)
266145522Sdarrenr			destroy_dev(ipf_devs[i]);
26754221Sguido	}
268145522Sdarrenr
269145522Sdarrenr	printf("%s unloaded\n", ipfilter_version);
270145522Sdarrenr
27154221Sguido	return error;
27254221Sguido}
27354221Sguido
274145522Sdarrenr
27554221Sguidostatic moduledata_t ipfiltermod = {
276145522Sdarrenr	"ipfilter",
27754221Sguido	ipfilter_modevent,
278145522Sdarrenr	0
27954221Sguido};
280145522Sdarrenr
281145522Sdarrenr
28254221SguidoDECLARE_MODULE(ipfilter, ipfiltermod, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY);
283145522Sdarrenr#ifdef	MODULE_VERSION
284145522SdarrenrMODULE_VERSION(ipfilter, 1);
285145522Sdarrenr#endif
286145522Sdarrenr
287145522Sdarrenr
288145522Sdarrenr#ifdef SYSCTL_IPF
289145522Sdarrenrint
290145522Sdarrenrsysctl_ipf_int ( SYSCTL_HANDLER_ARGS )
291145522Sdarrenr{
292145522Sdarrenr	int error = 0;
293145522Sdarrenr
294145522Sdarrenr	if (arg1)
295145522Sdarrenr		error = SYSCTL_OUT(req, arg1, sizeof(int));
296145522Sdarrenr	else
297145522Sdarrenr		error = SYSCTL_OUT(req, &arg2, sizeof(int));
298145522Sdarrenr
299145522Sdarrenr	if (error || !req->newptr)
300145522Sdarrenr		return (error);
301145522Sdarrenr
302145522Sdarrenr	if (!arg1)
303145522Sdarrenr		error = EPERM;
304145522Sdarrenr	else {
305145522Sdarrenr		if ((oidp->oid_kind & CTLFLAG_OFF) && (fr_running > 0))
306145522Sdarrenr			error = EBUSY;
307145522Sdarrenr		else
308145522Sdarrenr			error = SYSCTL_IN(req, arg1, sizeof(int));
309145522Sdarrenr	}
310145522Sdarrenr	return (error);
311145522Sdarrenr}
312145522Sdarrenr#endif
313161356Sguido
314161356Sguido
315161356Sguidostatic int
316170268Sdarrenr#if __FreeBSD_version >= 500043
317161356Sguidoiplpoll(struct cdev *dev, int events, struct thread *td)
318170268Sdarrenr#else
319170268Sdarrenriplpoll(dev_t dev, int events, struct proc *td)
320170268Sdarrenr#endif
321161356Sguido{
322161356Sguido	u_int xmin = GET_MINOR(dev);
323161356Sguido	int revents;
324161356Sguido
325161356Sguido	if (xmin < 0 || xmin > IPL_LOGMAX)
326161356Sguido		return 0;
327161356Sguido
328161356Sguido	revents = 0;
329161356Sguido
330161356Sguido	switch (xmin)
331161356Sguido	{
332161356Sguido	case IPL_LOGIPF :
333161356Sguido	case IPL_LOGNAT :
334161356Sguido	case IPL_LOGSTATE :
335161356Sguido#ifdef IPFILTER_LOG
336161356Sguido		if ((events & (POLLIN | POLLRDNORM)) && ipflog_canread(xmin))
337161356Sguido			revents |= events & (POLLIN | POLLRDNORM);
338161356Sguido#endif
339161356Sguido		break;
340161356Sguido	case IPL_LOGAUTH :
341161356Sguido		if ((events & (POLLIN | POLLRDNORM)) && fr_auth_waiting())
342161356Sguido			revents |= events & (POLLIN | POLLRDNORM);
343161356Sguido		break;
344161356Sguido	case IPL_LOGSYNC :
345161356Sguido#ifdef IPFILTER_SYNC
346161356Sguido		if ((events & (POLLIN | POLLRDNORM)) && ipfsync_canread())
347161356Sguido			revents |= events & (POLLIN | POLLRDNORM);
348161356Sguido		if ((events & (POLLOUT | POLLWRNORM)) && ipfsync_canwrite())
349161356Sguido			revents |= events & (POLLOUT | POLLWRNORM);
350161356Sguido#endif
351161356Sguido		break;
352161356Sguido	case IPL_LOGSCAN :
353161356Sguido	case IPL_LOGLOOKUP :
354161356Sguido	default :
355161356Sguido		break;
356161356Sguido	}
357161356Sguido
358161356Sguido	if ((revents == 0) && ((events & (POLLIN|POLLRDNORM)) != 0))
359161356Sguido		selrecord(td, &ipfselwait[xmin]);
360161356Sguido
361161356Sguido	return revents;
362161356Sguido}
363