ip_fw_pfil.c revision 196423
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/ipfw/ip_fw_pfil.c 196423 2009-08-21 11:20:10Z julian $"); 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> 46185895Szec#include <sys/lock.h> 47185895Szec#include <sys/rwlock.h> 48133920Sandre#include <sys/socket.h> 49133920Sandre#include <sys/socketvar.h> 50133920Sandre#include <sys/sysctl.h> 51133920Sandre#include <sys/ucred.h> 52133920Sandre 53133920Sandre#include <net/if.h> 54133920Sandre#include <net/route.h> 55133920Sandre#include <net/pfil.h> 56196423Sjulian#include <net/vnet.h> 57133920Sandre 58133920Sandre#include <netinet/in.h> 59133920Sandre#include <netinet/in_systm.h> 60133920Sandre#include <netinet/ip.h> 61133920Sandre#include <netinet/ip_var.h> 62133920Sandre#include <netinet/ip_fw.h> 63133920Sandre#include <netinet/ip_divert.h> 64133920Sandre#include <netinet/ip_dummynet.h> 65133920Sandre 66141351Sglebius#include <netgraph/ng_ipfw.h> 67141351Sglebius 68133920Sandre#include <machine/in_cksum.h> 69133920Sandre 70195699SrwatsonVNET_DEFINE(int, fw_enable) = 1; 71158470Smlaier#ifdef INET6 72195699SrwatsonVNET_DEFINE(int, fw6_enable) = 1; 73158470Smlaier#endif 74133920Sandre 75158470Smlaierint ipfw_chg_hook(SYSCTL_HANDLER_ARGS); 76158470Smlaier 77136714Sandre/* Divert hooks. */ 78136714Sandreip_divert_packet_t *ip_divert_ptr = NULL; 79136714Sandre 80141351Sglebius/* ng_ipfw hooks. */ 81141351Sglebiusng_ipfw_input_t *ng_ipfw_input_p = NULL; 82141351Sglebius 83136714Sandre/* Forward declarations. */ 84136714Sandrestatic int ipfw_divert(struct mbuf **, int, int); 85133920Sandre#define DIV_DIR_IN 1 86133920Sandre#define DIV_DIR_OUT 0 87133920Sandre 88133920Sandreint 89135920Smlaieripfw_check_in(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir, 90135920Smlaier struct inpcb *inp) 91133920Sandre{ 92133920Sandre struct ip_fw_args args; 93141351Sglebius struct ng_ipfw_tag *ng_tag; 94133920Sandre struct m_tag *dn_tag; 95133920Sandre int ipfw = 0; 96133920Sandre int divert; 97140224Sglebius int tee; 98133920Sandre#ifdef IPFIREWALL_FORWARD 99133920Sandre struct m_tag *fwd_tag; 100133920Sandre#endif 101133920Sandre 102133920Sandre KASSERT(dir == PFIL_IN, ("ipfw_check_in wrong direction!")); 103133920Sandre 104133920Sandre bzero(&args, sizeof(args)); 105133920Sandre 106173399Soleg ng_tag = (struct ng_ipfw_tag *)m_tag_locate(*m0, NGM_IPFW_COOKIE, 0, 107173399Soleg NULL); 108173399Soleg if (ng_tag != NULL) { 109173399Soleg KASSERT(ng_tag->dir == NG_IPFW_IN, 110173399Soleg ("ng_ipfw tag with wrong direction")); 111173399Soleg args.rule = ng_tag->rule; 112193859Soleg args.rule_id = ng_tag->rule_id; 113193859Soleg args.chain_id = ng_tag->chain_id; 114173399Soleg m_tag_delete(*m0, (struct m_tag *)ng_tag); 115173399Soleg } 116173399Soleg 117173399Solegagain: 118138652Sglebius dn_tag = m_tag_find(*m0, PACKET_TAG_DUMMYNET, NULL); 119138652Sglebius if (dn_tag != NULL){ 120133920Sandre struct dn_pkt_tag *dt; 121133920Sandre 122133920Sandre dt = (struct dn_pkt_tag *)(dn_tag+1); 123133920Sandre args.rule = dt->rule; 124193859Soleg args.rule_id = dt->rule_id; 125193859Soleg args.chain_id = dt->chain_id; 126133920Sandre 127133920Sandre m_tag_delete(*m0, dn_tag); 128133920Sandre } 129133920Sandre 130133920Sandre args.m = *m0; 131135920Smlaier args.inp = inp; 132140224Sglebius tee = 0; 133133920Sandre 134191570Soleg if (V_fw_one_pass == 0 || args.rule == NULL) { 135191570Soleg ipfw = ipfw_chk(&args); 136191570Soleg *m0 = args.m; 137191570Soleg } else 138191570Soleg ipfw = IP_FW_PASS; 139191570Soleg 140140224Sglebius KASSERT(*m0 != NULL || ipfw == IP_FW_DENY, ("%s: m0 is NULL", 141140224Sglebius __func__)); 142133920Sandre 143140224Sglebius switch (ipfw) { 144140224Sglebius case IP_FW_PASS: 145140224Sglebius if (args.next_hop == NULL) 146140224Sglebius goto pass; 147133920Sandre 148133920Sandre#ifdef IPFIREWALL_FORWARD 149133920Sandre fwd_tag = m_tag_get(PACKET_TAG_IPFORWARD, 150133920Sandre sizeof(struct sockaddr_in), M_NOWAIT); 151133920Sandre if (fwd_tag == NULL) 152133920Sandre goto drop; 153133920Sandre bcopy(args.next_hop, (fwd_tag+1), sizeof(struct sockaddr_in)); 154133920Sandre m_tag_prepend(*m0, fwd_tag); 155133920Sandre 156133920Sandre if (in_localip(args.next_hop->sin_addr)) 157133920Sandre (*m0)->m_flags |= M_FASTFWD_OURS; 158133920Sandre goto pass; 159133920Sandre#endif 160140224Sglebius break; /* not reached */ 161133920Sandre 162140224Sglebius case IP_FW_DENY: 163140224Sglebius goto drop; 164140224Sglebius break; /* not reached */ 165140224Sglebius 166140224Sglebius case IP_FW_DUMMYNET: 167193502Sluigi if (ip_dn_io_ptr == NULL) 168140224Sglebius goto drop; 169145246Sbrooks if (mtod(*m0, struct ip *)->ip_v == 4) 170173399Soleg ip_dn_io_ptr(m0, DN_TO_IP_IN, &args); 171145246Sbrooks else if (mtod(*m0, struct ip *)->ip_v == 6) 172173399Soleg ip_dn_io_ptr(m0, DN_TO_IP6_IN, &args); 173173399Soleg if (*m0 != NULL) 174173399Soleg goto again; 175140224Sglebius return 0; /* packet consumed */ 176140224Sglebius 177140224Sglebius case IP_FW_TEE: 178140224Sglebius tee = 1; 179140224Sglebius /* fall through */ 180140224Sglebius 181140224Sglebius case IP_FW_DIVERT: 182140224Sglebius divert = ipfw_divert(m0, DIV_DIR_IN, tee); 183140224Sglebius if (divert) { 184140224Sglebius *m0 = NULL; 185140224Sglebius return 0; /* packet consumed */ 186144712Sglebius } else { 187144712Sglebius args.rule = NULL; 188140224Sglebius goto again; /* continue with packet */ 189144712Sglebius } 190140224Sglebius 191141351Sglebius case IP_FW_NGTEE: 192141351Sglebius if (!NG_IPFW_LOADED) 193141351Sglebius goto drop; 194141351Sglebius (void)ng_ipfw_input_p(m0, NG_IPFW_IN, &args, 1); 195141351Sglebius goto again; /* continue with packet */ 196141351Sglebius 197141351Sglebius case IP_FW_NETGRAPH: 198141351Sglebius if (!NG_IPFW_LOADED) 199141351Sglebius goto drop; 200141351Sglebius return ng_ipfw_input_p(m0, NG_IPFW_IN, &args, 0); 201165648Spiso 202165648Spiso case IP_FW_NAT: 203165648Spiso goto again; /* continue with packet */ 204141351Sglebius 205190633Spiso case IP_FW_REASS: 206190633Spiso goto again; 207190633Spiso 208140224Sglebius default: 209140224Sglebius KASSERT(0, ("%s: unknown retval", __func__)); 210140224Sglebius } 211140224Sglebius 212133920Sandredrop: 213133920Sandre if (*m0) 214133920Sandre m_freem(*m0); 215133920Sandre *m0 = NULL; 216133920Sandre return (EACCES); 217133920Sandrepass: 218133920Sandre return 0; /* not filtered */ 219133920Sandre} 220133920Sandre 221133920Sandreint 222135920Smlaieripfw_check_out(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir, 223135920Smlaier struct inpcb *inp) 224133920Sandre{ 225133920Sandre struct ip_fw_args args; 226141351Sglebius struct ng_ipfw_tag *ng_tag; 227133920Sandre struct m_tag *dn_tag; 228133920Sandre int ipfw = 0; 229133920Sandre int divert; 230140224Sglebius int tee; 231133920Sandre#ifdef IPFIREWALL_FORWARD 232133920Sandre struct m_tag *fwd_tag; 233133920Sandre#endif 234133920Sandre 235133920Sandre KASSERT(dir == PFIL_OUT, ("ipfw_check_out wrong direction!")); 236133920Sandre 237133920Sandre bzero(&args, sizeof(args)); 238133920Sandre 239173399Soleg ng_tag = (struct ng_ipfw_tag *)m_tag_locate(*m0, NGM_IPFW_COOKIE, 0, 240173399Soleg NULL); 241173399Soleg if (ng_tag != NULL) { 242173399Soleg KASSERT(ng_tag->dir == NG_IPFW_OUT, 243173399Soleg ("ng_ipfw tag with wrong direction")); 244173399Soleg args.rule = ng_tag->rule; 245193859Soleg args.rule_id = ng_tag->rule_id; 246193859Soleg args.chain_id = ng_tag->chain_id; 247173399Soleg m_tag_delete(*m0, (struct m_tag *)ng_tag); 248173399Soleg } 249173399Soleg 250173399Solegagain: 251138652Sglebius dn_tag = m_tag_find(*m0, PACKET_TAG_DUMMYNET, NULL); 252138652Sglebius if (dn_tag != NULL) { 253133920Sandre struct dn_pkt_tag *dt; 254133920Sandre 255133920Sandre dt = (struct dn_pkt_tag *)(dn_tag+1); 256133920Sandre args.rule = dt->rule; 257193859Soleg args.rule_id = dt->rule_id; 258193859Soleg args.chain_id = dt->chain_id; 259133920Sandre 260133920Sandre m_tag_delete(*m0, dn_tag); 261133920Sandre } 262133920Sandre 263133920Sandre args.m = *m0; 264133920Sandre args.oif = ifp; 265135920Smlaier args.inp = inp; 266140224Sglebius tee = 0; 267133920Sandre 268191570Soleg if (V_fw_one_pass == 0 || args.rule == NULL) { 269191570Soleg ipfw = ipfw_chk(&args); 270191570Soleg *m0 = args.m; 271191570Soleg } else 272191570Soleg ipfw = IP_FW_PASS; 273191570Soleg 274140224Sglebius KASSERT(*m0 != NULL || ipfw == IP_FW_DENY, ("%s: m0 is NULL", 275140224Sglebius __func__)); 276133920Sandre 277140224Sglebius switch (ipfw) { 278140224Sglebius case IP_FW_PASS: 279140224Sglebius if (args.next_hop == NULL) 280140224Sglebius goto pass; 281133920Sandre#ifdef IPFIREWALL_FORWARD 282133920Sandre /* Overwrite existing tag. */ 283133920Sandre fwd_tag = m_tag_find(*m0, PACKET_TAG_IPFORWARD, NULL); 284135167Sandre if (fwd_tag == NULL) { 285133920Sandre fwd_tag = m_tag_get(PACKET_TAG_IPFORWARD, 286133920Sandre sizeof(struct sockaddr_in), M_NOWAIT); 287135167Sandre if (fwd_tag == NULL) 288135167Sandre goto drop; 289135167Sandre } else 290135167Sandre m_tag_unlink(*m0, fwd_tag); 291133920Sandre bcopy(args.next_hop, (fwd_tag+1), sizeof(struct sockaddr_in)); 292133920Sandre m_tag_prepend(*m0, fwd_tag); 293133920Sandre 294133920Sandre if (in_localip(args.next_hop->sin_addr)) 295133920Sandre (*m0)->m_flags |= M_FASTFWD_OURS; 296133920Sandre goto pass; 297133920Sandre#endif 298140224Sglebius break; /* not reached */ 299133920Sandre 300140224Sglebius case IP_FW_DENY: 301140224Sglebius goto drop; 302140224Sglebius break; /* not reached */ 303140224Sglebius 304140224Sglebius case IP_FW_DUMMYNET: 305193502Sluigi if (ip_dn_io_ptr == NULL) 306140224Sglebius break; 307145246Sbrooks if (mtod(*m0, struct ip *)->ip_v == 4) 308173399Soleg ip_dn_io_ptr(m0, DN_TO_IP_OUT, &args); 309145246Sbrooks else if (mtod(*m0, struct ip *)->ip_v == 6) 310173399Soleg ip_dn_io_ptr(m0, DN_TO_IP6_OUT, &args); 311173399Soleg if (*m0 != NULL) 312173399Soleg goto again; 313140224Sglebius return 0; /* packet consumed */ 314140224Sglebius 315140224Sglebius break; 316140224Sglebius 317140224Sglebius case IP_FW_TEE: 318140224Sglebius tee = 1; 319140224Sglebius /* fall through */ 320140224Sglebius 321140224Sglebius case IP_FW_DIVERT: 322140224Sglebius divert = ipfw_divert(m0, DIV_DIR_OUT, tee); 323140224Sglebius if (divert) { 324140224Sglebius *m0 = NULL; 325140224Sglebius return 0; /* packet consumed */ 326144712Sglebius } else { 327144712Sglebius args.rule = NULL; 328140224Sglebius goto again; /* continue with packet */ 329144712Sglebius } 330140224Sglebius 331141351Sglebius case IP_FW_NGTEE: 332141351Sglebius if (!NG_IPFW_LOADED) 333141351Sglebius goto drop; 334141351Sglebius (void)ng_ipfw_input_p(m0, NG_IPFW_OUT, &args, 1); 335141351Sglebius goto again; /* continue with packet */ 336141351Sglebius 337141351Sglebius case IP_FW_NETGRAPH: 338141351Sglebius if (!NG_IPFW_LOADED) 339141351Sglebius goto drop; 340141351Sglebius return ng_ipfw_input_p(m0, NG_IPFW_OUT, &args, 0); 341141351Sglebius 342165648Spiso case IP_FW_NAT: 343165648Spiso goto again; /* continue with packet */ 344165648Spiso 345190633Spiso case IP_FW_REASS: 346190633Spiso goto again; 347190633Spiso 348140224Sglebius default: 349140224Sglebius KASSERT(0, ("%s: unknown retval", __func__)); 350140224Sglebius } 351140224Sglebius 352133920Sandredrop: 353133920Sandre if (*m0) 354133920Sandre m_freem(*m0); 355133920Sandre *m0 = NULL; 356133920Sandre return (EACCES); 357133920Sandrepass: 358133920Sandre return 0; /* not filtered */ 359133920Sandre} 360133920Sandre 361133920Sandrestatic int 362133920Sandreipfw_divert(struct mbuf **m, int incoming, int tee) 363133920Sandre{ 364133920Sandre /* 365135154Sandre * ipfw_chk() has already tagged the packet with the divert tag. 366133920Sandre * If tee is set, copy packet and return original. 367133920Sandre * If not tee, consume packet and send it to divert socket. 368133920Sandre */ 369133920Sandre struct mbuf *clone, *reass; 370133920Sandre struct ip *ip; 371133920Sandre int hlen; 372133920Sandre 373133920Sandre reass = NULL; 374133920Sandre 375136714Sandre /* Is divert module loaded? */ 376136714Sandre if (ip_divert_ptr == NULL) 377136714Sandre goto nodivert; 378136714Sandre 379133920Sandre /* Cloning needed for tee? */ 380133920Sandre if (tee) 381133920Sandre clone = m_dup(*m, M_DONTWAIT); 382133920Sandre else 383133920Sandre clone = *m; 384133920Sandre 385133920Sandre /* In case m_dup was unable to allocate mbufs. */ 386133920Sandre if (clone == NULL) 387133920Sandre goto teeout; 388133920Sandre 389133920Sandre /* 390133920Sandre * Divert listeners can only handle non-fragmented packets. 391133920Sandre * However when tee is set we will *not* de-fragment the packets; 392133920Sandre * Doing do would put the reassembly into double-jeopardy. On top 393133920Sandre * of that someone doing a tee will probably want to get the packet 394133920Sandre * in its original form. 395133920Sandre */ 396133920Sandre ip = mtod(clone, struct ip *); 397133920Sandre if (!tee && ip->ip_off & (IP_MF | IP_OFFMASK)) { 398133920Sandre 399133920Sandre /* Reassemble packet. */ 400133920Sandre reass = ip_reass(clone); 401133920Sandre 402133920Sandre /* 403133920Sandre * IP header checksum fixup after reassembly and leave header 404133920Sandre * in network byte order. 405133920Sandre */ 406133920Sandre if (reass != NULL) { 407133920Sandre ip = mtod(reass, struct ip *); 408133920Sandre hlen = ip->ip_hl << 2; 409133920Sandre ip->ip_len = htons(ip->ip_len); 410133920Sandre ip->ip_off = htons(ip->ip_off); 411133920Sandre ip->ip_sum = 0; 412133920Sandre if (hlen == sizeof(struct ip)) 413133920Sandre ip->ip_sum = in_cksum_hdr(ip); 414133920Sandre else 415133920Sandre ip->ip_sum = in_cksum(reass, hlen); 416133920Sandre clone = reass; 417133920Sandre } else 418133920Sandre clone = NULL; 419133920Sandre } else { 420133920Sandre /* Convert header to network byte order. */ 421133920Sandre ip->ip_len = htons(ip->ip_len); 422133920Sandre ip->ip_off = htons(ip->ip_off); 423133920Sandre } 424133920Sandre 425133920Sandre /* Do the dirty job... */ 426136714Sandre if (clone && ip_divert_ptr != NULL) 427136714Sandre ip_divert_ptr(clone, incoming); 428133920Sandre 429133920Sandreteeout: 430135154Sandre /* 431135154Sandre * For tee we leave the divert tag attached to original packet. 432135154Sandre * It will then continue rule evaluation after the tee rule. 433135154Sandre */ 434135154Sandre if (tee) 435135154Sandre return 0; 436133920Sandre 437133920Sandre /* Packet diverted and consumed */ 438133920Sandre return 1; 439136714Sandre 440136714Sandrenodivert: 441133920Sandre m_freem(*m); 442133920Sandre return 1; 443133920Sandre} 444133920Sandre 445196423Sjulianint 446133920Sandreipfw_hook(void) 447133920Sandre{ 448133920Sandre struct pfil_head *pfh_inet; 449133920Sandre 450133920Sandre pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); 451133920Sandre if (pfh_inet == NULL) 452133920Sandre return ENOENT; 453133920Sandre 454186180Srwatson (void)pfil_add_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK, 455186180Srwatson pfh_inet); 456186180Srwatson (void)pfil_add_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK, 457186180Srwatson pfh_inet); 458133920Sandre 459133920Sandre return 0; 460133920Sandre} 461133920Sandre 462196423Sjulianint 463133920Sandreipfw_unhook(void) 464133920Sandre{ 465133920Sandre struct pfil_head *pfh_inet; 466133920Sandre 467133920Sandre pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); 468133920Sandre if (pfh_inet == NULL) 469133920Sandre return ENOENT; 470158470Smlaier 471186180Srwatson (void)pfil_remove_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK, 472186180Srwatson pfh_inet); 473186180Srwatson (void)pfil_remove_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK, 474186180Srwatson pfh_inet); 475158470Smlaier 476158470Smlaier return 0; 477158470Smlaier} 478158470Smlaier 479145246Sbrooks#ifdef INET6 480196423Sjulianint 481158470Smlaieripfw6_hook(void) 482158470Smlaier{ 483158470Smlaier struct pfil_head *pfh_inet6; 484158470Smlaier 485145246Sbrooks pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6); 486145246Sbrooks if (pfh_inet6 == NULL) 487145246Sbrooks return ENOENT; 488133920Sandre 489186180Srwatson (void)pfil_add_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK, 490186180Srwatson pfh_inet6); 491186180Srwatson (void)pfil_add_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK, 492186180Srwatson pfh_inet6); 493158470Smlaier 494158470Smlaier return 0; 495158470Smlaier} 496158470Smlaier 497196423Sjulianint 498158470Smlaieripfw6_unhook(void) 499158470Smlaier{ 500158470Smlaier struct pfil_head *pfh_inet6; 501158470Smlaier 502158470Smlaier pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6); 503158470Smlaier if (pfh_inet6 == NULL) 504158470Smlaier return ENOENT; 505158470Smlaier 506186180Srwatson (void)pfil_remove_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK, 507186180Srwatson pfh_inet6); 508186180Srwatson (void)pfil_remove_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK, 509186180Srwatson pfh_inet6); 510133920Sandre 511133920Sandre return 0; 512133920Sandre} 513158470Smlaier#endif /* INET6 */ 514133920Sandre 515158470Smlaierint 516158470Smlaieripfw_chg_hook(SYSCTL_HANDLER_ARGS) 517158470Smlaier{ 518158470Smlaier int enable = *(int *)arg1; 519158470Smlaier int error; 520158470Smlaier 521196423Sjulian#ifdef VIMAGE /* Since enabling is global, only let base do it. */ 522196423Sjulian if (! IS_DEFAULT_VNET(curvnet)) 523196423Sjulian return (EPERM); 524196423Sjulian#endif 525158470Smlaier error = sysctl_handle_int(oidp, &enable, 0, req); 526158470Smlaier if (error) 527158470Smlaier return (error); 528158470Smlaier 529158470Smlaier enable = (enable) ? 1 : 0; 530158470Smlaier 531158470Smlaier if (enable == *(int *)arg1) 532158470Smlaier return (0); 533158470Smlaier 534181803Sbz if (arg1 == &V_fw_enable) { 535158470Smlaier if (enable) 536158470Smlaier error = ipfw_hook(); 537158470Smlaier else 538158470Smlaier error = ipfw_unhook(); 539158470Smlaier } 540158470Smlaier#ifdef INET6 541181803Sbz if (arg1 == &V_fw6_enable) { 542158470Smlaier if (enable) 543158470Smlaier error = ipfw6_hook(); 544158470Smlaier else 545158470Smlaier error = ipfw6_unhook(); 546158470Smlaier } 547158470Smlaier#endif 548158470Smlaier 549158470Smlaier if (error) 550158470Smlaier return (error); 551158470Smlaier 552158470Smlaier *(int *)arg1 = enable; 553158470Smlaier 554158470Smlaier return (0); 555158470Smlaier} 556158470Smlaier 557