ip_fw_pfil.c revision 200580
11541Srgrimes/*-
21541Srgrimes * Copyright (c) 2004 Andre Oppermann, Internet Business Solutions AG
31541Srgrimes * All rights reserved.
41541Srgrimes *
51541Srgrimes * Redistribution and use in source and binary forms, with or without
61541Srgrimes * modification, are permitted provided that the following conditions
71541Srgrimes * are met:
81541Srgrimes * 1. Redistributions of source code must retain the above copyright
91541Srgrimes *    notice, this list of conditions and the following disclaimer.
101541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111541Srgrimes *    notice, this list of conditions and the following disclaimer in the
121541Srgrimes *    documentation and/or other materials provided with the distribution.
131541Srgrimes *
141541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
151541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
161541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
171541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
181541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
191541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
201541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
211541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
221541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
231541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
241541Srgrimes * SUCH DAMAGE.
251541Srgrimes */
261541Srgrimes
271541Srgrimes#include <sys/cdefs.h>
281541Srgrimes__FBSDID("$FreeBSD: head/sys/netinet/ipfw/ip_fw_pfil.c 200580 2009-12-15 16:15:14Z luigi $");
291541Srgrimes
301541Srgrimes#if !defined(KLD_MODULE)
311541Srgrimes#include "opt_ipfw.h"
321541Srgrimes#include "opt_ipdn.h"
331541Srgrimes#include "opt_inet.h"
3450477Speter#ifndef INET
351541Srgrimes#error IPFIREWALL requires INET.
361541Srgrimes#endif /* INET */
3732358Seivind#endif /* KLD_MODULE */
3816333Sgpalmer#include "opt_inet6.h"
3941793Sluigi
4030966Sjoerg#include <sys/param.h>
4134746Speter#include <sys/systm.h>
4250561Sdes#include <sys/malloc.h>
4355009Sshin#include <sys/mbuf.h>
44101095Srwatson#include <sys/module.h>
4564060Sdarrenr#include <sys/kernel.h>
4677574Skris#include <sys/lock.h>
4716333Sgpalmer#include <sys/rwlock.h>
481541Srgrimes#include <sys/socket.h>
491541Srgrimes#include <sys/socketvar.h>
50101095Srwatson#include <sys/sysctl.h>
511541Srgrimes#include <sys/ucred.h>
5241793Sluigi
531541Srgrimes#include <net/if.h>
541541Srgrimes#include <net/route.h>
551541Srgrimes#include <net/pfil.h>
561541Srgrimes#include <net/vnet.h>
571541Srgrimes
587091Swollman#include <netinet/in.h>
597090Sbde#include <netinet/in_systm.h>
601541Srgrimes#include <netinet/ip.h>
6164075Sache#include <netinet/ip_var.h>
621541Srgrimes#include <netinet/ip_fw.h>
6383934Sbrooks#include <netinet/ipfw/ip_fw_private.h>
6430948Sjulian#include <netinet/ip_divert.h>
6519622Sfenner#include <netinet/ip_dummynet.h>
661541Srgrimes
678426Swollman#include <netgraph/ng_ipfw.h>
681541Srgrimes
691541Srgrimes#include <machine/in_cksum.h>
701541Srgrimes
717090SbdeVNET_DEFINE(int, fw_enable) = 1;
721541Srgrimes#ifdef INET6
731541SrgrimesVNET_DEFINE(int, fw6_enable) = 1;
741541Srgrimes#endif
751541Srgrimes
7618797Swollmanint ipfw_chg_hook(SYSCTL_HANDLER_ARGS);
771541Srgrimes
782531Swollman/* Divert hooks. */
7915680Sgpalmerip_divert_packet_t *ip_divert_ptr = NULL;
8015680Sgpalmer
8184516Sps/* ng_ipfw hooks. */
8215680Sgpalmerng_ipfw_input_t *ng_ipfw_input_p = NULL;
8355009Sshin
8455009Sshin/* Forward declarations. */
8555009Sshinstatic int	ipfw_divert(struct mbuf **, int, int);
8655009Sshin#define	DIV_DIR_IN	1
8755009Sshin#define	DIV_DIR_OUT	0
88105199Ssam
89105199Ssamint
90105199Ssamipfw_check_in(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
91105199Ssam    struct inpcb *inp)
92105199Ssam{
939209Swollman	struct ip_fw_args args;
942531Swollman	struct ng_ipfw_tag *ng_tag;
9536192Sdg	struct m_tag *dn_tag;
9612296Sphk	int ipfw = 0;
9746381Sbillf	int divert;
9812296Sphk	int tee;
9913266Swollman#ifdef IPFIREWALL_FORWARD
10012296Sphk	struct m_tag *fwd_tag;
10146381Sbillf#endif
10212296Sphk
1031541Srgrimes	KASSERT(dir == PFIL_IN, ("ipfw_check_in wrong direction!"));
10412296Sphk
10546381Sbillf	bzero(&args, sizeof(args));
10612296Sphk
10712296Sphk	ng_tag = (struct ng_ipfw_tag *)m_tag_locate(*m0, NGM_IPFW_COOKIE, 0,
10812296Sphk	    NULL);
10946381Sbillf	if (ng_tag != NULL) {
11033440Sguido		KASSERT(ng_tag->dir == NG_IPFW_IN,
11133440Sguido		    ("ng_ipfw tag with wrong direction"));
11246381Sbillf		args.rule = ng_tag->rule;
11346381Sbillf		args.rule_id = ng_tag->rule_id;
11446381Sbillf		args.chain_id = ng_tag->chain_id;
11555009Sshin		m_tag_delete(*m0, (struct m_tag *)ng_tag);
11655009Sshin	}
11755009Sshin
11855009Sshinagain:
11955009Sshin	dn_tag = m_tag_find(*m0, PACKET_TAG_DUMMYNET, NULL);
12055009Sshin	if (dn_tag != NULL){
121109843Ssilby		struct dn_pkt_tag *dt;
122109843Ssilby
12377665Sjesper		dt = (struct dn_pkt_tag *)(dn_tag+1);
124109843Ssilby		args.rule = dt->rule;
12577665Sjesper		args.rule_id = dt->rule_id;
12677665Sjesper		args.chain_id = dt->chain_id;
127111244Ssilby
128111244Ssilby		m_tag_delete(*m0, dn_tag);
129111244Ssilby	}
130111244Ssilby
131111244Ssilby	args.m = *m0;
132107081Ssilby	args.inp = inp;
133107081Ssilby	tee = 0;
134107081Ssilby
135107081Ssilby	if (V_fw_one_pass == 0 || args.rule == NULL) {
136107081Ssilby		ipfw = ipfw_chk(&args);
13773399Struckman		*m0 = args.m;
13873399Struckman	} else
13973399Struckman		ipfw = IP_FW_PASS;
14073791Struckman
14173399Struckman	KASSERT(*m0 != NULL || ipfw == IP_FW_DENY, ("%s: m0 is NULL",
14273626Struckman	    __func__));
14373791Struckman
14473791Struckman	switch (ipfw) {
14573626Struckman	case IP_FW_PASS:
14673626Struckman		if (args.next_hop == NULL)
14773626Struckman			goto pass;
14873626Struckman
14973399Struckman#ifdef IPFIREWALL_FORWARD
15073357Sjlemon		fwd_tag = m_tag_get(PACKET_TAG_IPFORWARD,
15173357Sjlemon				sizeof(struct sockaddr_in), M_NOWAIT);
15273357Sjlemon		if (fwd_tag == NULL)
15373357Sjlemon			goto drop;
1541541Srgrimes		bcopy(args.next_hop, (fwd_tag+1), sizeof(struct sockaddr_in));
15512296Sphk		m_tag_prepend(*m0, fwd_tag);
1561541Srgrimes
157120386Ssam		if (in_localip(args.next_hop->sin_addr))
158120386Ssam			(*m0)->m_flags |= M_FASTFWD_OURS;
159120386Ssam		goto pass;
1601541Srgrimes#endif
161111888Sjlemon		break;			/* not reached */
16284102Sjlemon
16384102Sjlemon	case IP_FW_DENY:
1641541Srgrimes		goto drop;
16582884Sjulian		break;			/* not reached */
1661541Srgrimes
16784102Sjlemon	case IP_FW_DUMMYNET:
16884102Sjlemon		if (ip_dn_io_ptr == NULL)
16984102Sjlemon			goto drop;
17084102Sjlemon		if (mtod(*m0, struct ip *)->ip_v == 4)
17147546Sdg			ip_dn_io_ptr(m0, DN_TO_IP_IN, &args);
17246381Sbillf		else if (mtod(*m0, struct ip *)->ip_v == 6)
17312296Sphk			ip_dn_io_ptr(m0, DN_TO_IP6_IN, &args);
17446381Sbillf		if (*m0 != NULL)
1751541Srgrimes			goto again;
1762112Swollman		return 0;		/* packet consumed */
17778667Sru
17846381Sbillf	case IP_FW_TEE:
1792112Swollman		tee = 1;
18029480Sache		/* fall through */
18129480Sache
18229480Sache	case IP_FW_DIVERT:
18329480Sache		divert = ipfw_divert(m0, DIV_DIR_IN, tee);
18429480Sache		if (divert) {
18543305Sdillon			*m0 = NULL;
18629480Sache			return 0;	/* packet consumed */
18774362Sphk		} else {
188119753Ssam			args.rule = NULL;
18929480Sache			goto again;	/* continue with packet */
190119753Ssam		}
191119753Ssam
192121091Ssam	case IP_FW_NGTEE:
193121091Ssam		if (!NG_IPFW_LOADED)
194119753Ssam			goto drop;
19512296Sphk		(void)ng_ipfw_input_p(m0, NG_IPFW_IN, &args, 1);
19612296Sphk		goto again;		/* continue with packet */
19746381Sbillf
19812296Sphk	case IP_FW_NETGRAPH:
19912296Sphk		if (!NG_IPFW_LOADED)
20044219Sdes			goto drop;
20144219Sdes		return ng_ipfw_input_p(m0, NG_IPFW_IN, &args, 0);
20244219Sdes
20344219Sdes	case IP_FW_NAT:
20444219Sdes		goto again;		/* continue with packet */
20544219Sdes
20618797Swollman	case IP_FW_REASS:
20715026Sphk		goto again;
20815026Sphk
20957117Sluigi	default:
210107114Sluigi		KASSERT(0, ("%s: unknown retval", __func__));
21114209Sphk	}
21284516Sps
21384516Spsdrop:
21441793Sluigi	if (*m0)
215121093Ssam		m_freem(*m0);
216121093Ssam	*m0 = NULL;
217121093Ssam	return (EACCES);
218121093Ssampass:
219121093Ssam	return 0;	/* not filtered */
220121093Ssam}
221121093Ssam
22222531Sdarrenrint
223121093Ssamipfw_check_out(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
224121093Ssam    struct inpcb *inp)
225121093Ssam{
226121093Ssam	struct ip_fw_args args;
227121093Ssam	struct ng_ipfw_tag *ng_tag;
228121093Ssam	struct m_tag *dn_tag;
22914209Sphk	int ipfw = 0;
230121093Ssam	int divert;
231121093Ssam	int tee;
232121093Ssam#ifdef IPFIREWALL_FORWARD
233121093Ssam	struct m_tag *fwd_tag;
234121093Ssam#endif
235121093Ssam
236121119Ssam	KASSERT(dir == PFIL_OUT, ("ipfw_check_out wrong direction!"));
237121093Ssam
238121093Ssam	bzero(&args, sizeof(args));
239121093Ssam
240121093Ssam	ng_tag = (struct ng_ipfw_tag *)m_tag_locate(*m0, NGM_IPFW_COOKIE, 0,
241121093Ssam	    NULL);
242121093Ssam	if (ng_tag != NULL) {
243121119Ssam		KASSERT(ng_tag->dir == NG_IPFW_OUT,
244121093Ssam		    ("ng_ipfw tag with wrong direction"));
245121093Ssam		args.rule = ng_tag->rule;
246121093Ssam		args.rule_id = ng_tag->rule_id;
247121093Ssam		args.chain_id = ng_tag->chain_id;
248121119Ssam		m_tag_delete(*m0, (struct m_tag *)ng_tag);
249121093Ssam	}
250121093Ssam
25198701Sluigiagain:
25298701Sluigi	dn_tag = m_tag_find(*m0, PACKET_TAG_DUMMYNET, NULL);
25398701Sluigi	if (dn_tag != NULL) {
25498701Sluigi		struct dn_pkt_tag *dt;
25598701Sluigi
25698701Sluigi		dt = (struct dn_pkt_tag *)(dn_tag+1);
2571541Srgrimes		args.rule = dt->rule;
2581541Srgrimes		args.rule_id = dt->rule_id;
2591541Srgrimes		args.chain_id = dt->chain_id;
2601541Srgrimes
2611541Srgrimes		m_tag_delete(*m0, dn_tag);
2621541Srgrimes	}
26312296Sphk
2641541Srgrimes	args.m = *m0;
2651541Srgrimes	args.oif = ifp;
2661541Srgrimes	args.inp = inp;
2671541Srgrimes	tee = 0;
2681541Srgrimes
2691541Srgrimes	if (V_fw_one_pass == 0 || args.rule == NULL) {
2701541Srgrimes		ipfw = ipfw_chk(&args);
27192723Salfred		*m0 = args.m;
27298613Sluigi	} else
27398613Sluigi		ipfw = IP_FW_PASS;
274121093Ssam
27598613Sluigi	KASSERT(*m0 != NULL || ipfw == IP_FW_DENY, ("%s: m0 is NULL",
27692723Salfred	    __func__));
27798613Sluigi
27898613Sluigi	switch (ipfw) {
27917072Sjulian	case IP_FW_PASS:
2801541Srgrimes                if (args.next_hop == NULL)
2811541Srgrimes                        goto pass;
2821541Srgrimes#ifdef IPFIREWALL_FORWARD
2831541Srgrimes		/* Overwrite existing tag. */
2841541Srgrimes		fwd_tag = m_tag_find(*m0, PACKET_TAG_IPFORWARD, NULL);
2851541Srgrimes		if (fwd_tag == NULL) {
2861541Srgrimes			fwd_tag = m_tag_get(PACKET_TAG_IPFORWARD,
28782884Sjulian				sizeof(struct sockaddr_in), M_NOWAIT);
2881541Srgrimes			if (fwd_tag == NULL)
2891541Srgrimes				goto drop;
29020407Swollman		} else
29184102Sjlemon			m_tag_unlink(*m0, fwd_tag);
29282884Sjulian		bcopy(args.next_hop, (fwd_tag+1), sizeof(struct sockaddr_in));
2931541Srgrimes		m_tag_prepend(*m0, fwd_tag);
2941541Srgrimes
2951541Srgrimes		if (in_localip(args.next_hop->sin_addr))
2961541Srgrimes			(*m0)->m_flags |= M_FASTFWD_OURS;
29782884Sjulian		goto pass;
29882884Sjulian#endif
2991541Srgrimes		break;			/* not reached */
3001541Srgrimes
3011541Srgrimes	case IP_FW_DENY:
30229480Sache		goto drop;
303120386Ssam		break;  		/* not reached */
304120386Ssam
305120386Ssam	case IP_FW_DUMMYNET:
306120386Ssam		if (ip_dn_io_ptr == NULL)
307120386Ssam			break;
308120386Ssam		if (mtod(*m0, struct ip *)->ip_v == 4)
309120386Ssam			ip_dn_io_ptr(m0, DN_TO_IP_OUT, &args);
310120386Ssam		else if (mtod(*m0, struct ip *)->ip_v == 6)
311119753Ssam			ip_dn_io_ptr(m0, DN_TO_IP6_OUT, &args);
31229480Sache		if (*m0 != NULL)
31374362Sphk			goto again;
31429480Sache		return 0;		/* packet consumed */
315121093Ssam
316121093Ssam		break;
317121093Ssam
318111244Ssilby	case IP_FW_TEE:
319111244Ssilby		tee = 1;
32029480Sache		/* fall through */
32177574Skris
32234961Sphk	case IP_FW_DIVERT:
32377574Skris		divert = ipfw_divert(m0, DIV_DIR_OUT, tee);
3241541Srgrimes		if (divert) {
32593818Sjhb			*m0 = NULL;
326111888Sjlemon			return 0;	/* packet consumed */
3271541Srgrimes		} else {
3281541Srgrimes			args.rule = NULL;
32998701Sluigi			goto again;	/* continue with packet */
330121093Ssam		}
33198701Sluigi
332121093Ssam	case IP_FW_NGTEE:
333121093Ssam		if (!NG_IPFW_LOADED)
334121093Ssam			goto drop;
335121093Ssam		(void)ng_ipfw_input_p(m0, NG_IPFW_OUT, &args, 1);
3361541Srgrimes		goto again;		/* continue with packet */
337121093Ssam
338121093Ssam	case IP_FW_NETGRAPH:
339121093Ssam		if (!NG_IPFW_LOADED)
340121093Ssam			goto drop;
341121093Ssam		return ng_ipfw_input_p(m0, NG_IPFW_OUT, &args, 0);
342121093Ssam
343121093Ssam	case IP_FW_NAT:
344121093Ssam		goto again;		/* continue with packet */
345121093Ssam
3461541Srgrimes	case IP_FW_REASS:
3471541Srgrimes		goto again;
3481541Srgrimes
3491541Srgrimes	default:
35013929Swollman		KASSERT(0, ("%s: unknown retval", __func__));
35113929Swollman	}
3521541Srgrimes
35315026Sphkdrop:
35415026Sphk	if (*m0)
35567334Sjoe		m_freem(*m0);
35684102Sjlemon	*m0 = NULL;
35773399Struckman	return (EACCES);
35822333Sbrianpass:
35973172Sjlemon	return 0;	/* not filtered */
36054175Sarchie}
36198613Sluigi
362121093Ssamstatic int
363121141Ssamipfw_divert(struct mbuf **m, int incoming, int tee)
364121141Ssam{
365121141Ssam	/*
366121141Ssam	 * ipfw_chk() has already tagged the packet with the divert tag.
367105199Ssam	 * If tee is set, copy packet and return original.
368105199Ssam	 * If not tee, consume packet and send it to divert socket.
369105199Ssam	 */
370105199Ssam	struct mbuf *clone, *reass;
371105199Ssam	struct ip *ip;
372105199Ssam	int hlen;
3731541Srgrimes
37498613Sluigi	reass = NULL;
37598613Sluigi
37698613Sluigi	/* Is divert module loaded? */
37798613Sluigi	if (ip_divert_ptr == NULL)
37898613Sluigi		goto nodivert;
37954175Sarchie
38098666Sluigi	/* Cloning needed for tee? */
38198666Sluigi	if (tee)
382105194Ssam		clone = m_dup(*m, M_DONTWAIT);
38398613Sluigi	else
38498613Sluigi		clone = *m;
385105194Ssam
38698613Sluigi	/* In case m_dup was unable to allocate mbufs. */
38741793Sluigi	if (clone == NULL)
38898613Sluigi		goto teeout;
38998613Sluigi
39098613Sluigi	/*
39198613Sluigi	 * Divert listeners can only handle non-fragmented packets.
39298613Sluigi	 * However when tee is set we will *not* de-fragment the packets;
39398904Smux	 * Doing do would put the reassembly into double-jeopardy.  On top
39498613Sluigi	 * of that someone doing a tee will probably want to get the packet
39598613Sluigi	 * in its original form.
39698613Sluigi	 */
39798613Sluigi	ip = mtod(clone, struct ip *);
39898613Sluigi	if (!tee && ip->ip_off & (IP_MF | IP_OFFMASK)) {
39998613Sluigi
40098666Sluigi		/* Reassemble packet. */
40198613Sluigi		reass = ip_reass(clone);
402113255Sdes
40397074Sarr		/*
40498613Sluigi		 * IP header checksum fixup after reassembly and leave header
40598613Sluigi		 * in network byte order.
406105586Sphk		 */
40798613Sluigi		if (reass != NULL) {
40898613Sluigi			ip = mtod(reass, struct ip *);
40998613Sluigi			hlen = ip->ip_hl << 2;
4101541Srgrimes			ip->ip_len = htons(ip->ip_len);
41118797Swollman			ip->ip_off = htons(ip->ip_off);
41218797Swollman			ip->ip_sum = 0;
41318797Swollman			if (hlen == sizeof(struct ip))
41418797Swollman				ip->ip_sum = in_cksum_hdr(ip);
4151541Srgrimes			else
4161541Srgrimes				ip->ip_sum = in_cksum(reass, hlen);
4171541Srgrimes			clone = reass;
41813929Swollman		} else
4191541Srgrimes			clone = NULL;
4201541Srgrimes	} else {
42118797Swollman		/* Convert header to network byte order. */
422105586Sphk		ip->ip_len = htons(ip->ip_len);
4231541Srgrimes		ip->ip_off = htons(ip->ip_off);
4241541Srgrimes	}
4251541Srgrimes
42618797Swollman	/* Do the dirty job... */
427105586Sphk	if (clone && ip_divert_ptr != NULL)
4281541Srgrimes		ip_divert_ptr(clone, incoming);
4291541Srgrimes
4301541Srgrimesteeout:
4311541Srgrimes	/*
4321541Srgrimes	 * For tee we leave the divert tag attached to original packet.
4331541Srgrimes	 * It will then continue rule evaluation after the tee rule.
4341541Srgrimes	 */
43513929Swollman	if (tee)
4361541Srgrimes		return 0;
4371541Srgrimes
4381541Srgrimes	/* Packet diverted and consumed */
43978064Sume	return 1;
44078064Sume
44178064Sumenodivert:
44278064Sume	m_freem(*m);
44378064Sume	return 1;
44478064Sume}
44578064Sume
44678064Sumeint
44778064Sumeipfw_hook(void)
44878064Sume{
44958698Sjlemon	struct pfil_head *pfh_inet;
45058698Sjlemon
45118797Swollman	pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
45258698Sjlemon	if (pfh_inet == NULL)
45358698Sjlemon		return ENOENT;
45458698Sjlemon
45558698Sjlemon	(void)pfil_add_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK,
45658698Sjlemon	    pfh_inet);
45718797Swollman	(void)pfil_add_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK,
45822333Sbrian	    pfh_inet);
4591541Srgrimes
4601541Srgrimes	return 0;
4611541Srgrimes}
4621541Srgrimes
4631541Srgrimesint
4641541Srgrimesipfw_unhook(void)
4651541Srgrimes{
46690868Smike	struct pfil_head *pfh_inet;
4671541Srgrimes
4681541Srgrimes	pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
4691541Srgrimes	if (pfh_inet == NULL)
4701541Srgrimes		return ENOENT;
47190868Smike
4721541Srgrimes	(void)pfil_remove_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK,
4731541Srgrimes	    pfh_inet);
4741541Srgrimes	(void)pfil_remove_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK,
4751541Srgrimes	    pfh_inet);
4761541Srgrimes
4771541Srgrimes	return 0;
4781541Srgrimes}
4791541Srgrimes
48018797Swollman#ifdef INET6
4811541Srgrimesint
4821541Srgrimesipfw6_hook(void)
4831541Srgrimes{
4841541Srgrimes	struct pfil_head *pfh_inet6;
4851541Srgrimes
4861541Srgrimes	pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
4871541Srgrimes	if (pfh_inet6 == NULL)
4881541Srgrimes		return ENOENT;
4891541Srgrimes
4901541Srgrimes	(void)pfil_add_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK,
491111275Ssam	    pfh_inet6);
492111275Ssam	(void)pfil_add_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK,
493111275Ssam	    pfh_inet6);
494111275Ssam
495111275Ssam	return 0;
496111275Ssam}
497111275Ssam
498117897Ssamint
499117897Ssamipfw6_unhook(void)
500117897Ssam{
501117897Ssam	struct pfil_head *pfh_inet6;
502117897Ssam
503117897Ssam	pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
504117897Ssam	if (pfh_inet6 == NULL)
50573626Struckman		return ENOENT;
50673626Struckman
5075543Sugen	(void)pfil_remove_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK,
5085543Sugen	    pfh_inet6);
5095543Sugen	(void)pfil_remove_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK,
5105543Sugen	    pfh_inet6);
51117072Sjulian
51217758Ssos	return 0;
51341793Sluigi}
5145543Sugen#endif /* INET6 */
5155543Sugen
5165543Sugenint
51741793Sluigiipfw_chg_hook(SYSCTL_HANDLER_ARGS)
51841793Sluigi{
51964060Sdarrenr	int enable;
52064060Sdarrenr	int oldenable;
52124590Sdarrenr	int error;
522120386Ssam
523121141Ssam	if (arg1 == &VNET_NAME(fw_enable)) {
524121141Ssam		enable = V_fw_enable;
525121141Ssam	}
526121141Ssam#ifdef INET6
52724590Sdarrenr	else if (arg1 == &VNET_NAME(fw6_enable)) {
528121141Ssam		enable = V_fw6_enable;
529120386Ssam	}
530120386Ssam#endif
531120386Ssam	else
532120386Ssam		return (EINVAL);
533120386Ssam
534120386Ssam	oldenable = enable;
535121141Ssam
53664060Sdarrenr	error = sysctl_handle_int(oidp, &enable, 0, req);
5371541Srgrimes
53886047Sluigi	if (error)
53937409Sjulian		return (error);
54037409Sjulian
54137409Sjulian	enable = (enable) ? 1 : 0;
54237409Sjulian
54398613Sluigi	if (enable == oldenable)
54437409Sjulian		return (0);
54598613Sluigi
54698613Sluigi	if (arg1 == &VNET_NAME(fw_enable)) {
54798613Sluigi		if (enable)
54898613Sluigi			error = ipfw_hook();
54998613Sluigi		else
55096245Sluigi			error = ipfw_unhook();
55187915Sjlemon		if (error)
55287915Sjlemon			return (error);
55387915Sjlemon		V_fw_enable = enable;
55471909Sluigi	}
55596245Sluigi#ifdef INET6
55698613Sluigi	else if (arg1 == &VNET_NAME(fw6_enable)) {
55754175Sarchie		if (enable)
55886047Sluigi			error = ipfw6_hook();
55998666Sluigi		else
56098666Sluigi			error = ipfw6_unhook();
56154175Sarchie		if (error)
56241793Sluigi			return (error);
56326359Sjulian		V_fw6_enable = enable;
56454175Sarchie	}
56554175Sarchie#endif
56654175Sarchie
56726359Sjulian	return (0);
56826359Sjulian}
56941793Sluigi
57098613Sluigi