ip_fw_pfil.c revision 173399
1139823Simp/*-
2133920Sandre * Copyright (c) 2004 Andre Oppermann, Internet Business Solutions AG
3133920Sandre * All rights reserved.
4133920Sandre *
5133920Sandre * Redistribution and use in source and binary forms, with or without
6133920Sandre * modification, are permitted provided that the following conditions
7133920Sandre * are met:
8133920Sandre * 1. Redistributions of source code must retain the above copyright
9133920Sandre *    notice, this list of conditions and the following disclaimer.
10133920Sandre * 2. Redistributions in binary form must reproduce the above copyright
11133920Sandre *    notice, this list of conditions and the following disclaimer in the
12133920Sandre *    documentation and/or other materials provided with the distribution.
13133920Sandre *
14133920Sandre * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15133920Sandre * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16133920Sandre * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17133920Sandre * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18133920Sandre * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19133920Sandre * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20133920Sandre * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21133920Sandre * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22133920Sandre * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23133920Sandre * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24133920Sandre * SUCH DAMAGE.
25133920Sandre */
26133920Sandre
27172467Ssilby#include <sys/cdefs.h>
28172467Ssilby__FBSDID("$FreeBSD: head/sys/netinet/ip_fw_pfil.c 173399 2007-11-06 23:01:42Z oleg $");
29172467Ssilby
30134346Sru#if !defined(KLD_MODULE)
31133920Sandre#include "opt_ipfw.h"
32133920Sandre#include "opt_ipdn.h"
33133920Sandre#include "opt_inet.h"
34133920Sandre#ifndef INET
35133920Sandre#error IPFIREWALL requires INET.
36133920Sandre#endif /* INET */
37134383Sandre#endif /* KLD_MODULE */
38152928Sume#include "opt_inet6.h"
39133920Sandre
40133920Sandre#include <sys/param.h>
41133920Sandre#include <sys/systm.h>
42133920Sandre#include <sys/malloc.h>
43133920Sandre#include <sys/mbuf.h>
44133920Sandre#include <sys/module.h>
45133920Sandre#include <sys/kernel.h>
46133920Sandre#include <sys/socket.h>
47133920Sandre#include <sys/socketvar.h>
48133920Sandre#include <sys/sysctl.h>
49133920Sandre#include <sys/ucred.h>
50133920Sandre
51133920Sandre#include <net/if.h>
52133920Sandre#include <net/route.h>
53133920Sandre#include <net/pfil.h>
54133920Sandre
55133920Sandre#include <netinet/in.h>
56133920Sandre#include <netinet/in_systm.h>
57133920Sandre#include <netinet/in_var.h>
58133920Sandre#include <netinet/ip.h>
59133920Sandre#include <netinet/ip_var.h>
60133920Sandre#include <netinet/ip_fw.h>
61133920Sandre#include <netinet/ip_divert.h>
62133920Sandre#include <netinet/ip_dummynet.h>
63133920Sandre
64141351Sglebius#include <netgraph/ng_ipfw.h>
65141351Sglebius
66133920Sandre#include <machine/in_cksum.h>
67133920Sandre
68158470Smlaierint fw_enable = 1;
69158470Smlaier#ifdef INET6
70158470Smlaierint fw6_enable = 1;
71158470Smlaier#endif
72133920Sandre
73158470Smlaierint ipfw_chg_hook(SYSCTL_HANDLER_ARGS);
74158470Smlaier
75133920Sandre/* Dummynet hooks. */
76133920Sandreip_dn_ruledel_t	*ip_dn_ruledel_ptr = NULL;
77133920Sandre
78136714Sandre/* Divert hooks. */
79136714Sandreip_divert_packet_t *ip_divert_ptr = NULL;
80136714Sandre
81141351Sglebius/* ng_ipfw hooks. */
82141351Sglebiusng_ipfw_input_t *ng_ipfw_input_p = NULL;
83141351Sglebius
84136714Sandre/* Forward declarations. */
85136714Sandrestatic int	ipfw_divert(struct mbuf **, int, int);
86133920Sandre#define	DIV_DIR_IN	1
87133920Sandre#define	DIV_DIR_OUT	0
88133920Sandre
89133920Sandreint
90135920Smlaieripfw_check_in(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
91135920Smlaier    struct inpcb *inp)
92133920Sandre{
93133920Sandre	struct ip_fw_args args;
94141351Sglebius	struct ng_ipfw_tag *ng_tag;
95133920Sandre	struct m_tag *dn_tag;
96133920Sandre	int ipfw = 0;
97133920Sandre	int divert;
98140224Sglebius	int tee;
99133920Sandre#ifdef IPFIREWALL_FORWARD
100133920Sandre	struct m_tag *fwd_tag;
101133920Sandre#endif
102133920Sandre
103133920Sandre	KASSERT(dir == PFIL_IN, ("ipfw_check_in wrong direction!"));
104133920Sandre
105133920Sandre	bzero(&args, sizeof(args));
106133920Sandre
107173399Soleg	ng_tag = (struct ng_ipfw_tag *)m_tag_locate(*m0, NGM_IPFW_COOKIE, 0,
108173399Soleg	    NULL);
109173399Soleg	if (ng_tag != NULL) {
110173399Soleg		KASSERT(ng_tag->dir == NG_IPFW_IN,
111173399Soleg		    ("ng_ipfw tag with wrong direction"));
112173399Soleg		args.rule = ng_tag->rule;
113173399Soleg		m_tag_delete(*m0, (struct m_tag *)ng_tag);
114173399Soleg	}
115173399Soleg
116173399Solegagain:
117138652Sglebius	dn_tag = m_tag_find(*m0, PACKET_TAG_DUMMYNET, NULL);
118138652Sglebius	if (dn_tag != NULL){
119133920Sandre		struct dn_pkt_tag *dt;
120133920Sandre
121133920Sandre		dt = (struct dn_pkt_tag *)(dn_tag+1);
122133920Sandre		args.rule = dt->rule;
123133920Sandre
124133920Sandre		m_tag_delete(*m0, dn_tag);
125133920Sandre	}
126133920Sandre
127133920Sandre	args.m = *m0;
128135920Smlaier	args.inp = inp;
129133920Sandre	ipfw = ipfw_chk(&args);
130133920Sandre	*m0 = args.m;
131140224Sglebius	tee = 0;
132133920Sandre
133140224Sglebius	KASSERT(*m0 != NULL || ipfw == IP_FW_DENY, ("%s: m0 is NULL",
134140224Sglebius	    __func__));
135133920Sandre
136140224Sglebius	switch (ipfw) {
137140224Sglebius	case IP_FW_PASS:
138140224Sglebius		if (args.next_hop == NULL)
139140224Sglebius			goto pass;
140133920Sandre
141133920Sandre#ifdef IPFIREWALL_FORWARD
142133920Sandre		fwd_tag = m_tag_get(PACKET_TAG_IPFORWARD,
143133920Sandre				sizeof(struct sockaddr_in), M_NOWAIT);
144133920Sandre		if (fwd_tag == NULL)
145133920Sandre			goto drop;
146133920Sandre		bcopy(args.next_hop, (fwd_tag+1), sizeof(struct sockaddr_in));
147133920Sandre		m_tag_prepend(*m0, fwd_tag);
148133920Sandre
149133920Sandre		if (in_localip(args.next_hop->sin_addr))
150133920Sandre			(*m0)->m_flags |= M_FASTFWD_OURS;
151133920Sandre		goto pass;
152133920Sandre#endif
153140224Sglebius		break;			/* not reached */
154133920Sandre
155140224Sglebius	case IP_FW_DENY:
156140224Sglebius		goto drop;
157140224Sglebius		break;			/* not reached */
158140224Sglebius
159140224Sglebius	case IP_FW_DUMMYNET:
160140224Sglebius		if (!DUMMYNET_LOADED)
161140224Sglebius			goto drop;
162145246Sbrooks		if (mtod(*m0, struct ip *)->ip_v == 4)
163173399Soleg			ip_dn_io_ptr(m0, DN_TO_IP_IN, &args);
164145246Sbrooks		else if (mtod(*m0, struct ip *)->ip_v == 6)
165173399Soleg			ip_dn_io_ptr(m0, DN_TO_IP6_IN, &args);
166173399Soleg		if (*m0 != NULL)
167173399Soleg			goto again;
168140224Sglebius		return 0;		/* packet consumed */
169140224Sglebius
170140224Sglebius	case IP_FW_TEE:
171140224Sglebius		tee = 1;
172140224Sglebius		/* fall through */
173140224Sglebius
174140224Sglebius	case IP_FW_DIVERT:
175140224Sglebius		divert = ipfw_divert(m0, DIV_DIR_IN, tee);
176140224Sglebius		if (divert) {
177140224Sglebius			*m0 = NULL;
178140224Sglebius			return 0;	/* packet consumed */
179144712Sglebius		} else {
180144712Sglebius			args.rule = NULL;
181140224Sglebius			goto again;	/* continue with packet */
182144712Sglebius		}
183140224Sglebius
184141351Sglebius	case IP_FW_NGTEE:
185141351Sglebius		if (!NG_IPFW_LOADED)
186141351Sglebius			goto drop;
187141351Sglebius		(void)ng_ipfw_input_p(m0, NG_IPFW_IN, &args, 1);
188141351Sglebius		goto again;		/* continue with packet */
189141351Sglebius
190141351Sglebius	case IP_FW_NETGRAPH:
191141351Sglebius		if (!NG_IPFW_LOADED)
192141351Sglebius			goto drop;
193141351Sglebius		return ng_ipfw_input_p(m0, NG_IPFW_IN, &args, 0);
194165648Spiso
195165648Spiso	case IP_FW_NAT:
196165648Spiso		goto again;		/* continue with packet */
197141351Sglebius
198140224Sglebius	default:
199140224Sglebius		KASSERT(0, ("%s: unknown retval", __func__));
200140224Sglebius	}
201140224Sglebius
202133920Sandredrop:
203133920Sandre	if (*m0)
204133920Sandre		m_freem(*m0);
205133920Sandre	*m0 = NULL;
206133920Sandre	return (EACCES);
207133920Sandrepass:
208133920Sandre	return 0;	/* not filtered */
209133920Sandre}
210133920Sandre
211133920Sandreint
212135920Smlaieripfw_check_out(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
213135920Smlaier    struct inpcb *inp)
214133920Sandre{
215133920Sandre	struct ip_fw_args args;
216141351Sglebius	struct ng_ipfw_tag *ng_tag;
217133920Sandre	struct m_tag *dn_tag;
218133920Sandre	int ipfw = 0;
219133920Sandre	int divert;
220140224Sglebius	int tee;
221133920Sandre#ifdef IPFIREWALL_FORWARD
222133920Sandre	struct m_tag *fwd_tag;
223133920Sandre#endif
224133920Sandre
225133920Sandre	KASSERT(dir == PFIL_OUT, ("ipfw_check_out wrong direction!"));
226133920Sandre
227133920Sandre	bzero(&args, sizeof(args));
228133920Sandre
229173399Soleg	ng_tag = (struct ng_ipfw_tag *)m_tag_locate(*m0, NGM_IPFW_COOKIE, 0,
230173399Soleg	    NULL);
231173399Soleg	if (ng_tag != NULL) {
232173399Soleg		KASSERT(ng_tag->dir == NG_IPFW_OUT,
233173399Soleg		    ("ng_ipfw tag with wrong direction"));
234173399Soleg		args.rule = ng_tag->rule;
235173399Soleg		m_tag_delete(*m0, (struct m_tag *)ng_tag);
236173399Soleg	}
237173399Soleg
238173399Solegagain:
239138652Sglebius	dn_tag = m_tag_find(*m0, PACKET_TAG_DUMMYNET, NULL);
240138652Sglebius	if (dn_tag != NULL) {
241133920Sandre		struct dn_pkt_tag *dt;
242133920Sandre
243133920Sandre		dt = (struct dn_pkt_tag *)(dn_tag+1);
244133920Sandre		args.rule = dt->rule;
245133920Sandre
246133920Sandre		m_tag_delete(*m0, dn_tag);
247133920Sandre	}
248133920Sandre
249133920Sandre	args.m = *m0;
250133920Sandre	args.oif = ifp;
251135920Smlaier	args.inp = inp;
252133920Sandre	ipfw = ipfw_chk(&args);
253133920Sandre	*m0 = args.m;
254140224Sglebius	tee = 0;
255133920Sandre
256140224Sglebius	KASSERT(*m0 != NULL || ipfw == IP_FW_DENY, ("%s: m0 is NULL",
257140224Sglebius	    __func__));
258133920Sandre
259140224Sglebius	switch (ipfw) {
260140224Sglebius	case IP_FW_PASS:
261140224Sglebius                if (args.next_hop == NULL)
262140224Sglebius                        goto pass;
263133920Sandre#ifdef IPFIREWALL_FORWARD
264133920Sandre		/* Overwrite existing tag. */
265133920Sandre		fwd_tag = m_tag_find(*m0, PACKET_TAG_IPFORWARD, NULL);
266135167Sandre		if (fwd_tag == NULL) {
267133920Sandre			fwd_tag = m_tag_get(PACKET_TAG_IPFORWARD,
268133920Sandre				sizeof(struct sockaddr_in), M_NOWAIT);
269135167Sandre			if (fwd_tag == NULL)
270135167Sandre				goto drop;
271135167Sandre		} else
272135167Sandre			m_tag_unlink(*m0, fwd_tag);
273133920Sandre		bcopy(args.next_hop, (fwd_tag+1), sizeof(struct sockaddr_in));
274133920Sandre		m_tag_prepend(*m0, fwd_tag);
275133920Sandre
276133920Sandre		if (in_localip(args.next_hop->sin_addr))
277133920Sandre			(*m0)->m_flags |= M_FASTFWD_OURS;
278133920Sandre		goto pass;
279133920Sandre#endif
280140224Sglebius		break;			/* not reached */
281133920Sandre
282140224Sglebius	case IP_FW_DENY:
283140224Sglebius		goto drop;
284140224Sglebius		break;  		/* not reached */
285140224Sglebius
286140224Sglebius	case IP_FW_DUMMYNET:
287140224Sglebius		if (!DUMMYNET_LOADED)
288140224Sglebius			break;
289145246Sbrooks		if (mtod(*m0, struct ip *)->ip_v == 4)
290173399Soleg			ip_dn_io_ptr(m0, DN_TO_IP_OUT, &args);
291145246Sbrooks		else if (mtod(*m0, struct ip *)->ip_v == 6)
292173399Soleg			ip_dn_io_ptr(m0, DN_TO_IP6_OUT, &args);
293173399Soleg		if (*m0 != NULL)
294173399Soleg			goto again;
295140224Sglebius		return 0;		/* packet consumed */
296140224Sglebius
297140224Sglebius		break;
298140224Sglebius
299140224Sglebius	case IP_FW_TEE:
300140224Sglebius		tee = 1;
301140224Sglebius		/* fall through */
302140224Sglebius
303140224Sglebius	case IP_FW_DIVERT:
304140224Sglebius		divert = ipfw_divert(m0, DIV_DIR_OUT, tee);
305140224Sglebius		if (divert) {
306140224Sglebius			*m0 = NULL;
307140224Sglebius			return 0;	/* packet consumed */
308144712Sglebius		} else {
309144712Sglebius			args.rule = NULL;
310140224Sglebius			goto again;	/* continue with packet */
311144712Sglebius		}
312140224Sglebius
313141351Sglebius	case IP_FW_NGTEE:
314141351Sglebius		if (!NG_IPFW_LOADED)
315141351Sglebius			goto drop;
316141351Sglebius		(void)ng_ipfw_input_p(m0, NG_IPFW_OUT, &args, 1);
317141351Sglebius		goto again;		/* continue with packet */
318141351Sglebius
319141351Sglebius	case IP_FW_NETGRAPH:
320141351Sglebius		if (!NG_IPFW_LOADED)
321141351Sglebius			goto drop;
322141351Sglebius		return ng_ipfw_input_p(m0, NG_IPFW_OUT, &args, 0);
323141351Sglebius
324165648Spiso	case IP_FW_NAT:
325165648Spiso		goto again;		/* continue with packet */
326165648Spiso
327140224Sglebius	default:
328140224Sglebius		KASSERT(0, ("%s: unknown retval", __func__));
329140224Sglebius	}
330140224Sglebius
331133920Sandredrop:
332133920Sandre	if (*m0)
333133920Sandre		m_freem(*m0);
334133920Sandre	*m0 = NULL;
335133920Sandre	return (EACCES);
336133920Sandrepass:
337133920Sandre	return 0;	/* not filtered */
338133920Sandre}
339133920Sandre
340133920Sandrestatic int
341133920Sandreipfw_divert(struct mbuf **m, int incoming, int tee)
342133920Sandre{
343133920Sandre	/*
344135154Sandre	 * ipfw_chk() has already tagged the packet with the divert tag.
345133920Sandre	 * If tee is set, copy packet and return original.
346133920Sandre	 * If not tee, consume packet and send it to divert socket.
347133920Sandre	 */
348133920Sandre	struct mbuf *clone, *reass;
349133920Sandre	struct ip *ip;
350133920Sandre	int hlen;
351133920Sandre
352133920Sandre	reass = NULL;
353133920Sandre
354136714Sandre	/* Is divert module loaded? */
355136714Sandre	if (ip_divert_ptr == NULL)
356136714Sandre		goto nodivert;
357136714Sandre
358133920Sandre	/* Cloning needed for tee? */
359133920Sandre	if (tee)
360133920Sandre		clone = m_dup(*m, M_DONTWAIT);
361133920Sandre	else
362133920Sandre		clone = *m;
363133920Sandre
364133920Sandre	/* In case m_dup was unable to allocate mbufs. */
365133920Sandre	if (clone == NULL)
366133920Sandre		goto teeout;
367133920Sandre
368133920Sandre	/*
369133920Sandre	 * Divert listeners can only handle non-fragmented packets.
370133920Sandre	 * However when tee is set we will *not* de-fragment the packets;
371133920Sandre	 * Doing do would put the reassembly into double-jeopardy.  On top
372133920Sandre	 * of that someone doing a tee will probably want to get the packet
373133920Sandre	 * in its original form.
374133920Sandre	 */
375133920Sandre	ip = mtod(clone, struct ip *);
376133920Sandre	if (!tee && ip->ip_off & (IP_MF | IP_OFFMASK)) {
377133920Sandre
378133920Sandre		/* Reassemble packet. */
379133920Sandre		reass = ip_reass(clone);
380133920Sandre
381133920Sandre		/*
382133920Sandre		 * IP header checksum fixup after reassembly and leave header
383133920Sandre		 * in network byte order.
384133920Sandre		 */
385133920Sandre		if (reass != NULL) {
386133920Sandre			ip = mtod(reass, struct ip *);
387133920Sandre			hlen = ip->ip_hl << 2;
388133920Sandre			ip->ip_len = htons(ip->ip_len);
389133920Sandre			ip->ip_off = htons(ip->ip_off);
390133920Sandre			ip->ip_sum = 0;
391133920Sandre			if (hlen == sizeof(struct ip))
392133920Sandre				ip->ip_sum = in_cksum_hdr(ip);
393133920Sandre			else
394133920Sandre				ip->ip_sum = in_cksum(reass, hlen);
395133920Sandre			clone = reass;
396133920Sandre		} else
397133920Sandre			clone = NULL;
398133920Sandre	} else {
399133920Sandre		/* Convert header to network byte order. */
400133920Sandre		ip->ip_len = htons(ip->ip_len);
401133920Sandre		ip->ip_off = htons(ip->ip_off);
402133920Sandre	}
403133920Sandre
404133920Sandre	/* Do the dirty job... */
405136714Sandre	if (clone && ip_divert_ptr != NULL)
406136714Sandre		ip_divert_ptr(clone, incoming);
407133920Sandre
408133920Sandreteeout:
409135154Sandre	/*
410135154Sandre	 * For tee we leave the divert tag attached to original packet.
411135154Sandre	 * It will then continue rule evaluation after the tee rule.
412135154Sandre	 */
413135154Sandre	if (tee)
414135154Sandre		return 0;
415133920Sandre
416133920Sandre	/* Packet diverted and consumed */
417133920Sandre	return 1;
418136714Sandre
419136714Sandrenodivert:
420133920Sandre	m_freem(*m);
421133920Sandre	return 1;
422133920Sandre}
423133920Sandre
424133920Sandrestatic int
425133920Sandreipfw_hook(void)
426133920Sandre{
427133920Sandre	struct pfil_head *pfh_inet;
428133920Sandre
429133920Sandre	pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
430133920Sandre	if (pfh_inet == NULL)
431133920Sandre		return ENOENT;
432133920Sandre
433133920Sandre	pfil_add_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet);
434133920Sandre	pfil_add_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet);
435133920Sandre
436133920Sandre	return 0;
437133920Sandre}
438133920Sandre
439133920Sandrestatic int
440133920Sandreipfw_unhook(void)
441133920Sandre{
442133920Sandre	struct pfil_head *pfh_inet;
443133920Sandre
444133920Sandre	pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
445133920Sandre	if (pfh_inet == NULL)
446133920Sandre		return ENOENT;
447158470Smlaier
448158470Smlaier	pfil_remove_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet);
449158470Smlaier	pfil_remove_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet);
450158470Smlaier
451158470Smlaier	return 0;
452158470Smlaier}
453158470Smlaier
454145246Sbrooks#ifdef INET6
455158470Smlaierstatic int
456158470Smlaieripfw6_hook(void)
457158470Smlaier{
458158470Smlaier	struct pfil_head *pfh_inet6;
459158470Smlaier
460145246Sbrooks	pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
461145246Sbrooks	if (pfh_inet6 == NULL)
462145246Sbrooks		return ENOENT;
463133920Sandre
464158470Smlaier	pfil_add_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet6);
465158470Smlaier	pfil_add_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet6);
466158470Smlaier
467158470Smlaier	return 0;
468158470Smlaier}
469158470Smlaier
470158470Smlaierstatic int
471158470Smlaieripfw6_unhook(void)
472158470Smlaier{
473158470Smlaier	struct pfil_head *pfh_inet6;
474158470Smlaier
475158470Smlaier	pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
476158470Smlaier	if (pfh_inet6 == NULL)
477158470Smlaier		return ENOENT;
478158470Smlaier
479145246Sbrooks	pfil_remove_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet6);
480145246Sbrooks	pfil_remove_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet6);
481133920Sandre
482133920Sandre	return 0;
483133920Sandre}
484158470Smlaier#endif /* INET6 */
485133920Sandre
486158470Smlaierint
487158470Smlaieripfw_chg_hook(SYSCTL_HANDLER_ARGS)
488158470Smlaier{
489158470Smlaier	int enable = *(int *)arg1;
490158470Smlaier	int error;
491158470Smlaier
492158470Smlaier	error = sysctl_handle_int(oidp, &enable, 0, req);
493158470Smlaier	if (error)
494158470Smlaier		return (error);
495158470Smlaier
496158470Smlaier	enable = (enable) ? 1 : 0;
497158470Smlaier
498158470Smlaier	if (enable == *(int *)arg1)
499158470Smlaier		return (0);
500158470Smlaier
501158470Smlaier	if (arg1 == &fw_enable) {
502158470Smlaier		if (enable)
503158470Smlaier			error = ipfw_hook();
504158470Smlaier		else
505158470Smlaier			error = ipfw_unhook();
506158470Smlaier	}
507158470Smlaier#ifdef INET6
508158470Smlaier	if (arg1 == &fw6_enable) {
509158470Smlaier		if (enable)
510158470Smlaier			error = ipfw6_hook();
511158470Smlaier		else
512158470Smlaier			error = ipfw6_unhook();
513158470Smlaier	}
514158470Smlaier#endif
515158470Smlaier
516158470Smlaier	if (error)
517158470Smlaier		return (error);
518158470Smlaier
519158470Smlaier	*(int *)arg1 = enable;
520158470Smlaier
521158470Smlaier	return (0);
522158470Smlaier}
523158470Smlaier
524133920Sandrestatic int
525133920Sandreipfw_modevent(module_t mod, int type, void *unused)
526133920Sandre{
527133920Sandre	int err = 0;
528133920Sandre
529133920Sandre	switch (type) {
530133920Sandre	case MOD_LOAD:
531158470Smlaier		if ((err = ipfw_init()) != 0) {
532158470Smlaier			printf("ipfw_init() error\n");
533158470Smlaier			break;
534133920Sandre		}
535158470Smlaier		if ((err = ipfw_hook()) != 0) {
536158470Smlaier			printf("ipfw_hook() error\n");
537158470Smlaier			break;
538158470Smlaier		}
539158470Smlaier#ifdef INET6
540158470Smlaier		if ((err = ipfw6_hook()) != 0) {
541158470Smlaier			printf("ipfw_hook() error\n");
542158470Smlaier			break;
543158470Smlaier		}
544158470Smlaier#endif
545133920Sandre		break;
546133920Sandre
547133920Sandre	case MOD_UNLOAD:
548158470Smlaier		if ((err = ipfw_unhook()) > 0)
549158470Smlaier			break;
550158470Smlaier#ifdef INET6
551158470Smlaier		if ((err = ipfw6_unhook()) > 0)
552158470Smlaier			break;
553158470Smlaier#endif
554158470Smlaier		ipfw_destroy();
555133920Sandre		break;
556133920Sandre
557133920Sandre	default:
558133920Sandre		return EOPNOTSUPP;
559133920Sandre		break;
560133920Sandre	}
561133920Sandre	return err;
562133920Sandre}
563133920Sandre
564133920Sandrestatic moduledata_t ipfwmod = {
565133920Sandre	"ipfw",
566133920Sandre	ipfw_modevent,
567133920Sandre	0
568133920Sandre};
569133920SandreDECLARE_MODULE(ipfw, ipfwmod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY);
570133920SandreMODULE_VERSION(ipfw, 2);
571