13b3a8eb9SGleb Smirnoff /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3fe267a55SPedro F. Giffuni *
43b3a8eb9SGleb Smirnoff * Copyright (c) 2004 Andre Oppermann, Internet Business Solutions AG
53b3a8eb9SGleb Smirnoff * All rights reserved.
63b3a8eb9SGleb Smirnoff *
73b3a8eb9SGleb Smirnoff * Redistribution and use in source and binary forms, with or without
83b3a8eb9SGleb Smirnoff * modification, are permitted provided that the following conditions
93b3a8eb9SGleb Smirnoff * are met:
103b3a8eb9SGleb Smirnoff * 1. Redistributions of source code must retain the above copyright
113b3a8eb9SGleb Smirnoff * notice, this list of conditions and the following disclaimer.
123b3a8eb9SGleb Smirnoff * 2. Redistributions in binary form must reproduce the above copyright
133b3a8eb9SGleb Smirnoff * notice, this list of conditions and the following disclaimer in the
143b3a8eb9SGleb Smirnoff * documentation and/or other materials provided with the distribution.
153b3a8eb9SGleb Smirnoff *
163b3a8eb9SGleb Smirnoff * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
173b3a8eb9SGleb Smirnoff * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
183b3a8eb9SGleb Smirnoff * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
193b3a8eb9SGleb Smirnoff * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
203b3a8eb9SGleb Smirnoff * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
213b3a8eb9SGleb Smirnoff * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
223b3a8eb9SGleb Smirnoff * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
233b3a8eb9SGleb Smirnoff * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
243b3a8eb9SGleb Smirnoff * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
253b3a8eb9SGleb Smirnoff * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
263b3a8eb9SGleb Smirnoff * SUCH DAMAGE.
273b3a8eb9SGleb Smirnoff */
283b3a8eb9SGleb Smirnoff
293b3a8eb9SGleb Smirnoff #include <sys/cdefs.h>
303b3a8eb9SGleb Smirnoff #include "opt_ipfw.h"
313b3a8eb9SGleb Smirnoff #include "opt_inet.h"
323b3a8eb9SGleb Smirnoff #include "opt_inet6.h"
333b3a8eb9SGleb Smirnoff #ifndef INET
343b3a8eb9SGleb Smirnoff #error IPFIREWALL requires INET.
353b3a8eb9SGleb Smirnoff #endif /* INET */
363b3a8eb9SGleb Smirnoff
373b3a8eb9SGleb Smirnoff #include <sys/param.h>
383b3a8eb9SGleb Smirnoff #include <sys/systm.h>
393b3a8eb9SGleb Smirnoff #include <sys/malloc.h>
403b3a8eb9SGleb Smirnoff #include <sys/mbuf.h>
413b3a8eb9SGleb Smirnoff #include <sys/module.h>
423b3a8eb9SGleb Smirnoff #include <sys/kernel.h>
433b3a8eb9SGleb Smirnoff #include <sys/lock.h>
443b3a8eb9SGleb Smirnoff #include <sys/rwlock.h>
453b3a8eb9SGleb Smirnoff #include <sys/socket.h>
463b3a8eb9SGleb Smirnoff #include <sys/sysctl.h>
473b3a8eb9SGleb Smirnoff
483b3a8eb9SGleb Smirnoff #include <net/if.h>
49b252313fSGleb Smirnoff #include <net/if_var.h>
503b3a8eb9SGleb Smirnoff #include <net/route.h>
513b3a8eb9SGleb Smirnoff #include <net/ethernet.h>
523b3a8eb9SGleb Smirnoff #include <net/pfil.h>
533b3a8eb9SGleb Smirnoff #include <net/vnet.h>
543b3a8eb9SGleb Smirnoff
553b3a8eb9SGleb Smirnoff #include <netinet/in.h>
563b3a8eb9SGleb Smirnoff #include <netinet/in_systm.h>
573b3a8eb9SGleb Smirnoff #include <netinet/ip.h>
583b3a8eb9SGleb Smirnoff #include <netinet/ip_var.h>
593b3a8eb9SGleb Smirnoff #include <netinet/ip_fw.h>
603b3a8eb9SGleb Smirnoff #ifdef INET6
613b3a8eb9SGleb Smirnoff #include <netinet/ip6.h>
623b3a8eb9SGleb Smirnoff #include <netinet6/ip6_var.h>
632530ed9eSAndrey V. Elsukov #include <netinet6/scope6_var.h>
643b3a8eb9SGleb Smirnoff #endif
653b3a8eb9SGleb Smirnoff
663b3a8eb9SGleb Smirnoff #include <netgraph/ng_ipfw.h>
673b3a8eb9SGleb Smirnoff
683b3a8eb9SGleb Smirnoff #include <netpfil/ipfw/ip_fw_private.h>
693b3a8eb9SGleb Smirnoff
703b3a8eb9SGleb Smirnoff #include <machine/in_cksum.h>
713b3a8eb9SGleb Smirnoff
725f901c92SAndrew Turner VNET_DEFINE_STATIC(int, fw_enable) = 1;
733b3a8eb9SGleb Smirnoff #define V_fw_enable VNET(fw_enable)
743b3a8eb9SGleb Smirnoff
753b3a8eb9SGleb Smirnoff #ifdef INET6
765f901c92SAndrew Turner VNET_DEFINE_STATIC(int, fw6_enable) = 1;
773b3a8eb9SGleb Smirnoff #define V_fw6_enable VNET(fw6_enable)
783b3a8eb9SGleb Smirnoff #endif
793b3a8eb9SGleb Smirnoff
805f901c92SAndrew Turner VNET_DEFINE_STATIC(int, fwlink_enable) = 0;
813b3a8eb9SGleb Smirnoff #define V_fwlink_enable VNET(fwlink_enable)
823b3a8eb9SGleb Smirnoff
833b3a8eb9SGleb Smirnoff int ipfw_chg_hook(SYSCTL_HANDLER_ARGS);
843b3a8eb9SGleb Smirnoff
853b3a8eb9SGleb Smirnoff /* Forward declarations. */
86b00b7e03SGleb Smirnoff static int ipfw_divert(struct mbuf **, struct ip_fw_args *, bool);
873b3a8eb9SGleb Smirnoff
883b3a8eb9SGleb Smirnoff #ifdef SYSCTL_NODE
893b3a8eb9SGleb Smirnoff
903b3a8eb9SGleb Smirnoff SYSBEGIN(f1)
913b3a8eb9SGleb Smirnoff
923b3a8eb9SGleb Smirnoff SYSCTL_DECL(_net_inet_ip_fw);
936df8a710SGleb Smirnoff SYSCTL_PROC(_net_inet_ip_fw, OID_AUTO, enable,
9449197c39SZhenlei Huang CTLFLAG_VNET | CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_NOFETCH | CTLFLAG_SECURE3 |
957029da5cSPawel Biernacki CTLFLAG_NEEDGIANT, &VNET_NAME(fw_enable), 0, ipfw_chg_hook, "I",
967029da5cSPawel Biernacki "Enable ipfw");
973b3a8eb9SGleb Smirnoff #ifdef INET6
983b3a8eb9SGleb Smirnoff SYSCTL_DECL(_net_inet6_ip6_fw);
996df8a710SGleb Smirnoff SYSCTL_PROC(_net_inet6_ip6_fw, OID_AUTO, enable,
10049197c39SZhenlei Huang CTLFLAG_VNET | CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_NOFETCH | CTLFLAG_SECURE3 |
1017029da5cSPawel Biernacki CTLFLAG_NEEDGIANT, &VNET_NAME(fw6_enable), 0, ipfw_chg_hook, "I",
1027029da5cSPawel Biernacki "Enable ipfw+6");
1033b3a8eb9SGleb Smirnoff #endif /* INET6 */
1043b3a8eb9SGleb Smirnoff
1053b3a8eb9SGleb Smirnoff SYSCTL_DECL(_net_link_ether);
1066df8a710SGleb Smirnoff SYSCTL_PROC(_net_link_ether, OID_AUTO, ipfw,
10749197c39SZhenlei Huang CTLFLAG_VNET | CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_NOFETCH | CTLFLAG_SECURE3 |
1087029da5cSPawel Biernacki CTLFLAG_NEEDGIANT, &VNET_NAME(fwlink_enable), 0, ipfw_chg_hook, "I",
1096df8a710SGleb Smirnoff "Pass ether pkts through firewall");
1103b3a8eb9SGleb Smirnoff
1113b3a8eb9SGleb Smirnoff SYSEND
1123b3a8eb9SGleb Smirnoff
1133b3a8eb9SGleb Smirnoff #endif /* SYSCTL_NODE */
1143b3a8eb9SGleb Smirnoff
1153b3a8eb9SGleb Smirnoff /*
1163b3a8eb9SGleb Smirnoff * The pfilter hook to pass packets to ipfw_chk and then to
1173b3a8eb9SGleb Smirnoff * dummynet, divert, netgraph or other modules.
1183b3a8eb9SGleb Smirnoff * The packet may be consumed.
1193b3a8eb9SGleb Smirnoff */
120b252313fSGleb Smirnoff static pfil_return_t
ipfw_check_packet(struct mbuf ** m0,struct ifnet * ifp,int flags,void * ruleset __unused,struct inpcb * inp)121b7795b67SGleb Smirnoff ipfw_check_packet(struct mbuf **m0, struct ifnet *ifp, int flags,
122b252313fSGleb Smirnoff void *ruleset __unused, struct inpcb *inp)
1233b3a8eb9SGleb Smirnoff {
1243b3a8eb9SGleb Smirnoff struct ip_fw_args args;
1253b3a8eb9SGleb Smirnoff struct m_tag *tag;
126b252313fSGleb Smirnoff pfil_return_t ret;
127dc0fa4f7SGleb Smirnoff int ipfw;
1283b3a8eb9SGleb Smirnoff
129b7795b67SGleb Smirnoff args.flags = (flags & PFIL_IN) ? IPFW_ARGS_IN : IPFW_ARGS_OUT;
130*ff1aec7cSAndrey V. Elsukov args.rule.pkt_mark = 0;
1313b3a8eb9SGleb Smirnoff again:
1323b3a8eb9SGleb Smirnoff /*
1333b3a8eb9SGleb Smirnoff * extract and remove the tag if present. If we are left
1343b3a8eb9SGleb Smirnoff * with onepass, optimize the outgoing path.
1353b3a8eb9SGleb Smirnoff */
1363b3a8eb9SGleb Smirnoff tag = m_tag_locate(*m0, MTAG_IPFW_RULE, 0, NULL);
1373b3a8eb9SGleb Smirnoff if (tag != NULL) {
1383b3a8eb9SGleb Smirnoff args.rule = *((struct ipfw_rule_ref *)(tag+1));
1393b3a8eb9SGleb Smirnoff m_tag_delete(*m0, tag);
1408f35d5f3SGleb Smirnoff if (args.rule.info & IPFW_ONEPASS)
1411854fb8fSDag-Erling Smørgrav return (PFIL_PASS);
1421cdf23bcSAndrey V. Elsukov args.flags |= IPFW_ARGS_REF;
1433b3a8eb9SGleb Smirnoff }
1443b3a8eb9SGleb Smirnoff
1453b3a8eb9SGleb Smirnoff args.m = *m0;
146b7795b67SGleb Smirnoff args.ifp = ifp;
1473b3a8eb9SGleb Smirnoff args.inp = inp;
1483b3a8eb9SGleb Smirnoff
1493b3a8eb9SGleb Smirnoff ipfw = ipfw_chk(&args);
1503b3a8eb9SGleb Smirnoff *m0 = args.m;
1513b3a8eb9SGleb Smirnoff
152b11efc1eSAndrey V. Elsukov KASSERT(*m0 != NULL || ipfw == IP_FW_DENY ||
153b11efc1eSAndrey V. Elsukov ipfw == IP_FW_NAT64, ("%s: m0 is NULL", __func__));
1543b3a8eb9SGleb Smirnoff
155b252313fSGleb Smirnoff ret = PFIL_PASS;
1563b3a8eb9SGleb Smirnoff switch (ipfw) {
1573b3a8eb9SGleb Smirnoff case IP_FW_PASS:
1583b3a8eb9SGleb Smirnoff /* next_hop may be set by ipfw_chk */
1591cdf23bcSAndrey V. Elsukov if ((args.flags & (IPFW_ARGS_NH4 | IPFW_ARGS_NH4PTR |
160b252313fSGleb Smirnoff IPFW_ARGS_NH6 | IPFW_ARGS_NH6PTR)) == 0)
1611cdf23bcSAndrey V. Elsukov break;
162c1de64a4SAndrey V. Elsukov #if (!defined(INET6) && !defined(INET))
163b252313fSGleb Smirnoff ret = PFIL_DROPPED;
1643b3a8eb9SGleb Smirnoff #else
1653b3a8eb9SGleb Smirnoff {
1661cdf23bcSAndrey V. Elsukov void *psa;
1673b3a8eb9SGleb Smirnoff size_t len;
1683b3a8eb9SGleb Smirnoff #ifdef INET
1691cdf23bcSAndrey V. Elsukov if (args.flags & (IPFW_ARGS_NH4 | IPFW_ARGS_NH4PTR)) {
1701cdf23bcSAndrey V. Elsukov MPASS((args.flags & (IPFW_ARGS_NH4 |
1711cdf23bcSAndrey V. Elsukov IPFW_ARGS_NH4PTR)) != (IPFW_ARGS_NH4 |
1721cdf23bcSAndrey V. Elsukov IPFW_ARGS_NH4PTR));
1731cdf23bcSAndrey V. Elsukov MPASS((args.flags & (IPFW_ARGS_NH6 |
1741cdf23bcSAndrey V. Elsukov IPFW_ARGS_NH6PTR)) == 0);
1753b3a8eb9SGleb Smirnoff len = sizeof(struct sockaddr_in);
1761cdf23bcSAndrey V. Elsukov psa = (args.flags & IPFW_ARGS_NH4) ?
1771cdf23bcSAndrey V. Elsukov &args.hopstore : args.next_hop;
1781cdf23bcSAndrey V. Elsukov if (in_localip(satosin(psa)->sin_addr))
1791cdf23bcSAndrey V. Elsukov (*m0)->m_flags |= M_FASTFWD_OURS;
1801cdf23bcSAndrey V. Elsukov (*m0)->m_flags |= M_IP_NEXTHOP;
1811cdf23bcSAndrey V. Elsukov }
1821cdf23bcSAndrey V. Elsukov #endif /* INET */
1831cdf23bcSAndrey V. Elsukov #ifdef INET6
1841cdf23bcSAndrey V. Elsukov if (args.flags & (IPFW_ARGS_NH6 | IPFW_ARGS_NH6PTR)) {
1851cdf23bcSAndrey V. Elsukov MPASS((args.flags & (IPFW_ARGS_NH6 |
1861cdf23bcSAndrey V. Elsukov IPFW_ARGS_NH6PTR)) != (IPFW_ARGS_NH6 |
1871cdf23bcSAndrey V. Elsukov IPFW_ARGS_NH6PTR));
1881cdf23bcSAndrey V. Elsukov MPASS((args.flags & (IPFW_ARGS_NH4 |
1891cdf23bcSAndrey V. Elsukov IPFW_ARGS_NH4PTR)) == 0);
1901cdf23bcSAndrey V. Elsukov len = sizeof(struct sockaddr_in6);
1911cdf23bcSAndrey V. Elsukov psa = args.next_hop6;
1921cdf23bcSAndrey V. Elsukov (*m0)->m_flags |= M_IP6_NEXTHOP;
1931cdf23bcSAndrey V. Elsukov }
1941cdf23bcSAndrey V. Elsukov #endif /* INET6 */
1951cdf23bcSAndrey V. Elsukov /*
1961cdf23bcSAndrey V. Elsukov * Incoming packets should not be tagged so we do not
1973b3a8eb9SGleb Smirnoff * m_tag_find. Outgoing packets may be tagged, so we
1983b3a8eb9SGleb Smirnoff * reuse the tag if present.
1993b3a8eb9SGleb Smirnoff */
200b7795b67SGleb Smirnoff tag = (flags & PFIL_IN) ? NULL :
2013b3a8eb9SGleb Smirnoff m_tag_find(*m0, PACKET_TAG_IPFORWARD, NULL);
2021cdf23bcSAndrey V. Elsukov if (tag != NULL) {
2031cdf23bcSAndrey V. Elsukov m_tag_unlink(*m0, tag);
2043b3a8eb9SGleb Smirnoff } else {
2051cdf23bcSAndrey V. Elsukov tag = m_tag_get(PACKET_TAG_IPFORWARD, len,
2063b3a8eb9SGleb Smirnoff M_NOWAIT);
2071cdf23bcSAndrey V. Elsukov if (tag == NULL) {
208b252313fSGleb Smirnoff ret = PFIL_DROPPED;
209b252313fSGleb Smirnoff break;
2103b3a8eb9SGleb Smirnoff }
2113b3a8eb9SGleb Smirnoff }
2121cdf23bcSAndrey V. Elsukov if ((args.flags & IPFW_ARGS_NH6) == 0)
2131cdf23bcSAndrey V. Elsukov bcopy(psa, tag + 1, len);
2141cdf23bcSAndrey V. Elsukov m_tag_prepend(*m0, tag);
2151854fb8fSDag-Erling Smørgrav ret = PFIL_PASS;
2163b3a8eb9SGleb Smirnoff #ifdef INET6
2171cdf23bcSAndrey V. Elsukov /* IPv6 next hop needs additional handling */
2181cdf23bcSAndrey V. Elsukov if (args.flags & (IPFW_ARGS_NH6 | IPFW_ARGS_NH6PTR)) {
2192530ed9eSAndrey V. Elsukov struct sockaddr_in6 *sa6;
2202530ed9eSAndrey V. Elsukov
2211cdf23bcSAndrey V. Elsukov sa6 = satosin6(tag + 1);
2221cdf23bcSAndrey V. Elsukov if (args.flags & IPFW_ARGS_NH6) {
2231cdf23bcSAndrey V. Elsukov sa6->sin6_family = AF_INET6;
2241cdf23bcSAndrey V. Elsukov sa6->sin6_len = sizeof(*sa6);
2251cdf23bcSAndrey V. Elsukov sa6->sin6_addr = args.hopstore6.sin6_addr;
2261cdf23bcSAndrey V. Elsukov sa6->sin6_port = args.hopstore6.sin6_port;
2271cdf23bcSAndrey V. Elsukov sa6->sin6_scope_id =
2281cdf23bcSAndrey V. Elsukov args.hopstore6.sin6_scope_id;
2291cdf23bcSAndrey V. Elsukov }
2302530ed9eSAndrey V. Elsukov /*
2312530ed9eSAndrey V. Elsukov * If nh6 address is link-local we should convert
2322530ed9eSAndrey V. Elsukov * it to kernel internal form before doing any
2332530ed9eSAndrey V. Elsukov * comparisons.
2342530ed9eSAndrey V. Elsukov */
2352530ed9eSAndrey V. Elsukov if (sa6_embedscope(sa6, V_ip6_use_defzone) != 0) {
236b252313fSGleb Smirnoff ret = PFIL_DROPPED;
2372530ed9eSAndrey V. Elsukov break;
2382530ed9eSAndrey V. Elsukov }
2392530ed9eSAndrey V. Elsukov if (in6_localip(&sa6->sin6_addr))
2403b3a8eb9SGleb Smirnoff (*m0)->m_flags |= M_FASTFWD_OURS;
2413b3a8eb9SGleb Smirnoff }
2421cdf23bcSAndrey V. Elsukov #endif /* INET6 */
2433b3a8eb9SGleb Smirnoff }
244c1de64a4SAndrey V. Elsukov #endif /* INET || INET6 */
2453b3a8eb9SGleb Smirnoff break;
2463b3a8eb9SGleb Smirnoff
2473b3a8eb9SGleb Smirnoff case IP_FW_DENY:
248b252313fSGleb Smirnoff ret = PFIL_DROPPED;
249b252313fSGleb Smirnoff break;
2503b3a8eb9SGleb Smirnoff
2513b3a8eb9SGleb Smirnoff case IP_FW_DUMMYNET:
252b252313fSGleb Smirnoff if (ip_dn_io_ptr == NULL) {
253b252313fSGleb Smirnoff ret = PFIL_DROPPED;
254b252313fSGleb Smirnoff break;
255b252313fSGleb Smirnoff }
2563b1522c2SAndrey V. Elsukov MPASS(args.flags & IPFW_ARGS_REF);
257dc0fa4f7SGleb Smirnoff if (args.flags & (IPFW_ARGS_IP4 | IPFW_ARGS_IP6))
258dc0fa4f7SGleb Smirnoff (void )ip_dn_io_ptr(m0, &args);
259b252313fSGleb Smirnoff else {
260b252313fSGleb Smirnoff ret = PFIL_DROPPED;
261b252313fSGleb Smirnoff break;
262b252313fSGleb Smirnoff }
2633b3a8eb9SGleb Smirnoff /*
2643b3a8eb9SGleb Smirnoff * XXX should read the return value.
2653b3a8eb9SGleb Smirnoff * dummynet normally eats the packet and sets *m0=NULL
2663b3a8eb9SGleb Smirnoff * unless the packet can be sent immediately. In this
2673b3a8eb9SGleb Smirnoff * case args is updated and we should re-run the
2683b3a8eb9SGleb Smirnoff * check without clearing args.
2693b3a8eb9SGleb Smirnoff */
2703b3a8eb9SGleb Smirnoff if (*m0 != NULL)
2713b3a8eb9SGleb Smirnoff goto again;
272b252313fSGleb Smirnoff ret = PFIL_CONSUMED;
2733b3a8eb9SGleb Smirnoff break;
2743b3a8eb9SGleb Smirnoff
2753b3a8eb9SGleb Smirnoff case IP_FW_TEE:
2763b3a8eb9SGleb Smirnoff case IP_FW_DIVERT:
2773b3a8eb9SGleb Smirnoff if (ip_divert_ptr == NULL) {
278b252313fSGleb Smirnoff ret = PFIL_DROPPED;
279b252313fSGleb Smirnoff break;
2803b3a8eb9SGleb Smirnoff }
2813b1522c2SAndrey V. Elsukov MPASS(args.flags & IPFW_ARGS_REF);
282b00b7e03SGleb Smirnoff (void )ipfw_divert(m0, &args, ipfw == IP_FW_TEE);
2833b3a8eb9SGleb Smirnoff /* continue processing for the original packet (tee). */
2843b3a8eb9SGleb Smirnoff if (*m0)
2853b3a8eb9SGleb Smirnoff goto again;
286b252313fSGleb Smirnoff ret = PFIL_CONSUMED;
2873b3a8eb9SGleb Smirnoff break;
2883b3a8eb9SGleb Smirnoff
2893b3a8eb9SGleb Smirnoff case IP_FW_NGTEE:
2903b3a8eb9SGleb Smirnoff case IP_FW_NETGRAPH:
2913b3a8eb9SGleb Smirnoff if (ng_ipfw_input_p == NULL) {
292b252313fSGleb Smirnoff ret = PFIL_DROPPED;
293b252313fSGleb Smirnoff break;
2943b3a8eb9SGleb Smirnoff }
2953b1522c2SAndrey V. Elsukov MPASS(args.flags & IPFW_ARGS_REF);
296cef9f220SGleb Smirnoff (void )ng_ipfw_input_p(m0, &args, ipfw == IP_FW_NGTEE);
2973b3a8eb9SGleb Smirnoff if (ipfw == IP_FW_NGTEE) /* ignore errors for NGTEE */
2983b3a8eb9SGleb Smirnoff goto again; /* continue with packet */
299b252313fSGleb Smirnoff ret = PFIL_CONSUMED;
3003b3a8eb9SGleb Smirnoff break;
3013b3a8eb9SGleb Smirnoff
3023b3a8eb9SGleb Smirnoff case IP_FW_NAT:
3033b3a8eb9SGleb Smirnoff /* honor one-pass in case of successful nat */
304b252313fSGleb Smirnoff if (V_fw_one_pass)
3051cdf23bcSAndrey V. Elsukov break;
3063b3a8eb9SGleb Smirnoff goto again;
3073b3a8eb9SGleb Smirnoff
3083b3a8eb9SGleb Smirnoff case IP_FW_REASS:
3093b3a8eb9SGleb Smirnoff goto again; /* continue with packet */
3103b3a8eb9SGleb Smirnoff
311ca0f03e8SAndrey V. Elsukov case IP_FW_NAT64:
312ca0f03e8SAndrey V. Elsukov ret = PFIL_CONSUMED;
313ca0f03e8SAndrey V. Elsukov break;
314ca0f03e8SAndrey V. Elsukov
3153b3a8eb9SGleb Smirnoff default:
3163b3a8eb9SGleb Smirnoff KASSERT(0, ("%s: unknown retval", __func__));
3173b3a8eb9SGleb Smirnoff }
3183b3a8eb9SGleb Smirnoff
319b252313fSGleb Smirnoff if (ret != PFIL_PASS) {
3203b3a8eb9SGleb Smirnoff if (*m0)
3213b3a8eb9SGleb Smirnoff FREE_PKT(*m0);
3223b3a8eb9SGleb Smirnoff *m0 = NULL;
3233b3a8eb9SGleb Smirnoff }
32421d172a3SGleb Smirnoff
3251cdf23bcSAndrey V. Elsukov return (ret);
3263b3a8eb9SGleb Smirnoff }
3273b3a8eb9SGleb Smirnoff
3283b3a8eb9SGleb Smirnoff /*
329caf32b26SGleb Smirnoff * ipfw processing for ethernet packets (in and out), mbuf version.
3303b3a8eb9SGleb Smirnoff */
331b252313fSGleb Smirnoff static pfil_return_t
ipfw_check_frame_mbuf(struct mbuf ** m0,struct ifnet * ifp,const int flags,void * ruleset __unused,struct inpcb * inp)332caf32b26SGleb Smirnoff ipfw_check_frame_mbuf(struct mbuf **m0, struct ifnet *ifp, const int flags,
333b252313fSGleb Smirnoff void *ruleset __unused, struct inpcb *inp)
3343b3a8eb9SGleb Smirnoff {
335caf32b26SGleb Smirnoff struct ip_fw_args args = {
336caf32b26SGleb Smirnoff .flags = IPFW_ARGS_ETHER |
337caf32b26SGleb Smirnoff ((flags & PFIL_IN) ? IPFW_ARGS_IN : IPFW_ARGS_OUT),
338caf32b26SGleb Smirnoff .ifp = ifp,
339caf32b26SGleb Smirnoff .inp = inp,
340caf32b26SGleb Smirnoff };
341caf32b26SGleb Smirnoff struct m_tag *mtag;
342b252313fSGleb Smirnoff pfil_return_t ret;
343f355cb3eSGleb Smirnoff int ipfw;
3443b3a8eb9SGleb Smirnoff
3455310c191SEugene Grosbein again:
346f355cb3eSGleb Smirnoff /*
347f355cb3eSGleb Smirnoff * Fetch start point from rule, if any.
348f355cb3eSGleb Smirnoff * Remove the tag if present.
349f355cb3eSGleb Smirnoff */
350caf32b26SGleb Smirnoff mtag = m_tag_locate(*m0, MTAG_IPFW_RULE, 0, NULL);
3515310c191SEugene Grosbein if (mtag != NULL) {
352e4014585SLuiz Otavio O Souza args.rule = *((struct ipfw_rule_ref *)(mtag+1));
353caf32b26SGleb Smirnoff m_tag_delete(*m0, mtag);
354e4014585SLuiz Otavio O Souza if (args.rule.info & IPFW_ONEPASS)
355f355cb3eSGleb Smirnoff return (PFIL_PASS);
3561cdf23bcSAndrey V. Elsukov args.flags |= IPFW_ARGS_REF;
3573b3a8eb9SGleb Smirnoff }
358fc727ad6SBoris Lytochkin args.m = *m0;
3593b3a8eb9SGleb Smirnoff
360f355cb3eSGleb Smirnoff ipfw = ipfw_chk(&args);
361caf32b26SGleb Smirnoff *m0 = args.m;
3623b3a8eb9SGleb Smirnoff
363b252313fSGleb Smirnoff ret = PFIL_PASS;
364f355cb3eSGleb Smirnoff switch (ipfw) {
3653b3a8eb9SGleb Smirnoff case IP_FW_PASS:
3663b3a8eb9SGleb Smirnoff break;
3673b3a8eb9SGleb Smirnoff
3683b3a8eb9SGleb Smirnoff case IP_FW_DENY:
369b252313fSGleb Smirnoff ret = PFIL_DROPPED;
370b252313fSGleb Smirnoff break;
3713b3a8eb9SGleb Smirnoff
3723b3a8eb9SGleb Smirnoff case IP_FW_DUMMYNET:
373b252313fSGleb Smirnoff if (ip_dn_io_ptr == NULL) {
374b252313fSGleb Smirnoff ret = PFIL_DROPPED;
375b252313fSGleb Smirnoff break;
376b252313fSGleb Smirnoff }
3773b1522c2SAndrey V. Elsukov MPASS(args.flags & IPFW_ARGS_REF);
378caf32b26SGleb Smirnoff ip_dn_io_ptr(m0, &args);
379b252313fSGleb Smirnoff return (PFIL_CONSUMED);
3803b3a8eb9SGleb Smirnoff
3815310c191SEugene Grosbein case IP_FW_NGTEE:
3825310c191SEugene Grosbein case IP_FW_NETGRAPH:
3835310c191SEugene Grosbein if (ng_ipfw_input_p == NULL) {
384b252313fSGleb Smirnoff ret = PFIL_DROPPED;
385b252313fSGleb Smirnoff break;
3865310c191SEugene Grosbein }
3873b1522c2SAndrey V. Elsukov MPASS(args.flags & IPFW_ARGS_REF);
388caf32b26SGleb Smirnoff (void )ng_ipfw_input_p(m0, &args, ipfw == IP_FW_NGTEE);
389f355cb3eSGleb Smirnoff if (ipfw == IP_FW_NGTEE) /* ignore errors for NGTEE */
3905310c191SEugene Grosbein goto again; /* continue with packet */
391b252313fSGleb Smirnoff ret = PFIL_CONSUMED;
3925310c191SEugene Grosbein break;
3935310c191SEugene Grosbein
3943b3a8eb9SGleb Smirnoff default:
3953b3a8eb9SGleb Smirnoff KASSERT(0, ("%s: unknown retval", __func__));
3963b3a8eb9SGleb Smirnoff }
3973b3a8eb9SGleb Smirnoff
398caf32b26SGleb Smirnoff if (ret != PFIL_PASS) {
399caf32b26SGleb Smirnoff if (*m0)
400caf32b26SGleb Smirnoff FREE_PKT(*m0);
401caf32b26SGleb Smirnoff *m0 = NULL;
4023b3a8eb9SGleb Smirnoff }
4033b3a8eb9SGleb Smirnoff
404caf32b26SGleb Smirnoff return (ret);
405caf32b26SGleb Smirnoff }
406caf32b26SGleb Smirnoff
407caf32b26SGleb Smirnoff /*
408caf32b26SGleb Smirnoff * ipfw processing for ethernet packets (in and out), memory pointer version,
409caf32b26SGleb Smirnoff * two in/out accessors.
410caf32b26SGleb Smirnoff */
411caf32b26SGleb Smirnoff static pfil_return_t
ipfw_check_frame_mem(void * mem,u_int len,int flags,struct ifnet * ifp,void * ruleset __unused,struct mbuf ** m)412caf32b26SGleb Smirnoff ipfw_check_frame_mem(void *mem, u_int len, int flags, struct ifnet *ifp,
413caf32b26SGleb Smirnoff void *ruleset __unused, struct mbuf **m)
414caf32b26SGleb Smirnoff {
415caf32b26SGleb Smirnoff struct ip_fw_args args = {
416caf32b26SGleb Smirnoff .flags = len | IPFW_ARGS_ETHER |
417caf32b26SGleb Smirnoff ((flags & PFIL_IN) ? IPFW_ARGS_IN : IPFW_ARGS_OUT),
418caf32b26SGleb Smirnoff .ifp = ifp,
419caf32b26SGleb Smirnoff .mem = mem,
420caf32b26SGleb Smirnoff };
421caf32b26SGleb Smirnoff pfil_return_t ret;
422caf32b26SGleb Smirnoff int ipfw;
423caf32b26SGleb Smirnoff
424caf32b26SGleb Smirnoff *m = NULL;
425caf32b26SGleb Smirnoff again:
426caf32b26SGleb Smirnoff ipfw = ipfw_chk(&args);
427caf32b26SGleb Smirnoff
428caf32b26SGleb Smirnoff ret = PFIL_PASS;
429caf32b26SGleb Smirnoff switch (ipfw) {
430caf32b26SGleb Smirnoff case IP_FW_PASS:
431caf32b26SGleb Smirnoff break;
432caf32b26SGleb Smirnoff
433caf32b26SGleb Smirnoff case IP_FW_DENY:
434caf32b26SGleb Smirnoff ret = PFIL_DROPPED;
435caf32b26SGleb Smirnoff break;
436caf32b26SGleb Smirnoff
437caf32b26SGleb Smirnoff case IP_FW_DUMMYNET:
438caf32b26SGleb Smirnoff if (ip_dn_io_ptr == NULL) {
439caf32b26SGleb Smirnoff ret = PFIL_DROPPED;
440caf32b26SGleb Smirnoff break;
441caf32b26SGleb Smirnoff }
442caf32b26SGleb Smirnoff *m = m_devget(mem, len, 0, ifp, NULL);
443caf32b26SGleb Smirnoff if (*m == NULL) {
444caf32b26SGleb Smirnoff ret = PFIL_DROPPED;
445caf32b26SGleb Smirnoff break;
446caf32b26SGleb Smirnoff }
447caf32b26SGleb Smirnoff MPASS(args.flags & IPFW_ARGS_REF);
448caf32b26SGleb Smirnoff ip_dn_io_ptr(m, &args);
449caf32b26SGleb Smirnoff return (PFIL_CONSUMED);
450caf32b26SGleb Smirnoff
451caf32b26SGleb Smirnoff case IP_FW_NGTEE:
452caf32b26SGleb Smirnoff case IP_FW_NETGRAPH:
453caf32b26SGleb Smirnoff if (ng_ipfw_input_p == NULL) {
454caf32b26SGleb Smirnoff ret = PFIL_DROPPED;
455caf32b26SGleb Smirnoff break;
456caf32b26SGleb Smirnoff }
457caf32b26SGleb Smirnoff *m = m_devget(mem, len, 0, ifp, NULL);
458caf32b26SGleb Smirnoff if (*m == NULL) {
459caf32b26SGleb Smirnoff ret = PFIL_DROPPED;
460caf32b26SGleb Smirnoff break;
461caf32b26SGleb Smirnoff }
462caf32b26SGleb Smirnoff MPASS(args.flags & IPFW_ARGS_REF);
463caf32b26SGleb Smirnoff (void )ng_ipfw_input_p(m, &args, ipfw == IP_FW_NGTEE);
464caf32b26SGleb Smirnoff if (ipfw == IP_FW_NGTEE) /* ignore errors for NGTEE */
465caf32b26SGleb Smirnoff goto again; /* continue with packet */
466caf32b26SGleb Smirnoff ret = PFIL_CONSUMED;
467caf32b26SGleb Smirnoff break;
468caf32b26SGleb Smirnoff
469caf32b26SGleb Smirnoff default:
470caf32b26SGleb Smirnoff KASSERT(0, ("%s: unknown retval", __func__));
471caf32b26SGleb Smirnoff }
472caf32b26SGleb Smirnoff
473caf32b26SGleb Smirnoff if (*m != NULL && ret == PFIL_PASS)
474f355cb3eSGleb Smirnoff ret = PFIL_REALLOCED;
475f355cb3eSGleb Smirnoff
4761cdf23bcSAndrey V. Elsukov return (ret);
4773b3a8eb9SGleb Smirnoff }
4783b3a8eb9SGleb Smirnoff
4793b3a8eb9SGleb Smirnoff /* do the divert, return 1 on error 0 on success */
4803b3a8eb9SGleb Smirnoff static int
ipfw_divert(struct mbuf ** m0,struct ip_fw_args * args,bool tee)481b00b7e03SGleb Smirnoff ipfw_divert(struct mbuf **m0, struct ip_fw_args *args, bool tee)
4823b3a8eb9SGleb Smirnoff {
4833b3a8eb9SGleb Smirnoff /*
4843b3a8eb9SGleb Smirnoff * ipfw_chk() has already tagged the packet with the divert tag.
4853b3a8eb9SGleb Smirnoff * If tee is set, copy packet and return original.
4863b3a8eb9SGleb Smirnoff * If not tee, consume packet and send it to divert socket.
4873b3a8eb9SGleb Smirnoff */
4883b3a8eb9SGleb Smirnoff struct mbuf *clone;
4893b3a8eb9SGleb Smirnoff struct ip *ip = mtod(*m0, struct ip *);
4903b3a8eb9SGleb Smirnoff struct m_tag *tag;
4913b3a8eb9SGleb Smirnoff
4923b3a8eb9SGleb Smirnoff /* Cloning needed for tee? */
493b00b7e03SGleb Smirnoff if (tee == false) {
4943b3a8eb9SGleb Smirnoff clone = *m0; /* use the original mbuf */
4953b3a8eb9SGleb Smirnoff *m0 = NULL;
4963b3a8eb9SGleb Smirnoff } else {
497eb1b1807SGleb Smirnoff clone = m_dup(*m0, M_NOWAIT);
4983b3a8eb9SGleb Smirnoff /* If we cannot duplicate the mbuf, we sacrifice the divert
4993b3a8eb9SGleb Smirnoff * chain and continue with the tee-ed packet.
5003b3a8eb9SGleb Smirnoff */
5013b3a8eb9SGleb Smirnoff if (clone == NULL)
5023b3a8eb9SGleb Smirnoff return 1;
5033b3a8eb9SGleb Smirnoff }
5043b3a8eb9SGleb Smirnoff
5053b3a8eb9SGleb Smirnoff /*
5063b3a8eb9SGleb Smirnoff * Divert listeners can normally handle non-fragmented packets,
5073b3a8eb9SGleb Smirnoff * but we can only reass in the non-tee case.
5083b3a8eb9SGleb Smirnoff * This means that listeners on a tee rule may get fragments,
5093b3a8eb9SGleb Smirnoff * and have to live with that.
5103b3a8eb9SGleb Smirnoff * Note that we now have the 'reass' ipfw option so if we care
5113b3a8eb9SGleb Smirnoff * we can do it before a 'tee'.
5123b3a8eb9SGleb Smirnoff */
513b00b7e03SGleb Smirnoff if (tee == false) switch (ip->ip_v) {
5143b3a8eb9SGleb Smirnoff case IPVERSION:
5153b3a8eb9SGleb Smirnoff if (ntohs(ip->ip_off) & (IP_MF | IP_OFFMASK)) {
5163b3a8eb9SGleb Smirnoff int hlen;
5173b3a8eb9SGleb Smirnoff struct mbuf *reass;
5183b3a8eb9SGleb Smirnoff
5193b3a8eb9SGleb Smirnoff reass = ip_reass(clone); /* Reassemble packet. */
5203b3a8eb9SGleb Smirnoff if (reass == NULL)
5213b3a8eb9SGleb Smirnoff return 0; /* not an error */
5223b3a8eb9SGleb Smirnoff /* if reass = NULL then it was consumed by ip_reass */
5233b3a8eb9SGleb Smirnoff /*
5243b3a8eb9SGleb Smirnoff * IP header checksum fixup after reassembly and leave header
5253b3a8eb9SGleb Smirnoff * in network byte order.
5263b3a8eb9SGleb Smirnoff */
5273b3a8eb9SGleb Smirnoff ip = mtod(reass, struct ip *);
5283b3a8eb9SGleb Smirnoff hlen = ip->ip_hl << 2;
5293b3a8eb9SGleb Smirnoff ip->ip_sum = 0;
5303b3a8eb9SGleb Smirnoff if (hlen == sizeof(struct ip))
5313b3a8eb9SGleb Smirnoff ip->ip_sum = in_cksum_hdr(ip);
5323b3a8eb9SGleb Smirnoff else
5333b3a8eb9SGleb Smirnoff ip->ip_sum = in_cksum(reass, hlen);
5343b3a8eb9SGleb Smirnoff clone = reass;
5353b3a8eb9SGleb Smirnoff }
5363b3a8eb9SGleb Smirnoff break;
5373b3a8eb9SGleb Smirnoff #ifdef INET6
5383b3a8eb9SGleb Smirnoff case IPV6_VERSION >> 4:
5393b3a8eb9SGleb Smirnoff {
5403b3a8eb9SGleb Smirnoff struct ip6_hdr *const ip6 = mtod(clone, struct ip6_hdr *);
5413b3a8eb9SGleb Smirnoff
5423b3a8eb9SGleb Smirnoff if (ip6->ip6_nxt == IPPROTO_FRAGMENT) {
5433b3a8eb9SGleb Smirnoff int nxt, off;
5443b3a8eb9SGleb Smirnoff
5453b3a8eb9SGleb Smirnoff off = sizeof(struct ip6_hdr);
5463b3a8eb9SGleb Smirnoff nxt = frag6_input(&clone, &off, 0);
5473b3a8eb9SGleb Smirnoff if (nxt == IPPROTO_DONE)
5483b3a8eb9SGleb Smirnoff return (0);
5493b3a8eb9SGleb Smirnoff }
5503b3a8eb9SGleb Smirnoff break;
5513b3a8eb9SGleb Smirnoff }
5523b3a8eb9SGleb Smirnoff #endif
5533b3a8eb9SGleb Smirnoff }
5543b3a8eb9SGleb Smirnoff
5553b3a8eb9SGleb Smirnoff /* attach a tag to the packet with the reinject info */
5563b3a8eb9SGleb Smirnoff tag = m_tag_alloc(MTAG_IPFW_RULE, 0,
5573b3a8eb9SGleb Smirnoff sizeof(struct ipfw_rule_ref), M_NOWAIT);
5583b3a8eb9SGleb Smirnoff if (tag == NULL) {
5593b3a8eb9SGleb Smirnoff FREE_PKT(clone);
5603b3a8eb9SGleb Smirnoff return 1;
5613b3a8eb9SGleb Smirnoff }
562b00b7e03SGleb Smirnoff *((struct ipfw_rule_ref *)(tag+1)) = args->rule;
5633b3a8eb9SGleb Smirnoff m_tag_prepend(clone, tag);
5643b3a8eb9SGleb Smirnoff
5653b3a8eb9SGleb Smirnoff /* Do the dirty job... */
566b00b7e03SGleb Smirnoff ip_divert_ptr(clone, args->flags & IPFW_ARGS_IN);
5673b3a8eb9SGleb Smirnoff return 0;
5683b3a8eb9SGleb Smirnoff }
5693b3a8eb9SGleb Smirnoff
5703b3a8eb9SGleb Smirnoff /*
5713b3a8eb9SGleb Smirnoff * attach or detach hooks for a given protocol family
5723b3a8eb9SGleb Smirnoff */
573b252313fSGleb Smirnoff VNET_DEFINE_STATIC(pfil_hook_t, ipfw_inet_hook);
574b252313fSGleb Smirnoff #define V_ipfw_inet_hook VNET(ipfw_inet_hook)
5752790ca97SGleb Smirnoff #ifdef INET6
5762790ca97SGleb Smirnoff VNET_DEFINE_STATIC(pfil_hook_t, ipfw_inet6_hook);
577b252313fSGleb Smirnoff #define V_ipfw_inet6_hook VNET(ipfw_inet6_hook)
5782790ca97SGleb Smirnoff #endif
5792790ca97SGleb Smirnoff VNET_DEFINE_STATIC(pfil_hook_t, ipfw_link_hook);
580b252313fSGleb Smirnoff #define V_ipfw_link_hook VNET(ipfw_link_hook)
581b252313fSGleb Smirnoff
58297245d40SGleb Smirnoff static void
ipfw_hook(int pf)58397245d40SGleb Smirnoff ipfw_hook(int pf)
5843b3a8eb9SGleb Smirnoff {
585caf32b26SGleb Smirnoff struct pfil_hook_args pha = {
586caf32b26SGleb Smirnoff .pa_version = PFIL_VERSION,
587caf32b26SGleb Smirnoff .pa_flags = PFIL_IN | PFIL_OUT,
588caf32b26SGleb Smirnoff .pa_modname = "ipfw",
589caf32b26SGleb Smirnoff };
590b252313fSGleb Smirnoff pfil_hook_t *h;
5913b3a8eb9SGleb Smirnoff
592b252313fSGleb Smirnoff switch (pf) {
593b252313fSGleb Smirnoff case AF_INET:
594caf32b26SGleb Smirnoff pha.pa_mbuf_chk = ipfw_check_packet;
595b252313fSGleb Smirnoff pha.pa_type = PFIL_TYPE_IP4;
596b252313fSGleb Smirnoff pha.pa_rulname = "default";
597b252313fSGleb Smirnoff h = &V_ipfw_inet_hook;
598b252313fSGleb Smirnoff break;
599b252313fSGleb Smirnoff #ifdef INET6
600b252313fSGleb Smirnoff case AF_INET6:
601caf32b26SGleb Smirnoff pha.pa_mbuf_chk = ipfw_check_packet;
602b252313fSGleb Smirnoff pha.pa_type = PFIL_TYPE_IP6;
603b252313fSGleb Smirnoff pha.pa_rulname = "default6";
604b252313fSGleb Smirnoff h = &V_ipfw_inet6_hook;
605b252313fSGleb Smirnoff break;
606b252313fSGleb Smirnoff #endif
607b252313fSGleb Smirnoff case AF_LINK:
608caf32b26SGleb Smirnoff pha.pa_mbuf_chk = ipfw_check_frame_mbuf;
609caf32b26SGleb Smirnoff pha.pa_mem_chk = ipfw_check_frame_mem;
610b252313fSGleb Smirnoff pha.pa_type = PFIL_TYPE_ETHERNET;
611b252313fSGleb Smirnoff pha.pa_rulname = "default-link";
612b252313fSGleb Smirnoff h = &V_ipfw_link_hook;
613b252313fSGleb Smirnoff break;
614b252313fSGleb Smirnoff }
615b252313fSGleb Smirnoff
616b252313fSGleb Smirnoff *h = pfil_add_hook(&pha);
61797245d40SGleb Smirnoff }
6183b3a8eb9SGleb Smirnoff
61997245d40SGleb Smirnoff static void
ipfw_unhook(int pf)62097245d40SGleb Smirnoff ipfw_unhook(int pf)
62197245d40SGleb Smirnoff {
62297245d40SGleb Smirnoff
62397245d40SGleb Smirnoff switch (pf) {
62497245d40SGleb Smirnoff case AF_INET:
62597245d40SGleb Smirnoff pfil_remove_hook(V_ipfw_inet_hook);
62697245d40SGleb Smirnoff break;
62797245d40SGleb Smirnoff #ifdef INET6
62897245d40SGleb Smirnoff case AF_INET6:
62997245d40SGleb Smirnoff pfil_remove_hook(V_ipfw_inet6_hook);
63097245d40SGleb Smirnoff break;
63197245d40SGleb Smirnoff #endif
63297245d40SGleb Smirnoff case AF_LINK:
63397245d40SGleb Smirnoff pfil_remove_hook(V_ipfw_link_hook);
63497245d40SGleb Smirnoff break;
63597245d40SGleb Smirnoff }
63697245d40SGleb Smirnoff }
63797245d40SGleb Smirnoff
63897245d40SGleb Smirnoff static int
ipfw_link(int pf,bool unlink)63997245d40SGleb Smirnoff ipfw_link(int pf, bool unlink)
64097245d40SGleb Smirnoff {
64197245d40SGleb Smirnoff struct pfil_link_args pla;
64297245d40SGleb Smirnoff
64397245d40SGleb Smirnoff pla.pa_version = PFIL_VERSION;
64497245d40SGleb Smirnoff pla.pa_flags = PFIL_IN | PFIL_OUT | PFIL_HEADPTR | PFIL_HOOKPTR;
64597245d40SGleb Smirnoff if (unlink)
64697245d40SGleb Smirnoff pla.pa_flags |= PFIL_UNLINK;
64797245d40SGleb Smirnoff
64897245d40SGleb Smirnoff switch (pf) {
64997245d40SGleb Smirnoff case AF_INET:
65097245d40SGleb Smirnoff pla.pa_head = V_inet_pfil_head;
65197245d40SGleb Smirnoff pla.pa_hook = V_ipfw_inet_hook;
65297245d40SGleb Smirnoff break;
65397245d40SGleb Smirnoff #ifdef INET6
65497245d40SGleb Smirnoff case AF_INET6:
65597245d40SGleb Smirnoff pla.pa_head = V_inet6_pfil_head;
65697245d40SGleb Smirnoff pla.pa_hook = V_ipfw_inet6_hook;
65797245d40SGleb Smirnoff break;
65897245d40SGleb Smirnoff #endif
65997245d40SGleb Smirnoff case AF_LINK:
66097245d40SGleb Smirnoff pla.pa_head = V_link_pfil_head;
66197245d40SGleb Smirnoff pla.pa_hook = V_ipfw_link_hook;
66297245d40SGleb Smirnoff break;
66397245d40SGleb Smirnoff }
66497245d40SGleb Smirnoff
66597245d40SGleb Smirnoff return (pfil_link(&pla));
6663b3a8eb9SGleb Smirnoff }
6673b3a8eb9SGleb Smirnoff
6683b3a8eb9SGleb Smirnoff int
ipfw_attach_hooks(void)66997245d40SGleb Smirnoff ipfw_attach_hooks(void)
6703b3a8eb9SGleb Smirnoff {
6713b3a8eb9SGleb Smirnoff int error = 0;
6723b3a8eb9SGleb Smirnoff
67397245d40SGleb Smirnoff ipfw_hook(AF_INET);
67497245d40SGleb Smirnoff TUNABLE_INT_FETCH("net.inet.ip.fw.enable", &V_fw_enable);
67597245d40SGleb Smirnoff if (V_fw_enable && (error = ipfw_link(AF_INET, false)) != 0)
6763b3a8eb9SGleb Smirnoff printf("ipfw_hook() error\n");
6773b3a8eb9SGleb Smirnoff #ifdef INET6
67897245d40SGleb Smirnoff ipfw_hook(AF_INET6);
67997245d40SGleb Smirnoff TUNABLE_INT_FETCH("net.inet6.ip6.fw.enable", &V_fw6_enable);
68097245d40SGleb Smirnoff if (V_fw6_enable && (error = ipfw_link(AF_INET6, false)) != 0)
6813b3a8eb9SGleb Smirnoff printf("ipfw6_hook() error\n");
6823b3a8eb9SGleb Smirnoff #endif
68397245d40SGleb Smirnoff ipfw_hook(AF_LINK);
68497245d40SGleb Smirnoff TUNABLE_INT_FETCH("net.link.ether.ipfw", &V_fwlink_enable);
68597245d40SGleb Smirnoff if (V_fwlink_enable && (error = ipfw_link(AF_LINK, false)) != 0)
6863b3a8eb9SGleb Smirnoff printf("ipfw_link_hook() error\n");
68797245d40SGleb Smirnoff
68897245d40SGleb Smirnoff return (error);
6893b3a8eb9SGleb Smirnoff }
69097245d40SGleb Smirnoff
69197245d40SGleb Smirnoff void
ipfw_detach_hooks(void)69297245d40SGleb Smirnoff ipfw_detach_hooks(void)
69397245d40SGleb Smirnoff {
69497245d40SGleb Smirnoff
69597245d40SGleb Smirnoff ipfw_unhook(AF_INET);
69697245d40SGleb Smirnoff #ifdef INET6
69797245d40SGleb Smirnoff ipfw_unhook(AF_INET6);
69897245d40SGleb Smirnoff #endif
69997245d40SGleb Smirnoff ipfw_unhook(AF_LINK);
7003b3a8eb9SGleb Smirnoff }
7013b3a8eb9SGleb Smirnoff
7023b3a8eb9SGleb Smirnoff int
ipfw_chg_hook(SYSCTL_HANDLER_ARGS)7033b3a8eb9SGleb Smirnoff ipfw_chg_hook(SYSCTL_HANDLER_ARGS)
7043b3a8eb9SGleb Smirnoff {
7053b3a8eb9SGleb Smirnoff int newval;
7063b3a8eb9SGleb Smirnoff int error;
7073b3a8eb9SGleb Smirnoff int af;
7083b3a8eb9SGleb Smirnoff
709620ee5d3SGleb Smirnoff if (arg1 == &V_fw_enable)
7103b3a8eb9SGleb Smirnoff af = AF_INET;
7113b3a8eb9SGleb Smirnoff #ifdef INET6
712620ee5d3SGleb Smirnoff else if (arg1 == &V_fw6_enable)
7133b3a8eb9SGleb Smirnoff af = AF_INET6;
7143b3a8eb9SGleb Smirnoff #endif
715620ee5d3SGleb Smirnoff else if (arg1 == &V_fwlink_enable)
7163b3a8eb9SGleb Smirnoff af = AF_LINK;
7173b3a8eb9SGleb Smirnoff else
7183b3a8eb9SGleb Smirnoff return (EINVAL);
7193b3a8eb9SGleb Smirnoff
720620ee5d3SGleb Smirnoff newval = *(int *)arg1;
7213b3a8eb9SGleb Smirnoff /* Handle sysctl change */
7223b3a8eb9SGleb Smirnoff error = sysctl_handle_int(oidp, &newval, 0, req);
7233b3a8eb9SGleb Smirnoff
7243b3a8eb9SGleb Smirnoff if (error)
7253b3a8eb9SGleb Smirnoff return (error);
7263b3a8eb9SGleb Smirnoff
7273b3a8eb9SGleb Smirnoff /* Formalize new value */
7283b3a8eb9SGleb Smirnoff newval = (newval) ? 1 : 0;
7293b3a8eb9SGleb Smirnoff
730620ee5d3SGleb Smirnoff if (*(int *)arg1 == newval)
7313b3a8eb9SGleb Smirnoff return (0);
7323b3a8eb9SGleb Smirnoff
73397245d40SGleb Smirnoff error = ipfw_link(af, newval == 0 ? true : false);
7343b3a8eb9SGleb Smirnoff if (error)
7353b3a8eb9SGleb Smirnoff return (error);
736620ee5d3SGleb Smirnoff *(int *)arg1 = newval;
7373b3a8eb9SGleb Smirnoff
7383b3a8eb9SGleb Smirnoff return (0);
7393b3a8eb9SGleb Smirnoff }
7403b3a8eb9SGleb Smirnoff /* end of file */
741