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#if defined(KERNEL) || defined(_KERNEL)
11# undef KERNEL
12# undef _KERNEL
13# define	KERNEL  1
14# define	_KERNEL 1
15#endif
16
17#include <sys/param.h>
18#include <sys/systm.h>
19#include <sys/kernel.h>
20#include <sys/module.h>
21#include <sys/conf.h>
22#include <sys/socket.h>
23#include <sys/sysctl.h>
24#include <sys/select.h>
25#ifdef __FreeBSD__
26# include <sys/selinfo.h>
27# include <sys/jail.h>
28# ifdef _KERNEL
29#  include <net/vnet.h>
30# else
31#  define CURVNET_SET(arg)
32#  define CURVNET_RESTORE()
33#  define	VNET_DEFINE(_t, _v)	_t _v
34#  define	VNET_DECLARE(_t, _v)	extern _t _v
35#  define	VNET(arg)	arg
36# endif
37#endif
38#include <net/if.h>
39#include <netinet/in_systm.h>
40#include <netinet/in.h>
41
42
43#include "netinet/ipl.h"
44#include "netinet/ip_compat.h"
45#include "netinet/ip_fil.h"
46#include "netinet/ip_state.h"
47#include "netinet/ip_nat.h"
48#include "netinet/ip_auth.h"
49#include "netinet/ip_frag.h"
50#include "netinet/ip_sync.h"
51
52VNET_DECLARE(ipf_main_softc_t, ipfmain);
53#define	V_ipfmain		VNET(ipfmain)
54
55#ifdef __FreeBSD__
56static struct cdev *ipf_devs[IPL_LOGSIZE];
57#else
58static dev_t ipf_devs[IPL_LOGSIZE];
59#endif
60
61static int sysctl_ipf_int ( SYSCTL_HANDLER_ARGS );
62static int sysctl_ipf_int_nat ( SYSCTL_HANDLER_ARGS );
63static int sysctl_ipf_int_state ( SYSCTL_HANDLER_ARGS );
64static int sysctl_ipf_int_auth ( SYSCTL_HANDLER_ARGS );
65static int sysctl_ipf_int_frag ( SYSCTL_HANDLER_ARGS );
66static int ipf_modload(void);
67static int ipf_modunload(void);
68static int ipf_fbsd_sysctl_create(void);
69static int ipf_fbsd_sysctl_destroy(void);
70
71#ifdef __FreeBSD__
72static	int	ipfopen(struct cdev*, int, int, struct thread *);
73static	int	ipfclose(struct cdev*, int, int, struct thread *);
74static	int	ipfread(struct cdev*, struct uio *, int);
75static	int	ipfwrite(struct cdev*, struct uio *, int);
76#else
77static	int	ipfopen(dev_t, int, int, struct proc *);
78static	int	ipfclose(dev_t, int, int, struct proc *);
79static	int	ipfread(dev_t, struct uio *, int);
80static	int	ipfwrite(dev_t, struct uio *, int);
81#endif
82
83
84SYSCTL_DECL(_net_inet);
85#define SYSCTL_IPF(parent, nbr, name, access, ptr, val, descr) \
86    SYSCTL_OID(parent, nbr, name, \
87        CTLTYPE_INT | CTLFLAG_VNET | CTLFLAG_MPSAFE | access, \
88        ptr, val, sysctl_ipf_int, "I", descr)
89#define SYSCTL_DYN_IPF_NAT(parent, nbr, name, access,ptr, val, descr) \
90    SYSCTL_ADD_OID(&ipf_clist, SYSCTL_STATIC_CHILDREN(parent), nbr, name, \
91        CTLTYPE_INT | CTLFLAG_VNET | CTLFLAG_MPSAFE |access, \
92        ptr, val, sysctl_ipf_int_nat, "I", descr)
93#define SYSCTL_DYN_IPF_STATE(parent, nbr, name, access,ptr, val, descr) \
94    SYSCTL_ADD_OID(&ipf_clist, SYSCTL_STATIC_CHILDREN(parent), nbr, name, \
95        CTLTYPE_INT | CTLFLAG_VNET | CTLFLAG_MPSAFE | access, \
96        ptr, val, sysctl_ipf_int_state, "I", descr)
97#define SYSCTL_DYN_IPF_FRAG(parent, nbr, name, access,ptr, val, descr) \
98    SYSCTL_ADD_OID(&ipf_clist, SYSCTL_STATIC_CHILDREN(parent), nbr, name, \
99        CTLTYPE_INT | CTLFLAG_VNET | CTLFLAG_MPSAFE | access, \
100	ptr, val, sysctl_ipf_int_frag, "I", descr)
101#define SYSCTL_DYN_IPF_AUTH(parent, nbr, name, access,ptr, val, descr) \
102    SYSCTL_ADD_OID(&ipf_clist, SYSCTL_STATIC_CHILDREN(parent), nbr, name, \
103        CTLTYPE_INT | CTLFLAG_VNET | CTLFLAG_MPSAFE | access, \
104	ptr, val, sysctl_ipf_int_auth, "I", descr)
105static struct sysctl_ctx_list ipf_clist;
106#define	CTLFLAG_OFF	0x00800000	/* IPFilter must be disabled */
107#define	CTLFLAG_RWO	(CTLFLAG_RW|CTLFLAG_OFF)
108SYSCTL_NODE(_net_inet, OID_AUTO, ipf, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
109    "IPF");
110SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_flags, CTLFLAG_RW, &VNET_NAME(ipfmain.ipf_flags), 0, "IPF flags");
111SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_pass, CTLFLAG_RW, &VNET_NAME(ipfmain.ipf_pass), 0, "default pass/block");
112SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_active, CTLFLAG_RD, &VNET_NAME(ipfmain.ipf_active), 0, "IPF is active");
113SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpidletimeout, CTLFLAG_RWO,
114	   &VNET_NAME(ipfmain.ipf_tcpidletimeout), 0, "TCP idle timeout in seconds");
115SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcphalfclosed, CTLFLAG_RWO,
116	   &VNET_NAME(ipfmain.ipf_tcphalfclosed), 0, "timeout for half closed TCP sessions");
117SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpclosewait, CTLFLAG_RWO,
118	   &VNET_NAME(ipfmain.ipf_tcpclosewait), 0, "timeout for TCP sessions in closewait status");
119SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcplastack, CTLFLAG_RWO,
120	   &VNET_NAME(ipfmain.ipf_tcplastack), 0, "timeout for TCP sessions in last ack status");
121SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcptimeout, CTLFLAG_RWO,
122	   &VNET_NAME(ipfmain.ipf_tcptimeout), 0, "");
123SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpclosed, CTLFLAG_RWO,
124	   &VNET_NAME(ipfmain.ipf_tcpclosed), 0, "");
125SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_udptimeout, CTLFLAG_RWO,
126	   &VNET_NAME(ipfmain.ipf_udptimeout), 0, "UDP timeout");
127SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_udpacktimeout, CTLFLAG_RWO,
128	   &VNET_NAME(ipfmain.ipf_udpacktimeout), 0, "");
129SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_icmptimeout, CTLFLAG_RWO,
130	   &VNET_NAME(ipfmain.ipf_icmptimeout), 0, "ICMP timeout");
131SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_running, CTLFLAG_RD,
132	   &VNET_NAME(ipfmain.ipf_running), 0, "IPF is running");
133SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_chksrc, CTLFLAG_RW, &VNET_NAME(ipfmain.ipf_chksrc), 0, "");
134SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_minttl, CTLFLAG_RW, &VNET_NAME(ipfmain.ipf_minttl), 0, "");
135
136#define CDEV_MAJOR 79
137#include <sys/poll.h>
138#ifdef __FreeBSD__
139# include <sys/select.h>
140static int ipfpoll(struct cdev *dev, int events, struct thread *td);
141
142static struct cdevsw ipf_cdevsw = {
143	.d_version =	D_VERSION,
144	.d_flags =	0,	/* D_NEEDGIANT - Should be SMP safe */
145	.d_open =	ipfopen,
146	.d_close =	ipfclose,
147	.d_read =	ipfread,
148	.d_write =	ipfwrite,
149	.d_ioctl =	ipfioctl,
150	.d_poll =	ipfpoll,
151	.d_name =	"ipf",
152};
153#else
154static int ipfpoll(dev_t dev, int events, struct proc *td);
155
156static struct cdevsw ipf_cdevsw = {
157	/* open */	ipfopen,
158	/* close */	ipfclose,
159	/* read */	ipfread,
160	/* write */	ipfwrite,
161	/* ioctl */	ipfioctl,
162	/* poll */	ipfpoll,
163	/* mmap */	nommap,
164	/* strategy */	nostrategy,
165	/* name */	"ipf",
166	/* maj */	CDEV_MAJOR,
167	/* dump */	nodump,
168	/* psize */	nopsize,
169	/* flags */	0,
170};
171#endif
172
173static char *ipf_devfiles[] = {	IPL_NAME, IPNAT_NAME, IPSTATE_NAME, IPAUTH_NAME,
174				IPSYNC_NAME, IPSCAN_NAME, IPLOOKUP_NAME, NULL };
175
176static int
177ipfilter_modevent(module_t mod, int type, void *unused)
178{
179	int error = 0;
180
181	switch (type)
182	{
183	case MOD_LOAD :
184		error = ipf_modload();
185		break;
186
187	case MOD_UNLOAD :
188		error = ipf_modunload();
189		break;
190	default:
191		error = EINVAL;
192		break;
193	}
194	return error;
195}
196
197
198static void
199vnet_ipf_init(void)
200{
201	char *defpass;
202	int error;
203
204	if (ipf_create_all(&V_ipfmain) == NULL)
205		return;
206
207	error = ipfattach(&V_ipfmain);
208	if (error) {
209		ipf_destroy_all(&V_ipfmain);
210		return;
211	}
212
213	if (FR_ISPASS(V_ipfmain.ipf_pass))
214		defpass = "pass";
215	else if (FR_ISBLOCK(V_ipfmain.ipf_pass))
216		defpass = "block";
217	else
218		defpass = "no-match -> block";
219
220	if (IS_DEFAULT_VNET(curvnet)) {
221	    printf("%s initialized.  Default = %s all, Logging = %s%s\n",
222		ipfilter_version, defpass,
223#ifdef IPFILTER_LOG
224		"enabled",
225#else
226		"disabled",
227#endif
228#ifdef IPFILTER_COMPILED
229		" (COMPILED)"
230#else
231		""
232#endif
233		);
234	} else {
235		(void)ipf_pfil_hook();
236		ipf_event_reg();
237	}
238}
239VNET_SYSINIT(vnet_ipf_init, SI_SUB_PROTO_FIREWALL, SI_ORDER_THIRD,
240    vnet_ipf_init, NULL);
241
242static int
243ipf_modload()
244{
245	char *c, *str;
246	int i, j, error;
247
248	if (ipf_load_all() != 0)
249		return EIO;
250
251	if (ipf_fbsd_sysctl_create() != 0) {
252		return EIO;
253	}
254
255	for (i = 0; i < IPL_LOGSIZE; i++)
256		ipf_devs[i] = NULL;
257	for (i = 0; (str = ipf_devfiles[i]); i++) {
258		c = NULL;
259		for(j = strlen(str); j > 0; j--)
260			if (str[j] == '/') {
261				c = str + j + 1;
262				break;
263			}
264		if (!c)
265			c = str;
266		ipf_devs[i] = make_dev(&ipf_cdevsw, i, 0, 0, 0600, "%s", c);
267	}
268
269	error = ipf_pfil_hook();
270	if (error != 0)
271		return error;
272	ipf_event_reg();
273
274	return 0;
275}
276
277static void
278vnet_ipf_uninit(void)
279{
280
281	if (V_ipfmain.ipf_refcnt)
282		return;
283
284	if (V_ipfmain.ipf_running >= 0) {
285
286		if (ipfdetach(&V_ipfmain) != 0)
287			return;
288
289		V_ipfmain.ipf_running = -2;
290
291		ipf_destroy_all(&V_ipfmain);
292		if (!IS_DEFAULT_VNET(curvnet)) {
293			ipf_event_dereg();
294			(void)ipf_pfil_unhook();
295		}
296	}
297}
298VNET_SYSUNINIT(vnet_ipf_uninit, SI_SUB_PROTO_FIREWALL, SI_ORDER_THIRD,
299    vnet_ipf_uninit, NULL);
300
301static int
302ipf_modunload()
303{
304	int error, i;
305
306	ipf_event_dereg();
307
308	ipf_fbsd_sysctl_destroy();
309
310	error = ipf_pfil_unhook();
311	if (error != 0)
312		return error;
313
314	for (i = 0; ipf_devfiles[i]; i++) {
315		if (ipf_devs[i] != NULL)
316			destroy_dev(ipf_devs[i]);
317	}
318
319	ipf_unload_all();
320
321	printf("%s unloaded\n", ipfilter_version);
322
323	return (0);
324}
325
326
327static moduledata_t ipfiltermod = {
328	"ipfilter",
329	ipfilter_modevent,
330	0
331};
332
333
334DECLARE_MODULE(ipfilter, ipfiltermod, SI_SUB_PROTO_FIREWALL, SI_ORDER_SECOND);
335#ifdef	MODULE_VERSION
336MODULE_VERSION(ipfilter, 1);
337#endif
338
339
340#ifdef SYSCTL_IPF
341int
342sysctl_ipf_int ( SYSCTL_HANDLER_ARGS )
343{
344	int error = 0;
345
346	WRITE_ENTER(&V_ipfmain.ipf_mutex);
347	if (arg1)
348		error = SYSCTL_OUT(req, arg1, sizeof(int));
349	else
350		error = SYSCTL_OUT(req, &arg2, sizeof(int));
351
352	if (error || !req->newptr)
353		goto sysctl_error;
354
355	if (!arg1)
356		error = EPERM;
357	else {
358		if ((oidp->oid_kind & CTLFLAG_OFF) && (V_ipfmain.ipf_running > 0))
359			error = EBUSY;
360		else
361			error = SYSCTL_IN(req, arg1, sizeof(int));
362	}
363
364sysctl_error:
365	RWLOCK_EXIT(&V_ipfmain.ipf_mutex);
366	return (error);
367}
368
369/*
370 * arg2 holds the offset of the relevant member in the virtualized
371 * ipfmain structure.
372 */
373static int
374sysctl_ipf_int_nat ( SYSCTL_HANDLER_ARGS )
375{
376	ipf_nat_softc_t *nat_softc;
377
378	nat_softc = V_ipfmain.ipf_nat_soft;
379	arg1 = (void *)((uintptr_t)nat_softc + arg2);
380
381	return (sysctl_ipf_int(oidp, arg1, 0, req));
382}
383
384static int
385sysctl_ipf_int_state ( SYSCTL_HANDLER_ARGS )
386{
387	ipf_state_softc_t *state_softc;
388
389	state_softc = V_ipfmain.ipf_state_soft;
390	arg1 = (void *)((uintptr_t)state_softc + arg2);
391
392	return (sysctl_ipf_int(oidp, arg1, 0, req));
393}
394
395static int
396sysctl_ipf_int_auth ( SYSCTL_HANDLER_ARGS )
397{
398	ipf_auth_softc_t *auth_softc;
399
400	auth_softc = V_ipfmain.ipf_auth_soft;
401	arg1 = (void *)((uintptr_t)auth_softc + arg2);
402
403	return (sysctl_ipf_int(oidp, arg1, 0, req));
404}
405
406static int
407sysctl_ipf_int_frag ( SYSCTL_HANDLER_ARGS )
408{
409	ipf_frag_softc_t *frag_softc;
410
411	frag_softc = V_ipfmain.ipf_frag_soft;
412	arg1 = (void *)((uintptr_t)frag_softc + arg2);
413
414	return (sysctl_ipf_int(oidp, arg1, 0, req));
415}
416#endif
417
418
419static int
420#ifdef __FreeBSD__
421ipfpoll(struct cdev *dev, int events, struct thread *td)
422#else
423ipfpoll(dev_t dev, int events, struct proc *td)
424#endif
425{
426	int unit = GET_MINOR(dev);
427	int revents;
428
429	if (unit < 0 || unit > IPL_LOGMAX)
430		return 0;
431
432	revents = 0;
433
434	CURVNET_SET(TD_TO_VNET(td));
435	switch (unit)
436	{
437	case IPL_LOGIPF :
438	case IPL_LOGNAT :
439	case IPL_LOGSTATE :
440#ifdef IPFILTER_LOG
441		if ((events & (POLLIN | POLLRDNORM)) && ipf_log_canread(&V_ipfmain, unit))
442			revents |= events & (POLLIN | POLLRDNORM);
443#endif
444		break;
445	case IPL_LOGAUTH :
446		if ((events & (POLLIN | POLLRDNORM)) && ipf_auth_waiting(&V_ipfmain))
447			revents |= events & (POLLIN | POLLRDNORM);
448		break;
449	case IPL_LOGSYNC :
450		if ((events & (POLLIN | POLLRDNORM)) && ipf_sync_canread(&V_ipfmain))
451			revents |= events & (POLLIN | POLLRDNORM);
452		if ((events & (POLLOUT | POLLWRNORM)) && ipf_sync_canwrite(&V_ipfmain))
453			revents |= events & (POLLOUT | POLLWRNORM);
454		break;
455	case IPL_LOGSCAN :
456	case IPL_LOGLOOKUP :
457	default :
458		break;
459	}
460
461	if ((revents == 0) && ((events & (POLLIN|POLLRDNORM)) != 0))
462		selrecord(td, &V_ipfmain.ipf_selwait[unit]);
463	CURVNET_RESTORE();
464
465	return revents;
466}
467
468
469/*
470 * routines below for saving IP headers to buffer
471 */
472static int ipfopen(dev, flags
473#ifdef __FreeBSD__
474, devtype, p)
475	int devtype;
476	struct thread *p;
477	struct cdev *dev;
478#else
479)
480	dev_t dev;
481#endif
482	int flags;
483{
484	int unit = GET_MINOR(dev);
485	int error;
486
487	if (IPL_LOGMAX < unit)
488		error = ENXIO;
489	else {
490		switch (unit)
491		{
492		case IPL_LOGIPF :
493		case IPL_LOGNAT :
494		case IPL_LOGSTATE :
495		case IPL_LOGAUTH :
496		case IPL_LOGLOOKUP :
497		case IPL_LOGSYNC :
498#ifdef IPFILTER_SCAN
499		case IPL_LOGSCAN :
500#endif
501			error = 0;
502			break;
503		default :
504			error = ENXIO;
505			break;
506		}
507	}
508	return error;
509}
510
511
512static int ipfclose(dev, flags
513#ifdef __FreeBSD__
514, devtype, p)
515	int devtype;
516	struct thread *p;
517	struct cdev *dev;
518#else
519)
520	dev_t dev;
521#endif
522	int flags;
523{
524	int	unit = GET_MINOR(dev);
525
526	if (IPL_LOGMAX < unit)
527		unit = ENXIO;
528	else
529		unit = 0;
530	return unit;
531}
532
533/*
534 * ipfread/ipflog
535 * both of these must operate with at least splnet() lest they be
536 * called during packet processing and cause an inconsistancy to appear in
537 * the filter lists.
538 */
539static int ipfread(dev, uio, ioflag)
540	int ioflag;
541#ifdef __FreeBSD__
542	struct cdev *dev;
543#else
544	dev_t dev;
545#endif
546	struct uio *uio;
547{
548	int error;
549	int	unit = GET_MINOR(dev);
550
551	if (unit < 0)
552		return ENXIO;
553
554	CURVNET_SET(TD_TO_VNET(curthread));
555	if (V_ipfmain.ipf_running < 1) {
556		CURVNET_RESTORE();
557		return EIO;
558	}
559
560	if (unit == IPL_LOGSYNC) {
561		error = ipf_sync_read(&V_ipfmain, uio);
562		CURVNET_RESTORE();
563		return error;
564	}
565
566#ifdef IPFILTER_LOG
567	error = ipf_log_read(&V_ipfmain, unit, uio);
568#else
569	error = ENXIO;
570#endif
571	CURVNET_RESTORE();
572	return error;
573}
574
575
576/*
577 * ipfwrite
578 * both of these must operate with at least splnet() lest they be
579 * called during packet processing and cause an inconsistancy to appear in
580 * the filter lists.
581 */
582static int ipfwrite(dev, uio, ioflag)
583	int ioflag;
584#ifdef __FreeBSD__
585	struct cdev *dev;
586#else
587	dev_t dev;
588#endif
589	struct uio *uio;
590{
591	int error;
592
593	CURVNET_SET(TD_TO_VNET(curthread));
594	if (V_ipfmain.ipf_running < 1) {
595		CURVNET_RESTORE();
596		return EIO;
597	}
598
599	if (GET_MINOR(dev) == IPL_LOGSYNC) {
600		error = ipf_sync_write(&V_ipfmain, uio);
601		CURVNET_RESTORE();
602		return error;
603	}
604	return ENXIO;
605}
606
607static int
608ipf_fbsd_sysctl_create(void)
609{
610
611	sysctl_ctx_init(&ipf_clist);
612
613	SYSCTL_DYN_IPF_NAT(_net_inet_ipf, OID_AUTO, "fr_defnatage", CTLFLAG_RWO,
614	    NULL, offsetof(ipf_nat_softc_t, ipf_nat_defage), "");
615	SYSCTL_DYN_IPF_STATE(_net_inet_ipf, OID_AUTO, "fr_statesize", CTLFLAG_RWO,
616	    NULL, offsetof(ipf_state_softc_t, ipf_state_size), "");
617	SYSCTL_DYN_IPF_STATE(_net_inet_ipf, OID_AUTO, "fr_statemax", CTLFLAG_RWO,
618	    NULL, offsetof(ipf_state_softc_t, ipf_state_max), "");
619	SYSCTL_DYN_IPF_NAT(_net_inet_ipf, OID_AUTO, "ipf_nattable_max", CTLFLAG_RWO,
620	    NULL, offsetof(ipf_nat_softc_t, ipf_nat_table_max), "");
621	SYSCTL_DYN_IPF_NAT(_net_inet_ipf, OID_AUTO, "ipf_nattable_sz", CTLFLAG_RWO,
622	    NULL, offsetof(ipf_nat_softc_t, ipf_nat_table_sz), "");
623	SYSCTL_DYN_IPF_NAT(_net_inet_ipf, OID_AUTO, "ipf_natrules_sz", CTLFLAG_RWO,
624	    NULL, offsetof(ipf_nat_softc_t, ipf_nat_maprules_sz), "");
625	SYSCTL_DYN_IPF_NAT(_net_inet_ipf, OID_AUTO, "ipf_rdrrules_sz", CTLFLAG_RWO,
626	    NULL, offsetof(ipf_nat_softc_t, ipf_nat_rdrrules_sz), "");
627	SYSCTL_DYN_IPF_NAT(_net_inet_ipf, OID_AUTO, "ipf_hostmap_sz", CTLFLAG_RWO,
628	    NULL, offsetof(ipf_nat_softc_t, ipf_nat_hostmap_sz), "");
629	SYSCTL_DYN_IPF_AUTH(_net_inet_ipf, OID_AUTO, "fr_authsize", CTLFLAG_RWO,
630	    NULL, offsetof(ipf_auth_softc_t, ipf_auth_size), "");
631	SYSCTL_DYN_IPF_AUTH(_net_inet_ipf, OID_AUTO, "fr_authused", CTLFLAG_RD,
632	    NULL, offsetof(ipf_auth_softc_t, ipf_auth_used), "");
633	SYSCTL_DYN_IPF_AUTH(_net_inet_ipf, OID_AUTO, "fr_defaultauthage", CTLFLAG_RW,
634	    NULL, offsetof(ipf_auth_softc_t, ipf_auth_defaultage), "");
635	SYSCTL_DYN_IPF_FRAG(_net_inet_ipf, OID_AUTO, "fr_ipfrttl", CTLFLAG_RW,
636	    NULL, offsetof(ipf_frag_softc_t, ipfr_ttl), "");
637	return 0;
638}
639
640static int
641ipf_fbsd_sysctl_destroy(void)
642{
643	if (sysctl_ctx_free(&ipf_clist)) {
644		printf("sysctl_ctx_free failed");
645		return(ENOTEMPTY);
646	}
647	return 0;
648}
649
650