2 * Copyright (c) 2003-2012 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 /* $FreeBSD: src/sys/netinet6/ip6_fw.c,v 1.2.2.9 2002/04/28 05:40:27 suz Exp $ */
30 /* $KAME: ip6_fw.c,v 1.21 2001/01/24 01:25:32 itojun Exp $ */
33 * Copyright (C) 1998, 1999, 2000 and 2001 WIDE Project.
34 * All rights reserved.
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 * 3. Neither the name of the project nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
48 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62 * Copyright (c) 1993 Daniel Boulet
63 * Copyright (c) 1994 Ugen J.S.Antsilevich
64 * Copyright (c) 1996 Alex Nash
66 * Redistribution and use in source forms, with and without modification,
67 * are permitted provided that this entire comment appears intact.
69 * Redistribution in binary form may occur without any restrictions.
70 * Obviously, it would be nice if you gave credit where credit is due
71 * but requiring it would be too onerous.
73 * This software is provided ``AS IS'' without any warranties of any kind.
77 * Implement IPv6 packet firewall
82 #error "NOT SUPPORTED IPV6 DIVERT"
84 #ifdef IP6FW_DIVERT_RESTART
85 #error "NOT SUPPORTED IPV6 DIVERT"
89 #include <sys/param.h>
90 #include <sys/systm.h>
91 #include <sys/malloc.h>
93 #include <sys/queue.h>
94 #include <sys/kernel.h>
95 #include <sys/socket.h>
96 #include <sys/socketvar.h>
97 #include <sys/syslog.h>
100 #include <sys/kern_event.h>
103 #include <net/route.h>
104 #include <netinet/in_systm.h>
105 #include <netinet/in.h>
106 #include <netinet/ip.h>
108 #include <netinet/ip6.h>
109 #include <netinet6/ip6_var.h>
110 #include <netinet6/in6_var.h>
111 #include <netinet/icmp6.h>
113 #include <netinet/in_pcb.h>
115 #include <netinet6/ip6_fw.h>
116 #include <netinet/ip_var.h>
117 #include <netinet/tcp.h>
118 #include <netinet/tcp_seq.h>
119 #include <netinet/tcp_timer.h>
120 #include <netinet/tcp_var.h>
121 #include <netinet/udp.h>
123 #include <sys/sysctl.h>
125 #include <net/net_osdep.h>
127 MALLOC_DEFINE(M_IP6FW
, "Ip6Fw/Ip6Acct", "Ip6Fw/Ip6Acct chain's");
129 static int fw6_debug
= 0;
130 #ifdef IPV6FIREWALL_VERBOSE
131 static int fw6_verbose
= 1;
133 static int fw6_verbose
= 0;
135 #ifdef IPV6FIREWALL_VERBOSE_LIMIT
136 static int fw6_verbose_limit
= IPV6FIREWALL_VERBOSE_LIMIT
;
138 static int fw6_verbose_limit
= 0;
141 LIST_HEAD(ip6_fw_head
, ip6_fw_chain
) ip6_fw_chain
;
143 static void ip6fw_kev_post_msg(u_int32_t
);
146 static int ip6fw_sysctl SYSCTL_HANDLER_ARGS
;
148 SYSCTL_DECL(_net_inet6_ip6
);
149 SYSCTL_NODE(_net_inet6_ip6
, OID_AUTO
, fw
, CTLFLAG_RW
| CTLFLAG_LOCKED
, 0, "Firewall");
150 SYSCTL_PROC(_net_inet6_ip6_fw
, OID_AUTO
, enable
,
151 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_LOCKED
,
152 &ip6_fw_enable
, 0, ip6fw_sysctl
, "I", "Enable ip6fw");
153 SYSCTL_INT(_net_inet6_ip6_fw
, OID_AUTO
, debug
, CTLFLAG_RW
| CTLFLAG_LOCKED
, &fw6_debug
, 0, "");
154 SYSCTL_INT(_net_inet6_ip6_fw
, OID_AUTO
, verbose
, CTLFLAG_RW
| CTLFLAG_LOCKED
, &fw6_verbose
, 0, "");
155 SYSCTL_INT(_net_inet6_ip6_fw
, OID_AUTO
, verbose_limit
, CTLFLAG_RW
| CTLFLAG_LOCKED
, &fw6_verbose_limit
, 0, "");
158 ip6fw_sysctl SYSCTL_HANDLER_ARGS
160 #pragma unused(arg1, arg2)
163 error
= sysctl_handle_int(oidp
, oidp
->oid_arg1
, oidp
->oid_arg2
, req
);
164 if (error
|| !req
->newptr
) {
168 ip6fw_kev_post_msg(KEV_IP6FW_ENABLE
);
175 #define dprintf(a) do { \
179 #define SNPARGS(buf, len) buf + len, sizeof(buf) > len ? sizeof(buf) - len : 0
181 static int add_entry6
__P((struct ip6_fw_head
*chainptr
, struct ip6_fw
*frwl
));
182 static int del_entry6
__P((struct ip6_fw_head
*chainptr
, u_short number
));
183 static int zero_entry6
__P((struct ip6_fw
*frwl
));
184 static struct ip6_fw
*check_ip6fw_struct
__P((struct ip6_fw
*m
));
185 static int ip6opts_match
__P((struct ip6_hdr
**ip6
, struct ip6_fw
*f
,
187 int *off
, int *nxt
, u_short
*offset
));
188 static int port_match6
__P((u_short
*portptr
, int nports
, u_short port
,
190 static int tcp6flg_match
__P((struct tcphdr
*tcp6
, struct ip6_fw
*f
));
191 static int icmp6type_match
__P((struct icmp6_hdr
* icmp
, struct ip6_fw
* f
));
192 static void ip6fw_report
__P((struct ip6_fw
*f
, struct ip6_hdr
*ip6
,
193 struct ifnet
*rif
, struct ifnet
*oif
, int off
, int nxt
));
195 static int ip6_fw_chk
__P((struct ip6_hdr
**pip6
,
196 struct ifnet
*oif
, u_int16_t
*cookie
, struct mbuf
**m
));
197 static int ip6_fw_ctl
__P((struct sockopt
*));
198 static void cp_to_user_64( struct ip6_fw_64
*userrule_64
, struct ip6_fw
*rule
);
199 static void cp_from_user_64( struct ip6_fw_64
*userrule_64
, struct ip6_fw
*rule
);
200 static void cp_to_user_32( struct ip6_fw_32
*userrule_32
, struct ip6_fw
*rule
);
201 static void cp_from_user_32( struct ip6_fw_32
*userrule_32
, struct ip6_fw
*rule
);
203 static char err_prefix
[] = "ip6_fw_ctl:";
206 * Returns 1 if the port is matched by the vector, 0 otherwise
210 port_match6(u_short
*portptr
, int nports
, u_short port
, int range_flag
)
216 if (portptr
[0] <= port
&& port
<= portptr
[1]) {
222 while (nports
-- > 0) {
223 if (*portptr
++ == port
) {
231 tcp6flg_match(struct tcphdr
*tcp6
, struct ip6_fw
*f
)
233 u_char flg_set
, flg_clr
;
236 * If an established connection is required, reject packets that
237 * have only SYN of RST|ACK|SYN set. Otherwise, fall through to
238 * other flag requirements.
240 if ((f
->fw_ipflg
& IPV6_FW_IF_TCPEST
) &&
241 ((tcp6
->th_flags
& (IPV6_FW_TCPF_RST
| IPV6_FW_TCPF_ACK
|
242 IPV6_FW_TCPF_SYN
)) == IPV6_FW_TCPF_SYN
)) {
246 flg_set
= tcp6
->th_flags
& f
->fw_tcpf
;
247 flg_clr
= tcp6
->th_flags
& f
->fw_tcpnf
;
249 if (flg_set
!= f
->fw_tcpf
) {
260 icmp6type_match(struct icmp6_hdr
*icmp6
, struct ip6_fw
*f
)
264 if (!(f
->fw_flg
& IPV6_FW_F_ICMPBIT
)) {
268 type
= icmp6
->icmp6_type
;
270 /* check for matching type in the bitmap */
271 if (type
< IPV6_FW_ICMPTYPES_DIM
* sizeof(unsigned) * 8 &&
272 (f
->fw_icmp6types
[type
/ (sizeof(unsigned) * 8)] &
273 (1U << (type
% (8 * sizeof(unsigned)))))) {
277 return 0; /* no match */
281 is_icmp6_query(struct ip6_hdr
*ip6
, int off
)
283 const struct icmp6_hdr
*icmp6
;
286 icmp6
= (struct icmp6_hdr
*)((caddr_t
)ip6
+ off
);
287 icmp6_type
= icmp6
->icmp6_type
;
289 if (icmp6_type
== ICMP6_ECHO_REQUEST
||
290 icmp6_type
== ICMP6_MEMBERSHIP_QUERY
||
291 icmp6_type
== ICMP6_WRUREQUEST
||
292 icmp6_type
== ICMP6_FQDN_QUERY
||
293 icmp6_type
== ICMP6_NI_QUERY
) {
301 ip6opts_match(struct ip6_hdr
**pip6
, struct ip6_fw
*f
, struct mbuf
**m
,
302 int *off
, int *nxt
, u_short
*offset
)
305 struct ip6_hdr
*ip6
= *pip6
;
306 struct ip6_ext
*ip6e
;
307 u_char opts
, nopts
, nopts_sve
;
310 nopts
= nopts_sve
= f
->fw_ip6nopt
;
313 *off
= sizeof(struct ip6_hdr
);
314 len
= ntohs(ip6
->ip6_plen
) + sizeof(struct ip6_hdr
);
316 ip6e
= (struct ip6_ext
*)((caddr_t
) ip6
+ *off
);
317 if ((*m
)->m_len
< *off
+ sizeof(*ip6e
)) {
318 goto opts_check
; /* XXX */
321 case IPPROTO_FRAGMENT
:
322 if ((*m
)->m_len
>= *off
+ sizeof(struct ip6_frag
)) {
323 struct ip6_frag
*ip6f
;
325 ip6f
= (struct ip6_frag
*) ((caddr_t
)ip6
+ *off
);
326 *offset
= ip6f
->ip6f_offlg
& IP6F_OFF_MASK
;
328 opts
&= ~IPV6_FW_IP6OPT_FRAG
;
329 nopts
&= ~IPV6_FW_IP6OPT_FRAG
;
330 *off
+= sizeof(struct ip6_frag
);
333 opts
&= ~IPV6_FW_IP6OPT_AH
;
334 nopts
&= ~IPV6_FW_IP6OPT_AH
;
335 *off
+= (ip6e
->ip6e_len
+ 2) << 2;
339 case IPPROTO_HOPOPTS
:
340 opts
&= ~IPV6_FW_IP6OPT_HOPOPT
;
341 nopts
&= ~IPV6_FW_IP6OPT_HOPOPT
;
343 case IPPROTO_ROUTING
:
344 opts
&= ~IPV6_FW_IP6OPT_ROUTE
;
345 nopts
&= ~IPV6_FW_IP6OPT_ROUTE
;
348 opts
&= ~IPV6_FW_IP6OPT_ESP
;
349 nopts
&= ~IPV6_FW_IP6OPT_ESP
;
352 opts
&= ~IPV6_FW_IP6OPT_NONXT
;
353 nopts
&= ~IPV6_FW_IP6OPT_NONXT
;
356 case IPPROTO_DSTOPTS
:
357 opts
&= ~IPV6_FW_IP6OPT_OPTS
;
358 nopts
&= ~IPV6_FW_IP6OPT_OPTS
;
364 *off
+= (ip6e
->ip6e_len
+ 1) << 3;
367 *nxt
= ip6e
->ip6e_nxt
;
370 if (f
->fw_ip6opt
== f
->fw_ip6nopt
) { /* XXX */
374 if (opts
== 0 && nopts
== nopts_sve
) {
383 iface_match(struct ifnet
*ifp
, union ip6_fw_if
*ifu
, int byname
)
385 /* Check by name or by IP address */
387 /* Check unit number (-1 is wildcard) */
388 if (ifu
->fu_via_if
.unit
!= -1
389 && ifp
->if_unit
!= ifu
->fu_via_if
.unit
) {
393 if (strncmp(ifp
->if_name
, ifu
->fu_via_if
.name
, IP6FW_IFNLEN
)) {
397 } else if (!IN6_IS_ADDR_UNSPECIFIED(&ifu
->fu_via_ip6
)) { /* Zero == wildcard */
400 ifnet_lock_shared(ifp
);
401 for (ia
= ifp
->if_addrlist
.tqh_first
; ia
;
402 ia
= ia
->ifa_list
.tqe_next
) {
404 if (ia
->ifa_addr
->sa_family
!= AF_INET6
) {
408 if (!IN6_ARE_ADDR_EQUAL(&ifu
->fu_via_ip6
,
409 &(((struct sockaddr_in6
*)
410 (ia
->ifa_addr
))->sin6_addr
))) {
415 ifnet_lock_done(ifp
);
418 ifnet_lock_done(ifp
);
425 ip6fw_report(struct ip6_fw
*f
, struct ip6_hdr
*ip6
,
426 struct ifnet
*rif
, struct ifnet
*oif
, int off
, int nxt
)
429 struct tcphdr
*const tcp6
= (struct tcphdr
*) ((caddr_t
) ip6
+ off
);
430 struct udphdr
*const udp
= (struct udphdr
*) ((caddr_t
) ip6
+ off
);
431 struct icmp6_hdr
*const icmp6
= (struct icmp6_hdr
*) ((caddr_t
) ip6
+ off
);
434 char action2
[32], proto
[102], name
[18];
437 count
= f
? f
->fw_pcnt
: ++counter
;
438 if (fw6_verbose_limit
!= 0 && count
> fw6_verbose_limit
) {
442 /* Print command name */
443 snprintf(SNPARGS(name
, 0), "ip6fw: %d", f
? f
->fw_number
: -1);
449 switch (f
->fw_flg
& IPV6_FW_F_COMMAND
) {
453 case IPV6_FW_F_REJECT
:
454 if (f
->fw_reject_code
== IPV6_FW_REJECT_RST
) {
460 case IPV6_FW_F_ACCEPT
:
463 case IPV6_FW_F_COUNT
:
466 case IPV6_FW_F_DIVERT
:
467 snprintf(SNPARGS(action2
, 0), "Divert %d",
471 snprintf(SNPARGS(action2
, 0), "Tee %d",
474 case IPV6_FW_F_SKIPTO
:
475 snprintf(SNPARGS(action2
, 0), "SkipTo %d",
486 len
= scnprintf(SNPARGS(proto
, 0), "TCP [%s]",
487 ip6_sprintf(&ip6
->ip6_src
));
489 len
+= scnprintf(SNPARGS(proto
, len
), ":%d ",
490 ntohs(tcp6
->th_sport
));
492 len
+= scnprintf(SNPARGS(proto
, len
), " ");
494 len
+= scnprintf(SNPARGS(proto
, len
), "[%s]",
495 ip6_sprintf(&ip6
->ip6_dst
));
497 scnprintf(SNPARGS(proto
, len
), ":%d",
498 ntohs(tcp6
->th_dport
));
502 len
= scnprintf(SNPARGS(proto
, 0), "UDP [%s]",
503 ip6_sprintf(&ip6
->ip6_src
));
505 len
+= scnprintf(SNPARGS(proto
, len
), ":%d ",
506 ntohs(udp
->uh_sport
));
508 len
+= scnprintf(SNPARGS(proto
, len
), " ");
510 len
+= scnprintf(SNPARGS(proto
, len
), "[%s]",
511 ip6_sprintf(&ip6
->ip6_dst
));
513 scnprintf(SNPARGS(proto
, len
), ":%d",
514 ntohs(udp
->uh_dport
));
519 len
= scnprintf(SNPARGS(proto
, 0), "IPV6-ICMP:%u.%u ",
520 icmp6
->icmp6_type
, icmp6
->icmp6_code
);
522 len
= scnprintf(SNPARGS(proto
, 0), "IPV6-ICMP ");
524 len
+= scnprintf(SNPARGS(proto
, len
), "[%s]",
525 ip6_sprintf(&ip6
->ip6_src
));
526 scnprintf(SNPARGS(proto
, len
), " [%s]",
527 ip6_sprintf(&ip6
->ip6_dst
));
530 len
= scnprintf(SNPARGS(proto
, 0), "P:%d [%s]", nxt
,
531 ip6_sprintf(&ip6
->ip6_src
));
532 scnprintf(SNPARGS(proto
, len
), " [%s]",
533 ip6_sprintf(&ip6
->ip6_dst
));
538 log(LOG_AUTHPRIV
| LOG_INFO
, "%s %s %s out via %s\n",
539 name
, action
, proto
, if_name(oif
));
541 log(LOG_AUTHPRIV
| LOG_INFO
, "%s %s %s in via %s\n",
542 name
, action
, proto
, if_name(rif
));
544 log(LOG_AUTHPRIV
| LOG_INFO
, "%s %s %s",
545 name
, action
, proto
);
547 if (fw6_verbose_limit
!= 0 && count
== fw6_verbose_limit
) {
548 log(LOG_AUTHPRIV
| LOG_INFO
, "ip6fw: limit reached on entry %d\n",
549 f
? f
->fw_number
: -1);
556 * ip Pointer to packet header (struct ip6_hdr *)
557 * hlen Packet header length
558 * oif Outgoing interface, or NULL if packet is incoming
559 * #ifndef IP6FW_DIVERT_RESTART
560 * *cookie Ignore all divert/tee rules to this port (if non-zero)
562 * *cookie Skip up to the first rule past this rule number;
564 * *m The packet; we set to NULL when/if we nuke it.
568 * 0 The packet is to be accepted and routed normally OR
569 * the packet was denied/rejected and has been dropped;
570 * in the latter case, *m is equal to NULL upon return.
571 * port Divert the packet to port.
575 ip6_fw_chk(struct ip6_hdr
**pip6
,
576 struct ifnet
*oif
, u_int16_t
*cookie
, struct mbuf
**m
)
578 struct ip6_fw_chain
*chain
;
579 struct ip6_fw
*rule
= NULL
;
580 struct ip6_hdr
*ip6
= *pip6
;
581 struct ifnet
*const rif
= ((*m
)->m_flags
& M_LOOP
) ? lo_ifp
: (*m
)->m_pkthdr
.rcvif
;
583 int off
= sizeof(struct ip6_hdr
), nxt
= ip6
->ip6_nxt
;
584 u_short src_port
, dst_port
;
585 #ifdef IP6FW_DIVERT_RESTART
586 u_int16_t skipto
= *cookie
;
588 u_int16_t ignport
= ntohs(*cookie
);
590 struct timeval timenow
;
591 struct tcp_respond_args tra
;
593 getmicrotime(&timenow
);
597 * Go down the chain, looking for enlightment
598 * #ifdef IP6FW_DIVERT_RESTART
599 * If we've been asked to start at a given rule immediatly, do so.
602 chain
= LIST_FIRST(&ip6_fw_chain
);
603 #ifdef IP6FW_DIVERT_RESTART
605 if (skipto
>= 65535) {
608 while (chain
&& (chain
->rule
->fw_number
<= skipto
)) {
609 chain
= LIST_NEXT(chain
, chain
);
615 #endif /* IP6FW_DIVERT_RESTART */
616 for (; chain
; chain
= LIST_NEXT(chain
, chain
)) {
617 struct ip6_fw
*const f
= chain
->rule
;
620 /* Check direction outbound */
621 if (!(f
->fw_flg
& IPV6_FW_F_OUT
)) {
625 /* Check direction inbound */
626 if (!(f
->fw_flg
& IPV6_FW_F_IN
)) {
631 #define IN6_ARE_ADDR_MASKEQUAL(x, y, z) (\
632 (((x)->s6_addr32[0] & (y)->s6_addr32[0]) == (z)->s6_addr32[0]) && \
633 (((x)->s6_addr32[1] & (y)->s6_addr32[1]) == (z)->s6_addr32[1]) && \
634 (((x)->s6_addr32[2] & (y)->s6_addr32[2]) == (z)->s6_addr32[2]) && \
635 (((x)->s6_addr32[3] & (y)->s6_addr32[3]) == (z)->s6_addr32[3]))
637 /* If src-addr doesn't match, not this rule. */
638 if (((f
->fw_flg
& IPV6_FW_F_INVSRC
) != 0) ^
639 (!IN6_ARE_ADDR_MASKEQUAL(&ip6
->ip6_src
, &f
->fw_smsk
, &f
->fw_src
))) {
643 /* If dest-addr doesn't match, not this rule. */
644 if (((f
->fw_flg
& IPV6_FW_F_INVDST
) != 0) ^
645 (!IN6_ARE_ADDR_MASKEQUAL(&ip6
->ip6_dst
, &f
->fw_dmsk
, &f
->fw_dst
))) {
649 #undef IN6_ARE_ADDR_MASKEQUAL
650 /* Interface check */
651 if ((f
->fw_flg
& IF6_FW_F_VIAHACK
) == IF6_FW_F_VIAHACK
) {
652 struct ifnet
*const iface
= oif
? oif
: rif
;
654 /* Backwards compatibility hack for "via" */
655 if (!iface
|| !iface_match(iface
,
656 &f
->fw_in_if
, f
->fw_flg
& IPV6_FW_F_OIFNAME
)) {
660 /* Check receive interface */
661 if ((f
->fw_flg
& IPV6_FW_F_IIFACE
)
662 && (!rif
|| !iface_match(rif
,
663 &f
->fw_in_if
, f
->fw_flg
& IPV6_FW_F_IIFNAME
))) {
666 /* Check outgoing interface */
667 if ((f
->fw_flg
& IPV6_FW_F_OIFACE
)
668 && (!oif
|| !iface_match(oif
,
669 &f
->fw_out_if
, f
->fw_flg
& IPV6_FW_F_OIFNAME
))) {
674 /* Check IP options */
675 if (!ip6opts_match(&ip6
, f
, m
, &off
, &nxt
, &offset
)) {
680 if ((f
->fw_flg
& IPV6_FW_F_FRAG
) && !offset
) {
684 /* Check protocol; if wildcard, match */
685 if (f
->fw_prot
== IPPROTO_IPV6
) {
689 /* If different, don't match */
690 if (nxt
!= f
->fw_prot
) {
694 #define PULLUP_TO(len) do { \
695 if ((*m)->m_len < (len) \
696 && (*m = m_pullup(*m, (len))) == 0) { \
699 *pip6 = ip6 = mtod(*m, struct ip6_hdr *); \
702 /* Protocol specific checks */
708 if (offset
== 1) { /* cf. RFC 1858 */
709 PULLUP_TO(off
+ 4); /* XXX ? */
714 * TCP flags and ports aren't available in this
715 * packet -- if this rule specified either one,
716 * we consider the rule a non-match.
718 if (f
->fw_nports
!= 0 ||
719 f
->fw_tcpf
!= f
->fw_tcpnf
) {
726 tcp6
= (struct tcphdr
*) ((caddr_t
)ip6
+ off
);
727 if (((f
->fw_tcpf
!= f
->fw_tcpnf
) ||
728 (f
->fw_ipflg
& IPV6_FW_IF_TCPEST
)) &&
729 !tcp6flg_match(tcp6
, f
)) {
732 src_port
= ntohs(tcp6
->th_sport
);
733 dst_port
= ntohs(tcp6
->th_dport
);
743 * Port specification is unavailable -- if this
744 * rule specifies a port, we consider the rule
747 if (f
->fw_nports
!= 0) {
754 udp
= (struct udphdr
*) ((caddr_t
)ip6
+ off
);
755 src_port
= ntohs(udp
->uh_sport
);
756 dst_port
= ntohs(udp
->uh_dport
);
758 if (!port_match6(&f
->fw_pts
[0],
759 IPV6_FW_GETNSRCP(f
), src_port
,
760 f
->fw_flg
& IPV6_FW_F_SRNG
)) {
763 if (!port_match6(&f
->fw_pts
[IPV6_FW_GETNSRCP(f
)],
764 IPV6_FW_GETNDSTP(f
), dst_port
,
765 f
->fw_flg
& IPV6_FW_F_DRNG
)) {
773 struct icmp6_hdr
*icmp
;
775 if (offset
!= 0) { /* Type isn't valid */
779 icmp
= (struct icmp6_hdr
*) ((caddr_t
)ip6
+ off
);
780 if (!icmp6type_match(icmp
, f
)) {
789 ip6fw_report(NULL
, ip6
, rif
, oif
, off
, nxt
);
795 #ifndef IP6FW_DIVERT_RESTART
796 /* Ignore divert/tee rule if socket port is "ignport" */
797 switch (f
->fw_flg
& IPV6_FW_F_COMMAND
) {
798 case IPV6_FW_F_DIVERT
:
800 if (f
->fw_divert_port
== ignport
) {
801 continue; /* ignore this rule */
806 #endif /* IP6FW_DIVERT_RESTART */
807 /* Update statistics */
809 f
->fw_bcnt
+= ntohs(ip6
->ip6_plen
);
810 f
->timestamp
= timenow
.tv_sec
;
812 /* Log to console if desired */
813 if ((f
->fw_flg
& IPV6_FW_F_PRN
) && fw6_verbose
) {
814 ip6fw_report(f
, ip6
, rif
, oif
, off
, nxt
);
817 /* Take appropriate action */
818 switch (f
->fw_flg
& IPV6_FW_F_COMMAND
) {
819 case IPV6_FW_F_ACCEPT
:
821 case IPV6_FW_F_COUNT
:
823 case IPV6_FW_F_DIVERT
:
824 #ifdef IP6FW_DIVERT_RESTART
825 *cookie
= f
->fw_number
;
827 *cookie
= htons(f
->fw_divert_port
);
828 #endif /* IP6FW_DIVERT_RESTART */
829 return f
->fw_divert_port
;
832 * XXX someday tee packet here, but beware that you
833 * can't use m_copym() or m_copypacket() because
834 * the divert input routine modifies the mbuf
835 * (and these routines only increment reference
836 * counts in the case of mbuf clusters), so need
837 * to write custom routine.
840 case IPV6_FW_F_SKIPTO
:
842 while (chain
->chain
.le_next
843 && chain
->chain
.le_next
->rule
->fw_number
846 while (chain
->chain
.le_next
->rule
->fw_number
849 { chain
= chain
->chain
.le_next
;}
853 /* Deny/reject this packet using this rule */
859 /* Rule 65535 should always be there and should always match */
861 panic("ip6_fw: chain");
866 * At this point, we're going to drop the packet.
867 * Send a reject notice if all of the following are true:
869 * - The packet matched a reject rule
870 * - The packet is not an ICMP packet, or is an ICMP query packet
871 * - The packet is not a multicast or broadcast packet
873 if ((rule
->fw_flg
& IPV6_FW_F_COMMAND
) == IPV6_FW_F_REJECT
874 && (nxt
!= IPPROTO_ICMPV6
|| is_icmp6_query(ip6
, off
))
875 && !((*m
)->m_flags
& (M_BCAST
| M_MCAST
))
876 && !IN6_IS_ADDR_MULTICAST(&ip6
->ip6_dst
)) {
877 switch (rule
->fw_reject_code
) {
878 case IPV6_FW_REJECT_RST
:
880 struct tcphdr
*const tcp
=
881 (struct tcphdr
*) ((caddr_t
)ip6
+ off
);
889 if (offset
!= 0 || (tcp
->th_flags
& TH_RST
)) {
895 ti
.th
.th_seq
= ntohl(ti
.th
.th_seq
);
896 ti
.th
.th_ack
= ntohl(ti
.th
.th_ack
);
897 ti
.ip6
.ip6_nxt
= IPPROTO_TCP
;
898 if (ti
.th
.th_flags
& TH_ACK
) {
904 if (((*m
)->m_flags
& M_PKTHDR
) != 0) {
905 ack
+= (*m
)->m_pkthdr
.len
- off
906 - (ti
.th
.th_off
<< 2);
907 } else if (ip6
->ip6_plen
) {
908 ack
+= ntohs(ip6
->ip6_plen
) + sizeof(*ip6
)
909 - off
- (ti
.th
.th_off
<< 2);
916 flags
= TH_RST
| TH_ACK
;
918 bcopy(&ti
, ip6
, sizeof(ti
));
919 bzero(&tra
, sizeof(tra
));
920 tra
.ifscope
= IFSCOPE_NONE
;
921 tra
.awdl_unrestricted
= 1;
922 tcp_respond(NULL
, ip6
, (struct tcphdr
*)(ip6
+ 1),
923 *m
, ack
, seq
, flags
, &tra
);
927 default: /* Send an ICMP unreachable using code */
929 (*m
)->m_pkthdr
.rcvif
= oif
;
931 icmp6_error(*m
, ICMP6_DST_UNREACH
,
932 rule
->fw_reject_code
, 0);
940 * Finally, drop the packet.
950 add_entry6(struct ip6_fw_head
*chainptr
, struct ip6_fw
*frwl
)
952 struct ip6_fw
*ftmp
= 0;
953 struct ip6_fw_chain
*fwc
= 0, *fcp
, *fcpl
= 0;
956 fwc
= _MALLOC(sizeof *fwc
, M_IP6FW
, M_WAITOK
);
957 ftmp
= _MALLOC(sizeof *ftmp
, M_IP6FW
, M_WAITOK
);
959 dprintf(("%s malloc said no\n", err_prefix
));
969 bcopy(frwl
, ftmp
, sizeof(struct ip6_fw
));
970 ftmp
->fw_in_if
.fu_via_if
.name
[IP6FW_IFNLEN
- 1] = '\0';
975 if (!chainptr
->lh_first
) {
976 LIST_INSERT_HEAD(chainptr
, fwc
, chain
);
978 } else if (ftmp
->fw_number
== (u_short
) - 1) {
985 dprintf(("%s bad rule number\n", err_prefix
));
989 /* If entry number is 0, find highest numbered rule and add 100 */
990 if (ftmp
->fw_number
== 0) {
991 for (fcp
= chainptr
->lh_first
; fcp
; fcp
= fcp
->chain
.le_next
) {
992 if (fcp
->rule
->fw_number
!= (u_short
) - 1) {
993 nbr
= fcp
->rule
->fw_number
;
998 if (nbr
< (u_short
) - 1 - 100) {
1001 ftmp
->fw_number
= nbr
;
1004 /* Got a valid number; now insert it, keeping the list ordered */
1005 for (fcp
= chainptr
->lh_first
; fcp
; fcp
= fcp
->chain
.le_next
) {
1006 if (fcp
->rule
->fw_number
> ftmp
->fw_number
) {
1008 LIST_INSERT_AFTER(fcpl
, fwc
, chain
);
1010 LIST_INSERT_HEAD(chainptr
, fwc
, chain
);
1018 bcopy(ftmp
, frwl
, sizeof(struct ip6_fw
));
1023 del_entry6(struct ip6_fw_head
*chainptr
, u_short number
)
1025 struct ip6_fw_chain
*fcp
;
1027 fcp
= chainptr
->lh_first
;
1028 if (number
!= (u_short
) - 1) {
1029 for (; fcp
; fcp
= fcp
->chain
.le_next
) {
1030 if (fcp
->rule
->fw_number
== number
) {
1031 LIST_REMOVE(fcp
, chain
);
1032 FREE(fcp
->rule
, M_IP6FW
);
1043 zero_entry6(struct ip6_fw
*frwl
)
1045 struct ip6_fw_chain
*fcp
;
1048 * It's possible to insert multiple chain entries with the
1049 * same number, so we don't stop after finding the first
1050 * match if zeroing a specific entry.
1052 for (fcp
= ip6_fw_chain
.lh_first
; fcp
; fcp
= fcp
->chain
.le_next
) {
1053 if (!frwl
|| frwl
->fw_number
== 0 || frwl
->fw_number
== fcp
->rule
->fw_number
) {
1054 fcp
->rule
->fw_bcnt
= fcp
->rule
->fw_pcnt
= 0;
1055 fcp
->rule
->timestamp
= 0;
1061 log(LOG_AUTHPRIV
| LOG_NOTICE
,
1062 "ip6fw: Entry %d cleared.\n", frwl
->fw_number
);
1064 log(LOG_AUTHPRIV
| LOG_NOTICE
,
1065 "ip6fw: Accounting cleared.\n");
1072 static struct ip6_fw
*
1073 check_ip6fw_struct(struct ip6_fw
*frwl
)
1075 /* Check for invalid flag bits */
1076 if ((frwl
->fw_flg
& ~IPV6_FW_F_MASK
) != 0) {
1077 dprintf(("%s undefined flag bits set (flags=%x)\n",
1078 err_prefix
, frwl
->fw_flg
));
1081 /* Must apply to incoming or outgoing (or both) */
1082 if (!(frwl
->fw_flg
& (IPV6_FW_F_IN
| IPV6_FW_F_OUT
))) {
1083 dprintf(("%s neither in nor out\n", err_prefix
));
1086 /* Empty interface name is no good */
1087 if (((frwl
->fw_flg
& IPV6_FW_F_IIFNAME
)
1088 && !*frwl
->fw_in_if
.fu_via_if
.name
)
1089 || ((frwl
->fw_flg
& IPV6_FW_F_OIFNAME
)
1090 && !*frwl
->fw_out_if
.fu_via_if
.name
)) {
1091 dprintf(("%s empty interface name\n", err_prefix
));
1094 /* Sanity check interface matching */
1095 if ((frwl
->fw_flg
& IF6_FW_F_VIAHACK
) == IF6_FW_F_VIAHACK
) {
1096 ; /* allow "via" backwards compatibility */
1097 } else if ((frwl
->fw_flg
& IPV6_FW_F_IN
)
1098 && (frwl
->fw_flg
& IPV6_FW_F_OIFACE
)) {
1099 dprintf(("%s outgoing interface check on incoming\n",
1103 /* Sanity check port ranges */
1104 if ((frwl
->fw_flg
& IPV6_FW_F_SRNG
) && IPV6_FW_GETNSRCP(frwl
) < 2) {
1105 dprintf(("%s src range set but n_src_p=%d\n",
1106 err_prefix
, IPV6_FW_GETNSRCP(frwl
)));
1109 if ((frwl
->fw_flg
& IPV6_FW_F_DRNG
) && IPV6_FW_GETNDSTP(frwl
) < 2) {
1110 dprintf(("%s dst range set but n_dst_p=%d\n",
1111 err_prefix
, IPV6_FW_GETNDSTP(frwl
)));
1114 if (IPV6_FW_GETNSRCP(frwl
) + IPV6_FW_GETNDSTP(frwl
) > IPV6_FW_MAX_PORTS
) {
1115 dprintf(("%s too many ports (%d+%d)\n",
1116 err_prefix
, IPV6_FW_GETNSRCP(frwl
), IPV6_FW_GETNDSTP(frwl
)));
1120 * Protocols other than TCP/UDP don't use port range
1122 if ((frwl
->fw_prot
!= IPPROTO_TCP
) &&
1123 (frwl
->fw_prot
!= IPPROTO_UDP
) &&
1124 (IPV6_FW_GETNSRCP(frwl
) || IPV6_FW_GETNDSTP(frwl
))) {
1125 dprintf(("%s port(s) specified for non TCP/UDP rule\n",
1131 * Rather than modify the entry to make such entries work,
1132 * we reject this rule and require user level utilities
1133 * to enforce whatever policy they deem appropriate.
1135 if ((frwl
->fw_src
.s6_addr32
[0] & (~frwl
->fw_smsk
.s6_addr32
[0])) ||
1136 (frwl
->fw_src
.s6_addr32
[1] & (~frwl
->fw_smsk
.s6_addr32
[1])) ||
1137 (frwl
->fw_src
.s6_addr32
[2] & (~frwl
->fw_smsk
.s6_addr32
[2])) ||
1138 (frwl
->fw_src
.s6_addr32
[3] & (~frwl
->fw_smsk
.s6_addr32
[3])) ||
1139 (frwl
->fw_dst
.s6_addr32
[0] & (~frwl
->fw_dmsk
.s6_addr32
[0])) ||
1140 (frwl
->fw_dst
.s6_addr32
[1] & (~frwl
->fw_dmsk
.s6_addr32
[1])) ||
1141 (frwl
->fw_dst
.s6_addr32
[2] & (~frwl
->fw_dmsk
.s6_addr32
[2])) ||
1142 (frwl
->fw_dst
.s6_addr32
[3] & (~frwl
->fw_dmsk
.s6_addr32
[3]))) {
1143 dprintf(("%s rule never matches\n", err_prefix
));
1147 if ((frwl
->fw_flg
& IPV6_FW_F_FRAG
) &&
1148 (frwl
->fw_prot
== IPPROTO_UDP
|| frwl
->fw_prot
== IPPROTO_TCP
)) {
1149 if (frwl
->fw_nports
) {
1150 dprintf(("%s cannot mix 'frag' and ports\n", err_prefix
));
1153 if (frwl
->fw_prot
== IPPROTO_TCP
&&
1154 frwl
->fw_tcpf
!= frwl
->fw_tcpnf
) {
1155 dprintf(("%s cannot mix 'frag' with TCP flags\n", err_prefix
));
1160 /* Check command specific stuff */
1161 switch (frwl
->fw_flg
& IPV6_FW_F_COMMAND
) {
1162 case IPV6_FW_F_REJECT
:
1163 if (frwl
->fw_reject_code
>= 0x100
1164 && !(frwl
->fw_prot
== IPPROTO_TCP
1165 && frwl
->fw_reject_code
== IPV6_FW_REJECT_RST
)) {
1166 dprintf(("%s unknown reject code\n", err_prefix
));
1170 case IPV6_FW_F_DIVERT
: /* Diverting to port zero is invalid */
1172 if (frwl
->fw_divert_port
== 0) {
1173 dprintf(("%s can't divert to port 0\n", err_prefix
));
1177 case IPV6_FW_F_DENY
:
1178 case IPV6_FW_F_ACCEPT
:
1179 case IPV6_FW_F_COUNT
:
1180 case IPV6_FW_F_SKIPTO
:
1183 dprintf(("%s invalid command\n", err_prefix
));
1191 ip6fw_kev_post_msg(u_int32_t event_code
)
1193 struct kev_msg ev_msg
;
1195 bzero(&ev_msg
, sizeof(struct kev_msg
));
1197 ev_msg
.vendor_code
= KEV_VENDOR_APPLE
;
1198 ev_msg
.kev_class
= KEV_FIREWALL_CLASS
;
1199 ev_msg
.kev_subclass
= KEV_IP6FW_SUBCLASS
;
1200 ev_msg
.event_code
= event_code
;
1202 kev_post_msg(&ev_msg
);
1207 cp_to_user_64( struct ip6_fw_64
*userrule_64
, struct ip6_fw
*rule
)
1209 userrule_64
->version
= rule
->version
;
1210 userrule_64
->context
= CAST_USER_ADDR_T(rule
->context
);
1211 userrule_64
->fw_pcnt
= rule
->fw_pcnt
;
1212 userrule_64
->fw_bcnt
= rule
->fw_bcnt
;
1213 userrule_64
->fw_src
= rule
->fw_src
;
1214 userrule_64
->fw_dst
= rule
->fw_dst
;
1215 userrule_64
->fw_smsk
= rule
->fw_smsk
;
1216 userrule_64
->fw_dmsk
= rule
->fw_dmsk
;
1217 userrule_64
->fw_number
= rule
->fw_number
;
1218 userrule_64
->fw_flg
= rule
->fw_flg
;
1219 userrule_64
->fw_ipflg
= rule
->fw_ipflg
;
1220 bcopy( rule
->fw_pts
, userrule_64
->fw_pts
, IPV6_FW_MAX_PORTS
);
1221 userrule_64
->fw_ip6opt
= rule
->fw_ip6opt
;
1222 userrule_64
->fw_ip6nopt
= rule
->fw_ip6nopt
;
1223 userrule_64
->fw_tcpf
= rule
->fw_tcpf
;
1224 userrule_64
->fw_tcpnf
= rule
->fw_tcpnf
;
1225 bcopy( rule
->fw_icmp6types
, userrule_64
->fw_icmp6types
, sizeof(userrule_64
->fw_icmp6types
));
1226 userrule_64
->fw_in_if
= rule
->fw_in_if
;
1227 userrule_64
->fw_out_if
= rule
->fw_out_if
;
1228 userrule_64
->timestamp
= rule
->timestamp
;
1229 userrule_64
->fw_un
.fu_divert_port
= rule
->fw_un
.fu_divert_port
;
1230 userrule_64
->fw_prot
= rule
->fw_prot
;
1231 userrule_64
->fw_nports
= rule
->fw_nports
;
1236 cp_from_user_64( struct ip6_fw_64
*userrule_64
, struct ip6_fw
*rule
)
1238 rule
->version
= userrule_64
->version
;
1239 rule
->context
= CAST_DOWN(void *, userrule_64
->context
);
1240 rule
->fw_pcnt
= userrule_64
->fw_pcnt
;
1241 rule
->fw_bcnt
= userrule_64
->fw_bcnt
;
1242 rule
->fw_src
= userrule_64
->fw_src
;
1243 rule
->fw_dst
= userrule_64
->fw_dst
;
1244 rule
->fw_smsk
= userrule_64
->fw_smsk
;
1245 rule
->fw_dmsk
= userrule_64
->fw_dmsk
;
1246 rule
->fw_number
= userrule_64
->fw_number
;
1247 rule
->fw_flg
= userrule_64
->fw_flg
;
1248 rule
->fw_ipflg
= userrule_64
->fw_ipflg
;
1249 bcopy( userrule_64
->fw_pts
, rule
->fw_pts
, IPV6_FW_MAX_PORTS
);
1250 rule
->fw_ip6opt
= userrule_64
->fw_ip6opt
;
1251 rule
->fw_ip6nopt
= userrule_64
->fw_ip6nopt
;
1252 rule
->fw_tcpf
= userrule_64
->fw_tcpf
;
1253 rule
->fw_tcpnf
= userrule_64
->fw_tcpnf
;
1254 bcopy( userrule_64
->fw_icmp6types
, rule
->fw_icmp6types
, sizeof(userrule_64
->fw_icmp6types
));
1255 rule
->fw_in_if
= userrule_64
->fw_in_if
;
1256 rule
->fw_out_if
= userrule_64
->fw_out_if
;
1257 rule
->timestamp
= CAST_DOWN( long, userrule_64
->timestamp
);
1258 rule
->fw_un
.fu_divert_port
= userrule_64
->fw_un
.fu_divert_port
;
1259 rule
->fw_prot
= userrule_64
->fw_prot
;
1260 rule
->fw_nports
= userrule_64
->fw_nports
;
1265 cp_to_user_32( struct ip6_fw_32
*userrule_32
, struct ip6_fw
*rule
)
1267 userrule_32
->version
= rule
->version
;
1268 userrule_32
->context
= CAST_DOWN_EXPLICIT( user32_addr_t
, rule
->context
);
1269 userrule_32
->fw_pcnt
= rule
->fw_pcnt
;
1270 userrule_32
->fw_bcnt
= rule
->fw_bcnt
;
1271 userrule_32
->fw_src
= rule
->fw_src
;
1272 userrule_32
->fw_dst
= rule
->fw_dst
;
1273 userrule_32
->fw_smsk
= rule
->fw_smsk
;
1274 userrule_32
->fw_dmsk
= rule
->fw_dmsk
;
1275 userrule_32
->fw_number
= rule
->fw_number
;
1276 userrule_32
->fw_flg
= rule
->fw_flg
;
1277 userrule_32
->fw_ipflg
= rule
->fw_ipflg
;
1278 bcopy( rule
->fw_pts
, userrule_32
->fw_pts
, IPV6_FW_MAX_PORTS
);
1279 userrule_32
->fw_ip6opt
= rule
->fw_ip6opt
;
1280 userrule_32
->fw_ip6nopt
= rule
->fw_ip6nopt
;
1281 userrule_32
->fw_tcpf
= rule
->fw_tcpf
;
1282 userrule_32
->fw_tcpnf
= rule
->fw_tcpnf
;
1283 bcopy( rule
->fw_icmp6types
, userrule_32
->fw_icmp6types
, sizeof(rule
->fw_icmp6types
));
1284 userrule_32
->fw_in_if
= rule
->fw_in_if
;
1285 userrule_32
->fw_out_if
= rule
->fw_out_if
;
1286 userrule_32
->timestamp
= rule
->timestamp
;
1287 userrule_32
->fw_un
.fu_divert_port
= rule
->fw_un
.fu_divert_port
;
1288 userrule_32
->fw_prot
= rule
->fw_prot
;
1289 userrule_32
->fw_nports
= rule
->fw_nports
;
1294 cp_from_user_32( struct ip6_fw_32
*userrule_32
, struct ip6_fw
*rule
)
1296 rule
->version
= userrule_32
->version
;
1297 rule
->context
= CAST_DOWN(void *, userrule_32
->context
);
1298 rule
->fw_pcnt
= userrule_32
->fw_pcnt
;
1299 rule
->fw_bcnt
= userrule_32
->fw_bcnt
;
1300 rule
->fw_src
= userrule_32
->fw_src
;
1301 rule
->fw_dst
= userrule_32
->fw_dst
;
1302 rule
->fw_smsk
= userrule_32
->fw_smsk
;
1303 rule
->fw_dmsk
= userrule_32
->fw_dmsk
;
1304 rule
->fw_number
= userrule_32
->fw_number
;
1305 rule
->fw_flg
= userrule_32
->fw_flg
;
1306 rule
->fw_ipflg
= userrule_32
->fw_ipflg
;
1307 bcopy( userrule_32
->fw_pts
, rule
->fw_pts
, IPV6_FW_MAX_PORTS
);
1308 rule
->fw_ip6opt
= userrule_32
->fw_ip6opt
;
1309 rule
->fw_ip6nopt
= userrule_32
->fw_ip6nopt
;
1310 rule
->fw_tcpf
= userrule_32
->fw_tcpf
;
1311 rule
->fw_tcpnf
= userrule_32
->fw_tcpnf
;
1312 bcopy( userrule_32
->fw_icmp6types
, rule
->fw_icmp6types
, sizeof(userrule_32
->fw_icmp6types
));
1313 rule
->fw_in_if
= userrule_32
->fw_in_if
;
1314 rule
->fw_out_if
= userrule_32
->fw_out_if
;
1315 rule
->timestamp
= CAST_DOWN(long, userrule_32
->timestamp
);
1316 rule
->fw_un
.fu_divert_port
= userrule_32
->fw_un
.fu_divert_port
;
1317 rule
->fw_prot
= userrule_32
->fw_prot
;
1318 rule
->fw_nports
= userrule_32
->fw_nports
;
1322 ip6_fw_ctl(struct sockopt
*sopt
)
1328 size_t userrulesize
;
1330 if (securelevel
>= 3 &&
1331 (sopt
->sopt_dir
!= SOPT_GET
|| sopt
->sopt_name
!= IPV6_FW_GET
)) {
1335 if (proc_is64bit(sopt
->sopt_p
)) {
1337 userrulesize
= sizeof(struct ip6_fw_64
);
1339 userrulesize
= sizeof(struct ip6_fw_32
);
1342 /* We ALWAYS expect the client to pass in a rule structure so that we can
1343 * check the version of the API that they are using. In the case of a
1344 * IPV6_FW_GET operation, the first rule of the output buffer passed to us
1345 * must have the version set. */
1346 if (!sopt
->sopt_val
|| sopt
->sopt_valsize
< userrulesize
) {
1350 /* save sopt->sopt_valsize */
1351 valsize
= sopt
->sopt_valsize
;
1354 struct ip6_fw_64 userrule_64
;
1356 if ((error
= sooptcopyin(sopt
, &userrule_64
, userrulesize
, userrulesize
))) {
1360 cp_from_user_64( &userrule_64
, &rule
);
1362 struct ip6_fw_32 userrule_32
;
1364 if ((error
= sooptcopyin(sopt
, &userrule_32
, userrulesize
, userrulesize
))) {
1368 cp_from_user_32( &userrule_32
, &rule
);
1371 if (rule
.version
!= IPV6_FW_CURRENT_API_VERSION
) {
1374 rule
.version
= 0xFFFFFFFF; /* version is meaningless once rules "make it in the door". */
1376 switch (sopt
->sopt_name
) {
1379 struct ip6_fw_chain
*fcp
;
1382 size_t rulesize
= 0;
1385 rulesize
= sizeof(struct ip6_fw_64
);
1387 rulesize
= sizeof(struct ip6_fw_32
);
1390 LIST_FOREACH(fcp
, &ip6_fw_chain
, chain
)
1393 buf
= _MALLOC(size
, M_TEMP
, M_WAITOK
);
1397 //struct ip6_fw *bp = buf;
1398 caddr_t bp
= (caddr_t
)buf
;
1400 LIST_FOREACH(fcp
, &ip6_fw_chain
, chain
)
1402 //bcopy(fcp->rule, bp, sizeof *bp);
1404 cp_to_user_64((struct ip6_fw_64
*)bp
, fcp
->rule
);
1406 cp_to_user_32((struct ip6_fw_32
*)bp
, fcp
->rule
);
1409 ((struct ip6_fw
*)bp
)->version
= IPV6_FW_CURRENT_API_VERSION
;
1416 sopt
->sopt_valsize
= valsize
;
1417 error
= sooptcopyout(sopt
, buf
, size
);
1425 while (ip6_fw_chain
.lh_first
&&
1426 ip6_fw_chain
.lh_first
->rule
->fw_number
!= (u_short
) - 1) {
1427 struct ip6_fw_chain
*fcp
= ip6_fw_chain
.lh_first
;
1428 LIST_REMOVE(ip6_fw_chain
.lh_first
, chain
);
1429 FREE(fcp
->rule
, M_IP6FW
);
1432 ip6fw_kev_post_msg(KEV_IP6FW_FLUSH
);
1436 error
= zero_entry6(&rule
);
1440 if (check_ip6fw_struct(&rule
)) {
1441 error
= add_entry6(&ip6_fw_chain
, &rule
);
1443 ip6fw_kev_post_msg(KEV_IP6FW_ADD
);
1449 struct ip6_fw_64 userrule_64
;
1450 cp_to_user_64( &userrule_64
, &rule
);
1451 error
= sooptcopyout(sopt
, &userrule_64
, userrulesize
);
1453 struct ip6_fw_32 userrule_32
;
1454 cp_to_user_32( &userrule_32
, &rule
);
1455 error
= sooptcopyout(sopt
, &userrule_32
, userrulesize
);
1460 if (rule
.fw_number
== (u_short
) - 1) {
1461 dprintf(("%s can't delete rule 65535\n", err_prefix
));
1464 error
= del_entry6(&ip6_fw_chain
, rule
.fw_number
);
1466 ip6fw_kev_post_msg(KEV_IP6FW_DEL
);
1471 dprintf(("%s invalid option %d\n", err_prefix
, sopt
->sopt_name
));
1481 struct ip6_fw default_rule
;
1483 ip6_fw_chk_ptr
= ip6_fw_chk
;
1484 ip6_fw_ctl_ptr
= ip6_fw_ctl
;
1485 LIST_INIT(&ip6_fw_chain
);
1487 bzero(&default_rule
, sizeof default_rule
);
1488 default_rule
.fw_prot
= IPPROTO_IPV6
;
1489 default_rule
.fw_number
= (u_short
) - 1;
1490 #ifdef IPV6FIREWALL_DEFAULT_TO_ACCEPT
1491 default_rule
.fw_flg
|= IPV6_FW_F_ACCEPT
;
1493 default_rule
.fw_flg
|= IPV6_FW_F_DENY
;
1495 default_rule
.fw_flg
|= IPV6_FW_F_IN
| IPV6_FW_F_OUT
;
1496 if (check_ip6fw_struct(&default_rule
) == NULL
||
1497 add_entry6(&ip6_fw_chain
, &default_rule
)) {
1498 panic("%s", __FUNCTION__
);
1501 printf("IPv6 packet filtering initialized, ");
1502 #ifdef IPV6FIREWALL_DEFAULT_TO_ACCEPT
1503 printf("default to accept, ");
1505 #ifndef IPV6FIREWALL_VERBOSE
1506 printf("logging disabled\n");
1508 if (fw6_verbose_limit
== 0) {
1509 printf("unlimited logging\n");
1511 printf("logging limited to %d packets/entry\n",