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 
49 VNET_DECLARE(ipf_main_softc_t, ipfmain);
50 #define	V_ipfmain		VNET(ipfmain)
51 
52 #ifdef __FreeBSD__
53 static struct cdev *ipf_devs[IPL_LOGSIZE];
54 #else
55 static dev_t ipf_devs[IPL_LOGSIZE];
56 #endif
57 
58 static int sysctl_ipf_int ( SYSCTL_HANDLER_ARGS );
59 static int sysctl_ipf_int_nat ( SYSCTL_HANDLER_ARGS );
60 static int sysctl_ipf_int_state ( SYSCTL_HANDLER_ARGS );
61 static int sysctl_ipf_int_auth ( SYSCTL_HANDLER_ARGS );
62 static int sysctl_ipf_int_frag ( SYSCTL_HANDLER_ARGS );
63 static int ipf_modload(void);
64 static int ipf_modunload(void);
65 static int ipf_fbsd_sysctl_create(void);
66 static int ipf_fbsd_sysctl_destroy(void);
67 
68 #ifdef __FreeBSD__
69 static	int	ipfopen(struct cdev*, int, int, struct thread *);
70 static	int	ipfclose(struct cdev*, int, int, struct thread *);
71 static	int	ipfread(struct cdev*, struct uio *, int);
72 static	int	ipfwrite(struct cdev*, struct uio *, int);
73 #else
74 static	int	ipfopen(dev_t, int, int, struct proc *);
75 static	int	ipfclose(dev_t, int, int, struct proc *);
76 static	int	ipfread(dev_t, struct uio *, int);
77 static	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 
86 SYSCTL_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)
107 static struct sysctl_ctx_list ipf_clist;
108 #define	CTLFLAG_OFF	0x00800000	/* IPFilter must be disabled */
109 #define	CTLFLAG_RWO	(CTLFLAG_RW|CTLFLAG_OFF)
110 SYSCTL_NODE(_net_inet, OID_AUTO, ipf, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
111     "IPF");
112 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_flags, CTLFLAG_RW, &VNET_NAME(ipfmain.ipf_flags), 0, "IPF flags");
113 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_pass, CTLFLAG_RW, &VNET_NAME(ipfmain.ipf_pass), 0, "default pass/block");
114 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_active, CTLFLAG_RD, &VNET_NAME(ipfmain.ipf_active), 0, "IPF is active");
115 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpidletimeout, CTLFLAG_RWO,
116 	   &VNET_NAME(ipfmain.ipf_tcpidletimeout), 0, "TCP idle timeout in seconds");
117 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcphalfclosed, CTLFLAG_RWO,
118 	   &VNET_NAME(ipfmain.ipf_tcphalfclosed), 0, "timeout for half closed TCP sessions");
119 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpclosewait, CTLFLAG_RWO,
120 	   &VNET_NAME(ipfmain.ipf_tcpclosewait), 0, "timeout for TCP sessions in closewait status");
121 SYSCTL_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");
123 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcptimeout, CTLFLAG_RWO,
124 	   &VNET_NAME(ipfmain.ipf_tcptimeout), 0, "");
125 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpclosed, CTLFLAG_RWO,
126 	   &VNET_NAME(ipfmain.ipf_tcpclosed), 0, "");
127 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_udptimeout, CTLFLAG_RWO,
128 	   &VNET_NAME(ipfmain.ipf_udptimeout), 0, "UDP timeout");
129 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_udpacktimeout, CTLFLAG_RWO,
130 	   &VNET_NAME(ipfmain.ipf_udpacktimeout), 0, "");
131 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_icmptimeout, CTLFLAG_RWO,
132 	   &VNET_NAME(ipfmain.ipf_icmptimeout), 0, "ICMP timeout");
133 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_running, CTLFLAG_RD,
134 	   &VNET_NAME(ipfmain.ipf_running), 0, "IPF is running");
135 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_chksrc, CTLFLAG_RW, &VNET_NAME(ipfmain.ipf_chksrc), 0, "");
136 SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_minttl, CTLFLAG_RW, &VNET_NAME(ipfmain.ipf_minttl), 0, "");
137 SYSCTL_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>
143 static int ipfpoll(struct cdev *dev, int events, struct thread *td);
144 
145 static 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
157 static int ipfpoll(dev_t dev, int events, struct proc *td);
158 
159 static 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 
176 static char *ipf_devfiles[] = {	IPL_NAME, IPNAT_NAME, IPSTATE_NAME, IPAUTH_NAME,
177 				IPSYNC_NAME, IPSCAN_NAME, IPLOOKUP_NAME, NULL };
178 
179 static int
ipfilter_modevent(module_t mod,int type,void * unused)180 ipfilter_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 
201 static void
vnet_ipf_init(void)202 vnet_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 }
242 VNET_SYSINIT(vnet_ipf_init, SI_SUB_PROTO_FIREWALL, SI_ORDER_THIRD,
243     vnet_ipf_init, NULL);
244 
245 static int
ipf_modload(void)246 ipf_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 
280 static void
vnet_ipf_uninit(void)281 vnet_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 }
301 VNET_SYSUNINIT(vnet_ipf_uninit, SI_SUB_PROTO_FIREWALL, SI_ORDER_THIRD,
302     vnet_ipf_uninit, NULL);
303 
304 static int
ipf_modunload(void)305 ipf_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 
330 static moduledata_t ipfiltermod = {
331 	"ipfilter",
332 	ipfilter_modevent,
333 	0
334 };
335 
336 
337 DECLARE_MODULE(ipfilter, ipfiltermod, SI_SUB_PROTO_FIREWALL, SI_ORDER_SECOND);
338 #ifdef	MODULE_VERSION
339 MODULE_VERSION(ipfilter, 1);
340 #endif
341 
342 
343 #ifdef SYSCTL_IPF
344 int
sysctl_ipf_int(SYSCTL_HANDLER_ARGS)345 sysctl_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 
366 sysctl_error:
367 	return (error);
368 }
369 
370 /*
371  * arg2 holds the offset of the relevant member in the virtualized
372  * ipfmain structure.
373  */
374 static int
sysctl_ipf_int_nat(SYSCTL_HANDLER_ARGS)375 sysctl_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 
388 static int
sysctl_ipf_int_state(SYSCTL_HANDLER_ARGS)389 sysctl_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 
402 static int
sysctl_ipf_int_auth(SYSCTL_HANDLER_ARGS)403 sysctl_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 
416 static int
sysctl_ipf_int_frag(SYSCTL_HANDLER_ARGS)417 sysctl_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 
432 static int
433 #ifdef __FreeBSD__
ipfpoll(struct cdev * dev,int events,struct thread * td)434 ipfpoll(struct cdev *dev, int events, struct thread *td)
435 #else
436 ipfpoll(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  */
485 static int
486 #ifdef __FreeBSD__
ipfopen(struct cdev * dev,int flags,int devtype,struct thread * p)487 ipfopen(struct cdev *dev, int flags, int devtype, struct thread *p)
488 #else
489 ipfopen(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 
520 static int
521 #ifdef __FreeBSD__
ipfclose(struct cdev * dev,int flags,int devtype,struct thread * p)522 ipfclose(struct cdev *dev, int flags, int devtype, struct thread *p)
523 #else
524 ipfclose(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__
ipfread(struct cdev * dev,struct uio * uio,int ioflag)543 static int ipfread(struct cdev *dev, struct uio *uio, int ioflag)
544 #else
545 static 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__
ipfwrite(struct cdev * dev,struct uio * uio,int ioflag)586 static int ipfwrite(struct cdev *dev, struct uio *uio, int ioflag)
587 #else
588 static 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 
610 static int
ipf_fbsd_sysctl_create(void)611 ipf_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 
643 static int
ipf_fbsd_sysctl_destroy(void)644 ipf_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