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