]> git.saurik.com Git - apple/xnu.git/blob - bsd/netinet6/ip6_fw.c
xnu-1456.1.26.tar.gz
[apple/xnu.git] / bsd / netinet6 / ip6_fw.c
1 /*
2 * Copyright (c) 2003-2008 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
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 $ */
31
32 /*
33 * Copyright (C) 1998, 1999, 2000 and 2001 WIDE Project.
34 * All rights reserved.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
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.
47 *
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
58 * SUCH DAMAGE.
59 */
60
61 /*
62 * Copyright (c) 1993 Daniel Boulet
63 * Copyright (c) 1994 Ugen J.S.Antsilevich
64 * Copyright (c) 1996 Alex Nash
65 *
66 * Redistribution and use in source forms, with and without modification,
67 * are permitted provided that this entire comment appears intact.
68 *
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.
72 *
73 * This software is provided ``AS IS'' without any warranties of any kind.
74 */
75
76 /*
77 * Implement IPv6 packet firewall
78 */
79
80
81 #ifdef IP6DIVERT
82 #error "NOT SUPPORTED IPV6 DIVERT"
83 #endif
84 #ifdef IP6FW_DIVERT_RESTART
85 #error "NOT SUPPORTED IPV6 DIVERT"
86 #endif
87
88 #include <string.h>
89 #include <machine/spl.h>
90
91 #include <sys/param.h>
92 #include <sys/systm.h>
93 #include <sys/malloc.h>
94 #include <sys/mbuf.h>
95 #include <sys/queue.h>
96 #include <sys/kernel.h>
97 #include <sys/socket.h>
98 #include <sys/socketvar.h>
99 #include <sys/syslog.h>
100 #include <sys/lock.h>
101 #include <sys/time.h>
102 #include <sys/kern_event.h>
103
104 #include <net/if.h>
105 #include <net/route.h>
106 #include <netinet/in_systm.h>
107 #include <netinet/in.h>
108 #include <netinet/ip.h>
109
110 #include <netinet/ip6.h>
111 #include <netinet6/ip6_var.h>
112 #include <netinet6/in6_var.h>
113 #include <netinet/icmp6.h>
114
115 #include <netinet/in_pcb.h>
116
117 #include <netinet6/ip6_fw.h>
118 #include <netinet/ip_var.h>
119 #include <netinet/tcp.h>
120 #include <netinet/tcp_seq.h>
121 #include <netinet/tcp_timer.h>
122 #include <netinet/tcp_var.h>
123 #include <netinet/udp.h>
124
125 #include <sys/sysctl.h>
126
127 #include <net/net_osdep.h>
128
129 MALLOC_DEFINE(M_IP6FW, "Ip6Fw/Ip6Acct", "Ip6Fw/Ip6Acct chain's");
130
131 static int fw6_debug = 0;
132 #ifdef IPV6FIREWALL_VERBOSE
133 static int fw6_verbose = 1;
134 #else
135 static int fw6_verbose = 0;
136 #endif
137 #ifdef IPV6FIREWALL_VERBOSE_LIMIT
138 static int fw6_verbose_limit = IPV6FIREWALL_VERBOSE_LIMIT;
139 #else
140 static int fw6_verbose_limit = 0;
141 #endif
142
143 LIST_HEAD (ip6_fw_head, ip6_fw_chain) ip6_fw_chain;
144
145 static void ip6fw_kev_post_msg(u_int32_t );
146
147 #ifdef SYSCTL_NODE
148 static int ip6fw_sysctl SYSCTL_HANDLER_ARGS;
149
150 SYSCTL_DECL(_net_inet6_ip6);
151 SYSCTL_NODE(_net_inet6_ip6, OID_AUTO, fw, CTLFLAG_RW|CTLFLAG_LOCKED, 0, "Firewall");
152 SYSCTL_PROC(_net_inet6_ip6_fw, OID_AUTO, enable,
153 CTLTYPE_INT | CTLFLAG_RW,
154 &ip6_fw_enable, 0, ip6fw_sysctl, "I", "Enable ip6fw");
155 SYSCTL_INT(_net_inet6_ip6_fw, OID_AUTO, debug, CTLFLAG_RW, &fw6_debug, 0, "");
156 SYSCTL_INT(_net_inet6_ip6_fw, OID_AUTO, verbose, CTLFLAG_RW, &fw6_verbose, 0, "");
157 SYSCTL_INT(_net_inet6_ip6_fw, OID_AUTO, verbose_limit, CTLFLAG_RW, &fw6_verbose_limit, 0, "");
158
159 static int
160 ip6fw_sysctl SYSCTL_HANDLER_ARGS
161 {
162 #pragma unused(arg1, arg2)
163 int error;
164
165 error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
166 if (error || !req->newptr)
167 return (error);
168
169 ip6fw_kev_post_msg(KEV_IP6FW_ENABLE);
170
171 return error;
172 }
173
174 #endif
175
176 #define dprintf(a) do { \
177 if (fw6_debug) \
178 printf a; \
179 } while (0)
180 #define SNPARGS(buf, len) buf + len, sizeof(buf) > len ? sizeof(buf) - len : 0
181
182 static int add_entry6 __P((struct ip6_fw_head *chainptr, struct ip6_fw *frwl));
183 static int del_entry6 __P((struct ip6_fw_head *chainptr, u_short number));
184 static int zero_entry6 __P((struct ip6_fw *frwl));
185 static struct ip6_fw *check_ip6fw_struct __P((struct ip6_fw *m));
186 static int ip6opts_match __P((struct ip6_hdr **ip6, struct ip6_fw *f,
187 struct mbuf **m,
188 int *off, int *nxt, u_short *offset));
189 static int port_match6 __P((u_short *portptr, int nports, u_short port,
190 int range_flag));
191 static int tcp6flg_match __P((struct tcphdr *tcp6, struct ip6_fw *f));
192 static int icmp6type_match __P((struct icmp6_hdr * icmp, struct ip6_fw * f));
193 static void ip6fw_report __P((struct ip6_fw *f, struct ip6_hdr *ip6,
194 struct ifnet *rif, struct ifnet *oif, int off, int nxt));
195
196 static int ip6_fw_chk __P((struct ip6_hdr **pip6,
197 struct ifnet *oif, u_int16_t *cookie, struct mbuf **m));
198 static int ip6_fw_ctl __P((struct sockopt *));
199 static void cp_to_user_64( struct ip6_fw_64 *userrule_64, struct ip6_fw *rule);
200 static void cp_from_user_64( struct ip6_fw_64 *userrule_64, struct ip6_fw *rule);
201 static void cp_to_user_32( struct ip6_fw_32 *userrule_32, struct ip6_fw *rule);
202 static void cp_from_user_32( struct ip6_fw_32 *userrule_32, struct ip6_fw *rule);
203
204 static char err_prefix[] = "ip6_fw_ctl:";
205 extern lck_mtx_t *ip6_mutex;
206
207 /*
208 * Returns 1 if the port is matched by the vector, 0 otherwise
209 */
210 static
211 __inline int
212 port_match6(u_short *portptr, int nports, u_short port, int range_flag)
213 {
214 if (!nports)
215 return 1;
216 if (range_flag) {
217 if (portptr[0] <= port && port <= portptr[1]) {
218 return 1;
219 }
220 nports -= 2;
221 portptr += 2;
222 }
223 while (nports-- > 0) {
224 if (*portptr++ == port) {
225 return 1;
226 }
227 }
228 return 0;
229 }
230
231 static int
232 tcp6flg_match(struct tcphdr *tcp6, struct ip6_fw *f)
233 {
234 u_char flg_set, flg_clr;
235
236 /*
237 * If an established connection is required, reject packets that
238 * have only SYN of RST|ACK|SYN set. Otherwise, fall through to
239 * other flag requirements.
240 */
241 if ((f->fw_ipflg & IPV6_FW_IF_TCPEST) &&
242 ((tcp6->th_flags & (IPV6_FW_TCPF_RST | IPV6_FW_TCPF_ACK |
243 IPV6_FW_TCPF_SYN)) == IPV6_FW_TCPF_SYN))
244 return 0;
245
246 flg_set = tcp6->th_flags & f->fw_tcpf;
247 flg_clr = tcp6->th_flags & f->fw_tcpnf;
248
249 if (flg_set != f->fw_tcpf)
250 return 0;
251 if (flg_clr)
252 return 0;
253
254 return 1;
255 }
256
257 static int
258 icmp6type_match(struct icmp6_hdr *icmp6, struct ip6_fw *f)
259 {
260 int type;
261
262 if (!(f->fw_flg & IPV6_FW_F_ICMPBIT))
263 return(1);
264
265 type = icmp6->icmp6_type;
266
267 /* check for matching type in the bitmap */
268 if (type < IPV6_FW_ICMPTYPES_DIM * sizeof(unsigned) * 8 &&
269 (f->fw_icmp6types[type / (sizeof(unsigned) * 8)] &
270 (1U << (type % (8 * sizeof(unsigned))))))
271 return(1);
272
273 return(0); /* no match */
274 }
275
276 static int
277 is_icmp6_query(struct ip6_hdr *ip6, int off)
278 {
279 const struct icmp6_hdr *icmp6;
280 int icmp6_type;
281
282 icmp6 = (struct icmp6_hdr *)((caddr_t)ip6 + off);
283 icmp6_type = icmp6->icmp6_type;
284
285 if (icmp6_type == ICMP6_ECHO_REQUEST ||
286 icmp6_type == ICMP6_MEMBERSHIP_QUERY ||
287 icmp6_type == ICMP6_WRUREQUEST ||
288 icmp6_type == ICMP6_FQDN_QUERY ||
289 icmp6_type == ICMP6_NI_QUERY)
290 return(1);
291
292 return(0);
293 }
294
295 static int
296 ip6opts_match(struct ip6_hdr **pip6, struct ip6_fw *f, struct mbuf **m,
297 int *off, int *nxt, u_short *offset)
298 {
299 int len;
300 struct ip6_hdr *ip6 = *pip6;
301 struct ip6_ext *ip6e;
302 u_char opts, nopts, nopts_sve;
303
304 opts = f->fw_ip6opt;
305 nopts = nopts_sve = f->fw_ip6nopt;
306
307 *nxt = ip6->ip6_nxt;
308 *off = sizeof(struct ip6_hdr);
309 len = ntohs(ip6->ip6_plen) + sizeof(struct ip6_hdr);
310 while (*off < len) {
311 ip6e = (struct ip6_ext *)((caddr_t) ip6 + *off);
312 if ((*m)->m_len < *off + sizeof(*ip6e))
313 goto opts_check; /* XXX */
314
315 switch(*nxt) {
316 case IPPROTO_FRAGMENT:
317 if ((*m)->m_len >= *off + sizeof(struct ip6_frag)) {
318 struct ip6_frag *ip6f;
319
320 ip6f = (struct ip6_frag *) ((caddr_t)ip6 + *off);
321 *offset = ip6f->ip6f_offlg & IP6F_OFF_MASK;
322 }
323 opts &= ~IPV6_FW_IP6OPT_FRAG;
324 nopts &= ~IPV6_FW_IP6OPT_FRAG;
325 *off += sizeof(struct ip6_frag);
326 break;
327 case IPPROTO_AH:
328 opts &= ~IPV6_FW_IP6OPT_AH;
329 nopts &= ~IPV6_FW_IP6OPT_AH;
330 *off += (ip6e->ip6e_len + 2) << 2;
331 break;
332 default:
333 switch (*nxt) {
334 case IPPROTO_HOPOPTS:
335 opts &= ~IPV6_FW_IP6OPT_HOPOPT;
336 nopts &= ~IPV6_FW_IP6OPT_HOPOPT;
337 break;
338 case IPPROTO_ROUTING:
339 opts &= ~IPV6_FW_IP6OPT_ROUTE;
340 nopts &= ~IPV6_FW_IP6OPT_ROUTE;
341 break;
342 case IPPROTO_ESP:
343 opts &= ~IPV6_FW_IP6OPT_ESP;
344 nopts &= ~IPV6_FW_IP6OPT_ESP;
345 break;
346 case IPPROTO_NONE:
347 opts &= ~IPV6_FW_IP6OPT_NONXT;
348 nopts &= ~IPV6_FW_IP6OPT_NONXT;
349 goto opts_check;
350 break;
351 case IPPROTO_DSTOPTS:
352 opts &= ~IPV6_FW_IP6OPT_OPTS;
353 nopts &= ~IPV6_FW_IP6OPT_OPTS;
354 break;
355 default:
356 goto opts_check;
357 break;
358 }
359 *off += (ip6e->ip6e_len + 1) << 3;
360 break;
361 }
362 *nxt = ip6e->ip6e_nxt;
363
364 }
365 opts_check:
366 if (f->fw_ip6opt == f->fw_ip6nopt) /* XXX */
367 return 1;
368
369 if (opts == 0 && nopts == nopts_sve)
370 return 1;
371 else
372 return 0;
373 }
374
375 static
376 __inline int
377 iface_match(struct ifnet *ifp, union ip6_fw_if *ifu, int byname)
378 {
379 /* Check by name or by IP address */
380 if (byname) {
381 /* Check unit number (-1 is wildcard) */
382 if (ifu->fu_via_if.unit != -1
383 && ifp->if_unit != ifu->fu_via_if.unit)
384 return(0);
385 /* Check name */
386 if (strncmp(ifp->if_name, ifu->fu_via_if.name, IP6FW_IFNLEN))
387 return(0);
388 return(1);
389 } else if (!IN6_IS_ADDR_UNSPECIFIED(&ifu->fu_via_ip6)) { /* Zero == wildcard */
390 struct ifaddr *ia;
391
392 ifnet_lock_shared(ifp);
393 for (ia = ifp->if_addrlist.tqh_first; ia; ia = ia->ifa_list.tqe_next)
394 {
395
396 if (ia->ifa_addr == NULL)
397 continue;
398 if (ia->ifa_addr->sa_family != AF_INET6)
399 continue;
400 if (!IN6_ARE_ADDR_EQUAL(&ifu->fu_via_ip6,
401 &(((struct sockaddr_in6 *)
402 (ia->ifa_addr))->sin6_addr)))
403 continue;
404 ifnet_lock_done(ifp);
405 return(1);
406 }
407 ifnet_lock_done(ifp);
408 return(0);
409 }
410 return(1);
411 }
412
413 static void
414 ip6fw_report(struct ip6_fw *f, struct ip6_hdr *ip6,
415 struct ifnet *rif, struct ifnet *oif, int off, int nxt)
416 {
417 static int counter;
418 struct tcphdr *const tcp6 = (struct tcphdr *) ((caddr_t) ip6+ off);
419 struct udphdr *const udp = (struct udphdr *) ((caddr_t) ip6+ off);
420 struct icmp6_hdr *const icmp6 = (struct icmp6_hdr *) ((caddr_t) ip6+ off);
421 int count;
422 const char *action;
423 char action2[32], proto[102], name[18];
424 int len;
425
426 count = f ? f->fw_pcnt : ++counter;
427 if (fw6_verbose_limit != 0 && count > fw6_verbose_limit)
428 return;
429
430 /* Print command name */
431 snprintf(SNPARGS(name, 0), "ip6fw: %d", f ? f->fw_number : -1);
432
433 action = action2;
434 if (!f)
435 action = "Refuse";
436 else {
437 switch (f->fw_flg & IPV6_FW_F_COMMAND) {
438 case IPV6_FW_F_DENY:
439 action = "Deny";
440 break;
441 case IPV6_FW_F_REJECT:
442 if (f->fw_reject_code == IPV6_FW_REJECT_RST)
443 action = "Reset";
444 else
445 action = "Unreach";
446 break;
447 case IPV6_FW_F_ACCEPT:
448 action = "Accept";
449 break;
450 case IPV6_FW_F_COUNT:
451 action = "Count";
452 break;
453 case IPV6_FW_F_DIVERT:
454 snprintf(SNPARGS(action2, 0), "Divert %d",
455 f->fw_divert_port);
456 break;
457 case IPV6_FW_F_TEE:
458 snprintf(SNPARGS(action2, 0), "Tee %d",
459 f->fw_divert_port);
460 break;
461 case IPV6_FW_F_SKIPTO:
462 snprintf(SNPARGS(action2, 0), "SkipTo %d",
463 f->fw_skipto_rule);
464 break;
465 default:
466 action = "UNKNOWN";
467 break;
468 }
469 }
470
471 switch (nxt) {
472 case IPPROTO_TCP:
473 len = snprintf(SNPARGS(proto, 0), "TCP [%s]",
474 ip6_sprintf(&ip6->ip6_src));
475 if (off > 0)
476 len += snprintf(SNPARGS(proto, len), ":%d ",
477 ntohs(tcp6->th_sport));
478 else
479 len += snprintf(SNPARGS(proto, len), " ");
480 len += snprintf(SNPARGS(proto, len), "[%s]",
481 ip6_sprintf(&ip6->ip6_dst));
482 if (off > 0)
483 snprintf(SNPARGS(proto, len), ":%d",
484 ntohs(tcp6->th_dport));
485 break;
486 case IPPROTO_UDP:
487 len = snprintf(SNPARGS(proto, 0), "UDP [%s]",
488 ip6_sprintf(&ip6->ip6_src));
489 if (off > 0)
490 len += snprintf(SNPARGS(proto, len), ":%d ",
491 ntohs(udp->uh_sport));
492 else
493 len += snprintf(SNPARGS(proto, len), " ");
494 len += snprintf(SNPARGS(proto, len), "[%s]",
495 ip6_sprintf(&ip6->ip6_dst));
496 if (off > 0)
497 snprintf(SNPARGS(proto, len), ":%d",
498 ntohs(udp->uh_dport));
499 break;
500 case IPPROTO_ICMPV6:
501 if (off > 0)
502 len = snprintf(SNPARGS(proto, 0), "IPV6-ICMP:%u.%u ",
503 icmp6->icmp6_type, icmp6->icmp6_code);
504 else
505 len = snprintf(SNPARGS(proto, 0), "IPV6-ICMP ");
506 len += snprintf(SNPARGS(proto, len), "[%s]",
507 ip6_sprintf(&ip6->ip6_src));
508 snprintf(SNPARGS(proto, len), " [%s]",
509 ip6_sprintf(&ip6->ip6_dst));
510 break;
511 default:
512 len = snprintf(SNPARGS(proto, 0), "P:%d [%s]", nxt,
513 ip6_sprintf(&ip6->ip6_src));
514 snprintf(SNPARGS(proto, len), " [%s]",
515 ip6_sprintf(&ip6->ip6_dst));
516 break;
517 }
518
519 if (oif)
520 log(LOG_AUTHPRIV | LOG_INFO, "%s %s %s out via %s\n",
521 name, action, proto, if_name(oif));
522 else if (rif)
523 log(LOG_AUTHPRIV | LOG_INFO, "%s %s %s in via %s\n",
524 name, action, proto, if_name(rif));
525 else
526 log(LOG_AUTHPRIV | LOG_INFO, "%s %s %s",
527 name, action, proto);
528 if (fw6_verbose_limit != 0 && count == fw6_verbose_limit)
529 log(LOG_AUTHPRIV | LOG_INFO, "ip6fw: limit reached on entry %d\n",
530 f ? f->fw_number : -1);
531 }
532
533 /*
534 * Parameters:
535 *
536 * ip Pointer to packet header (struct ip6_hdr *)
537 * hlen Packet header length
538 * oif Outgoing interface, or NULL if packet is incoming
539 * #ifndef IP6FW_DIVERT_RESTART
540 * *cookie Ignore all divert/tee rules to this port (if non-zero)
541 * #else
542 * *cookie Skip up to the first rule past this rule number;
543 * #endif
544 * *m The packet; we set to NULL when/if we nuke it.
545 *
546 * Return value:
547 *
548 * 0 The packet is to be accepted and routed normally OR
549 * the packet was denied/rejected and has been dropped;
550 * in the latter case, *m is equal to NULL upon return.
551 * port Divert the packet to port.
552 */
553
554 static int
555 ip6_fw_chk(struct ip6_hdr **pip6,
556 struct ifnet *oif, u_int16_t *cookie, struct mbuf **m)
557 {
558 struct ip6_fw_chain *chain;
559 struct ip6_fw *rule = NULL;
560 struct ip6_hdr *ip6 = *pip6;
561 struct ifnet *const rif = ((*m)->m_flags & M_LOOP) ? ifunit("lo0") : (*m)->m_pkthdr.rcvif;
562 u_short offset = 0;
563 int off = sizeof(struct ip6_hdr), nxt = ip6->ip6_nxt;
564 u_short src_port, dst_port;
565 #ifdef IP6FW_DIVERT_RESTART
566 u_int16_t skipto = *cookie;
567 #else
568 u_int16_t ignport = ntohs(*cookie);
569 #endif
570 struct timeval timenow;
571
572 getmicrotime(&timenow);
573
574 *cookie = 0;
575 /*
576 * Go down the chain, looking for enlightment
577 * #ifdef IP6FW_DIVERT_RESTART
578 * If we've been asked to start at a given rule immediatly, do so.
579 * #endif
580 */
581 chain = LIST_FIRST(&ip6_fw_chain);
582 #ifdef IP6FW_DIVERT_RESTART
583 if (skipto) {
584 if (skipto >= 65535)
585 goto dropit;
586 while (chain && (chain->rule->fw_number <= skipto)) {
587 chain = LIST_NEXT(chain, chain);
588 }
589 if (! chain) goto dropit;
590 }
591 #endif /* IP6FW_DIVERT_RESTART */
592 for (; chain; chain = LIST_NEXT(chain, chain)) {
593 struct ip6_fw *const f = chain->rule;
594
595 if (oif) {
596 /* Check direction outbound */
597 if (!(f->fw_flg & IPV6_FW_F_OUT))
598 continue;
599 } else {
600 /* Check direction inbound */
601 if (!(f->fw_flg & IPV6_FW_F_IN))
602 continue;
603 }
604
605 #define IN6_ARE_ADDR_MASKEQUAL(x,y,z) (\
606 (((x)->s6_addr32[0] & (y)->s6_addr32[0]) == (z)->s6_addr32[0]) && \
607 (((x)->s6_addr32[1] & (y)->s6_addr32[1]) == (z)->s6_addr32[1]) && \
608 (((x)->s6_addr32[2] & (y)->s6_addr32[2]) == (z)->s6_addr32[2]) && \
609 (((x)->s6_addr32[3] & (y)->s6_addr32[3]) == (z)->s6_addr32[3]))
610
611 /* If src-addr doesn't match, not this rule. */
612 if (((f->fw_flg & IPV6_FW_F_INVSRC) != 0) ^
613 (!IN6_ARE_ADDR_MASKEQUAL(&ip6->ip6_src,&f->fw_smsk,&f->fw_src)))
614 continue;
615
616 /* If dest-addr doesn't match, not this rule. */
617 if (((f->fw_flg & IPV6_FW_F_INVDST) != 0) ^
618 (!IN6_ARE_ADDR_MASKEQUAL(&ip6->ip6_dst,&f->fw_dmsk,&f->fw_dst)))
619 continue;
620
621 #undef IN6_ARE_ADDR_MASKEQUAL
622 /* Interface check */
623 if ((f->fw_flg & IF6_FW_F_VIAHACK) == IF6_FW_F_VIAHACK) {
624 struct ifnet *const iface = oif ? oif : rif;
625
626 /* Backwards compatibility hack for "via" */
627 if (!iface || !iface_match(iface,
628 &f->fw_in_if, f->fw_flg & IPV6_FW_F_OIFNAME))
629 continue;
630 } else {
631 /* Check receive interface */
632 if ((f->fw_flg & IPV6_FW_F_IIFACE)
633 && (!rif || !iface_match(rif,
634 &f->fw_in_if, f->fw_flg & IPV6_FW_F_IIFNAME)))
635 continue;
636 /* Check outgoing interface */
637 if ((f->fw_flg & IPV6_FW_F_OIFACE)
638 && (!oif || !iface_match(oif,
639 &f->fw_out_if, f->fw_flg & IPV6_FW_F_OIFNAME)))
640 continue;
641 }
642
643 /* Check IP options */
644 if (!ip6opts_match(&ip6, f, m, &off, &nxt, &offset))
645 continue;
646
647 /* Fragments */
648 if ((f->fw_flg & IPV6_FW_F_FRAG) && !offset)
649 continue;
650
651 /* Check protocol; if wildcard, match */
652 if (f->fw_prot == IPPROTO_IPV6)
653 goto got_match;
654
655 /* If different, don't match */
656 if (nxt != f->fw_prot)
657 continue;
658
659 #define PULLUP_TO(len) do { \
660 if ((*m)->m_len < (len) \
661 && (*m = m_pullup(*m, (len))) == 0) { \
662 goto dropit; \
663 } \
664 *pip6 = ip6 = mtod(*m, struct ip6_hdr *); \
665 } while (0)
666
667 /* Protocol specific checks */
668 switch (nxt) {
669 case IPPROTO_TCP:
670 {
671 struct tcphdr *tcp6;
672
673 if (offset == 1) { /* cf. RFC 1858 */
674 PULLUP_TO(off + 4); /* XXX ? */
675 goto bogusfrag;
676 }
677 if (offset != 0) {
678 /*
679 * TCP flags and ports aren't available in this
680 * packet -- if this rule specified either one,
681 * we consider the rule a non-match.
682 */
683 if (f->fw_nports != 0 ||
684 f->fw_tcpf != f->fw_tcpnf)
685 continue;
686
687 break;
688 }
689 PULLUP_TO(off + 14);
690 tcp6 = (struct tcphdr *) ((caddr_t)ip6 + off);
691 if (((f->fw_tcpf != f->fw_tcpnf) ||
692 (f->fw_ipflg & IPV6_FW_IF_TCPEST)) &&
693 !tcp6flg_match(tcp6, f))
694 continue;
695 src_port = ntohs(tcp6->th_sport);
696 dst_port = ntohs(tcp6->th_dport);
697 goto check_ports;
698 }
699
700 case IPPROTO_UDP:
701 {
702 struct udphdr *udp;
703
704 if (offset != 0) {
705 /*
706 * Port specification is unavailable -- if this
707 * rule specifies a port, we consider the rule
708 * a non-match.
709 */
710 if (f->fw_nports != 0)
711 continue;
712
713 break;
714 }
715 PULLUP_TO(off + 4);
716 udp = (struct udphdr *) ((caddr_t)ip6 + off);
717 src_port = ntohs(udp->uh_sport);
718 dst_port = ntohs(udp->uh_dport);
719 check_ports:
720 if (!port_match6(&f->fw_pts[0],
721 IPV6_FW_GETNSRCP(f), src_port,
722 f->fw_flg & IPV6_FW_F_SRNG))
723 continue;
724 if (!port_match6(&f->fw_pts[IPV6_FW_GETNSRCP(f)],
725 IPV6_FW_GETNDSTP(f), dst_port,
726 f->fw_flg & IPV6_FW_F_DRNG))
727 continue;
728 break;
729 }
730
731 case IPPROTO_ICMPV6:
732 {
733 struct icmp6_hdr *icmp;
734
735 if (offset != 0) /* Type isn't valid */
736 break;
737 PULLUP_TO(off + 2);
738 icmp = (struct icmp6_hdr *) ((caddr_t)ip6 + off);
739 if (!icmp6type_match(icmp, f))
740 continue;
741 break;
742 }
743 #undef PULLUP_TO
744
745 bogusfrag:
746 if (fw6_verbose)
747 ip6fw_report(NULL, ip6, rif, oif, off, nxt);
748 goto dropit;
749 }
750
751 got_match:
752 #ifndef IP6FW_DIVERT_RESTART
753 /* Ignore divert/tee rule if socket port is "ignport" */
754 switch (f->fw_flg & IPV6_FW_F_COMMAND) {
755 case IPV6_FW_F_DIVERT:
756 case IPV6_FW_F_TEE:
757 if (f->fw_divert_port == ignport)
758 continue; /* ignore this rule */
759 break;
760 }
761
762 #endif /* IP6FW_DIVERT_RESTART */
763 /* Update statistics */
764 f->fw_pcnt += 1;
765 f->fw_bcnt += ntohs(ip6->ip6_plen);
766 f->timestamp = timenow.tv_sec;
767
768 /* Log to console if desired */
769 if ((f->fw_flg & IPV6_FW_F_PRN) && fw6_verbose)
770 ip6fw_report(f, ip6, rif, oif, off, nxt);
771
772 /* Take appropriate action */
773 switch (f->fw_flg & IPV6_FW_F_COMMAND) {
774 case IPV6_FW_F_ACCEPT:
775 return(0);
776 case IPV6_FW_F_COUNT:
777 continue;
778 case IPV6_FW_F_DIVERT:
779 #ifdef IP6FW_DIVERT_RESTART
780 *cookie = f->fw_number;
781 #else
782 *cookie = htons(f->fw_divert_port);
783 #endif /* IP6FW_DIVERT_RESTART */
784 return(f->fw_divert_port);
785 case IPV6_FW_F_TEE:
786 /*
787 * XXX someday tee packet here, but beware that you
788 * can't use m_copym() or m_copypacket() because
789 * the divert input routine modifies the mbuf
790 * (and these routines only increment reference
791 * counts in the case of mbuf clusters), so need
792 * to write custom routine.
793 */
794 continue;
795 case IPV6_FW_F_SKIPTO:
796 #ifdef DIAGNOSTIC
797 while (chain->chain.le_next
798 && chain->chain.le_next->rule->fw_number
799 < f->fw_skipto_rule)
800 #else
801 while (chain->chain.le_next->rule->fw_number
802 < f->fw_skipto_rule)
803 #endif
804 chain = chain->chain.le_next;
805 continue;
806 }
807
808 /* Deny/reject this packet using this rule */
809 rule = f;
810 break;
811 }
812
813 #ifdef DIAGNOSTIC
814 /* Rule 65535 should always be there and should always match */
815 if (!chain)
816 panic("ip6_fw: chain");
817 #endif
818
819 /*
820 * At this point, we're going to drop the packet.
821 * Send a reject notice if all of the following are true:
822 *
823 * - The packet matched a reject rule
824 * - The packet is not an ICMP packet, or is an ICMP query packet
825 * - The packet is not a multicast or broadcast packet
826 */
827 if ((rule->fw_flg & IPV6_FW_F_COMMAND) == IPV6_FW_F_REJECT
828 && (nxt != IPPROTO_ICMPV6 || is_icmp6_query(ip6, off))
829 && !((*m)->m_flags & (M_BCAST|M_MCAST))
830 && !IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
831 switch (rule->fw_reject_code) {
832 case IPV6_FW_REJECT_RST:
833 {
834 struct tcphdr *const tcp =
835 (struct tcphdr *) ((caddr_t)ip6 + off);
836 struct {
837 struct ip6_hdr ip6;
838 struct tcphdr th;
839 } ti;
840 tcp_seq ack, seq;
841 int flags;
842
843 if (offset != 0 || (tcp->th_flags & TH_RST))
844 break;
845
846 ti.ip6 = *ip6;
847 ti.th = *tcp;
848 ti.th.th_seq = ntohl(ti.th.th_seq);
849 ti.th.th_ack = ntohl(ti.th.th_ack);
850 ti.ip6.ip6_nxt = IPPROTO_TCP;
851 if (ti.th.th_flags & TH_ACK) {
852 ack = 0;
853 seq = ti.th.th_ack;
854 flags = TH_RST;
855 } else {
856 ack = ti.th.th_seq;
857 if (((*m)->m_flags & M_PKTHDR) != 0) {
858 ack += (*m)->m_pkthdr.len - off
859 - (ti.th.th_off << 2);
860 } else if (ip6->ip6_plen) {
861 ack += ntohs(ip6->ip6_plen) + sizeof(*ip6)
862 - off - (ti.th.th_off << 2);
863 } else {
864 m_freem(*m);
865 *m = 0;
866 break;
867 }
868 seq = 0;
869 flags = TH_RST|TH_ACK;
870 }
871 bcopy(&ti, ip6, sizeof(ti));
872 tcp_respond(NULL, ip6, (struct tcphdr *)(ip6 + 1),
873 *m, ack, seq, flags, IFSCOPE_NONE);
874 *m = NULL;
875 break;
876 }
877 default: /* Send an ICMP unreachable using code */
878 if (oif)
879 (*m)->m_pkthdr.rcvif = oif;
880 lck_mtx_assert(ip6_mutex, LCK_MTX_ASSERT_OWNED);
881 lck_mtx_unlock(ip6_mutex);
882 icmp6_error(*m, ICMP6_DST_UNREACH,
883 rule->fw_reject_code, 0);
884 lck_mtx_lock(ip6_mutex);
885 *m = NULL;
886 break;
887 }
888 }
889
890 dropit:
891 /*
892 * Finally, drop the packet.
893 */
894 if (*m) {
895 m_freem(*m);
896 *m = NULL;
897 }
898 return(0);
899 }
900
901 static int
902 add_entry6(struct ip6_fw_head *chainptr, struct ip6_fw *frwl)
903 {
904 struct ip6_fw *ftmp = 0;
905 struct ip6_fw_chain *fwc = 0, *fcp, *fcpl = 0;
906 u_short nbr = 0;
907 int s;
908
909 fwc = _MALLOC(sizeof *fwc, M_IP6FW, M_WAITOK);
910 ftmp = _MALLOC(sizeof *ftmp, M_IP6FW, M_WAITOK);
911 if (!fwc || !ftmp) {
912 dprintf(("%s malloc said no\n", err_prefix));
913 if (fwc) FREE(fwc, M_IP6FW);
914 if (ftmp) FREE(ftmp, M_IP6FW);
915 return (ENOSPC);
916 }
917
918 bcopy(frwl, ftmp, sizeof(struct ip6_fw));
919 ftmp->fw_in_if.fu_via_if.name[IP6FW_IFNLEN - 1] = '\0';
920 ftmp->fw_pcnt = 0L;
921 ftmp->fw_bcnt = 0L;
922 fwc->rule = ftmp;
923
924 s = splnet();
925
926 if (!chainptr->lh_first) {
927 LIST_INSERT_HEAD(chainptr, fwc, chain);
928 splx(s);
929 return(0);
930 } else if (ftmp->fw_number == (u_short)-1) {
931 if (fwc) FREE(fwc, M_IP6FW);
932 if (ftmp) FREE(ftmp, M_IP6FW);
933 splx(s);
934 dprintf(("%s bad rule number\n", err_prefix));
935 return (EINVAL);
936 }
937
938 /* If entry number is 0, find highest numbered rule and add 100 */
939 if (ftmp->fw_number == 0) {
940 for (fcp = chainptr->lh_first; fcp; fcp = fcp->chain.le_next) {
941 if (fcp->rule->fw_number != (u_short)-1)
942 nbr = fcp->rule->fw_number;
943 else
944 break;
945 }
946 if (nbr < (u_short)-1 - 100)
947 nbr += 100;
948 ftmp->fw_number = nbr;
949 }
950
951 /* Got a valid number; now insert it, keeping the list ordered */
952 for (fcp = chainptr->lh_first; fcp; fcp = fcp->chain.le_next) {
953 if (fcp->rule->fw_number > ftmp->fw_number) {
954 if (fcpl) {
955 LIST_INSERT_AFTER(fcpl, fwc, chain);
956 } else {
957 LIST_INSERT_HEAD(chainptr, fwc, chain);
958 }
959 break;
960 } else {
961 fcpl = fcp;
962 }
963 }
964
965 splx(s);
966 return (0);
967 }
968
969 static int
970 del_entry6(struct ip6_fw_head *chainptr, u_short number)
971 {
972 struct ip6_fw_chain *fcp;
973 int s;
974
975 s = splnet();
976
977 fcp = chainptr->lh_first;
978 if (number != (u_short)-1) {
979 for (; fcp; fcp = fcp->chain.le_next) {
980 if (fcp->rule->fw_number == number) {
981 LIST_REMOVE(fcp, chain);
982 splx(s);
983 FREE(fcp->rule, M_IP6FW);
984 FREE(fcp, M_IP6FW);
985 return 0;
986 }
987 }
988 }
989
990 splx(s);
991 return (EINVAL);
992 }
993
994 static int
995 zero_entry6(struct ip6_fw *frwl)
996 {
997 struct ip6_fw_chain *fcp;
998 int s;
999
1000 /*
1001 * It's possible to insert multiple chain entries with the
1002 * same number, so we don't stop after finding the first
1003 * match if zeroing a specific entry.
1004 */
1005 s = splnet();
1006 for (fcp = ip6_fw_chain.lh_first; fcp; fcp = fcp->chain.le_next)
1007 if (!frwl || frwl->fw_number == 0 || frwl->fw_number == fcp->rule->fw_number) {
1008 fcp->rule->fw_bcnt = fcp->rule->fw_pcnt = 0;
1009 fcp->rule->timestamp = 0;
1010 }
1011 splx(s);
1012
1013 if (fw6_verbose) {
1014 if (frwl)
1015 log(LOG_AUTHPRIV | LOG_NOTICE,
1016 "ip6fw: Entry %d cleared.\n", frwl->fw_number);
1017 else
1018 log(LOG_AUTHPRIV | LOG_NOTICE,
1019 "ip6fw: Accounting cleared.\n");
1020 }
1021
1022 return(0);
1023 }
1024
1025 static struct ip6_fw *
1026 check_ip6fw_struct(struct ip6_fw *frwl)
1027 {
1028 /* Check for invalid flag bits */
1029 if ((frwl->fw_flg & ~IPV6_FW_F_MASK) != 0) {
1030 dprintf(("%s undefined flag bits set (flags=%x)\n",
1031 err_prefix, frwl->fw_flg));
1032 return (NULL);
1033 }
1034 /* Must apply to incoming or outgoing (or both) */
1035 if (!(frwl->fw_flg & (IPV6_FW_F_IN | IPV6_FW_F_OUT))) {
1036 dprintf(("%s neither in nor out\n", err_prefix));
1037 return (NULL);
1038 }
1039 /* Empty interface name is no good */
1040 if (((frwl->fw_flg & IPV6_FW_F_IIFNAME)
1041 && !*frwl->fw_in_if.fu_via_if.name)
1042 || ((frwl->fw_flg & IPV6_FW_F_OIFNAME)
1043 && !*frwl->fw_out_if.fu_via_if.name)) {
1044 dprintf(("%s empty interface name\n", err_prefix));
1045 return (NULL);
1046 }
1047 /* Sanity check interface matching */
1048 if ((frwl->fw_flg & IF6_FW_F_VIAHACK) == IF6_FW_F_VIAHACK) {
1049 ; /* allow "via" backwards compatibility */
1050 } else if ((frwl->fw_flg & IPV6_FW_F_IN)
1051 && (frwl->fw_flg & IPV6_FW_F_OIFACE)) {
1052 dprintf(("%s outgoing interface check on incoming\n",
1053 err_prefix));
1054 return (NULL);
1055 }
1056 /* Sanity check port ranges */
1057 if ((frwl->fw_flg & IPV6_FW_F_SRNG) && IPV6_FW_GETNSRCP(frwl) < 2) {
1058 dprintf(("%s src range set but n_src_p=%d\n",
1059 err_prefix, IPV6_FW_GETNSRCP(frwl)));
1060 return (NULL);
1061 }
1062 if ((frwl->fw_flg & IPV6_FW_F_DRNG) && IPV6_FW_GETNDSTP(frwl) < 2) {
1063 dprintf(("%s dst range set but n_dst_p=%d\n",
1064 err_prefix, IPV6_FW_GETNDSTP(frwl)));
1065 return (NULL);
1066 }
1067 if (IPV6_FW_GETNSRCP(frwl) + IPV6_FW_GETNDSTP(frwl) > IPV6_FW_MAX_PORTS) {
1068 dprintf(("%s too many ports (%d+%d)\n",
1069 err_prefix, IPV6_FW_GETNSRCP(frwl), IPV6_FW_GETNDSTP(frwl)));
1070 return (NULL);
1071 }
1072 /*
1073 * Protocols other than TCP/UDP don't use port range
1074 */
1075 if ((frwl->fw_prot != IPPROTO_TCP) &&
1076 (frwl->fw_prot != IPPROTO_UDP) &&
1077 (IPV6_FW_GETNSRCP(frwl) || IPV6_FW_GETNDSTP(frwl))) {
1078 dprintf(("%s port(s) specified for non TCP/UDP rule\n",
1079 err_prefix));
1080 return(NULL);
1081 }
1082
1083 /*
1084 * Rather than modify the entry to make such entries work,
1085 * we reject this rule and require user level utilities
1086 * to enforce whatever policy they deem appropriate.
1087 */
1088 if ((frwl->fw_src.s6_addr32[0] & (~frwl->fw_smsk.s6_addr32[0])) ||
1089 (frwl->fw_src.s6_addr32[1] & (~frwl->fw_smsk.s6_addr32[1])) ||
1090 (frwl->fw_src.s6_addr32[2] & (~frwl->fw_smsk.s6_addr32[2])) ||
1091 (frwl->fw_src.s6_addr32[3] & (~frwl->fw_smsk.s6_addr32[3])) ||
1092 (frwl->fw_dst.s6_addr32[0] & (~frwl->fw_dmsk.s6_addr32[0])) ||
1093 (frwl->fw_dst.s6_addr32[1] & (~frwl->fw_dmsk.s6_addr32[1])) ||
1094 (frwl->fw_dst.s6_addr32[2] & (~frwl->fw_dmsk.s6_addr32[2])) ||
1095 (frwl->fw_dst.s6_addr32[3] & (~frwl->fw_dmsk.s6_addr32[3]))) {
1096 dprintf(("%s rule never matches\n", err_prefix));
1097 return(NULL);
1098 }
1099
1100 if ((frwl->fw_flg & IPV6_FW_F_FRAG) &&
1101 (frwl->fw_prot == IPPROTO_UDP || frwl->fw_prot == IPPROTO_TCP)) {
1102 if (frwl->fw_nports) {
1103 dprintf(("%s cannot mix 'frag' and ports\n", err_prefix));
1104 return(NULL);
1105 }
1106 if (frwl->fw_prot == IPPROTO_TCP &&
1107 frwl->fw_tcpf != frwl->fw_tcpnf) {
1108 dprintf(("%s cannot mix 'frag' with TCP flags\n", err_prefix));
1109 return(NULL);
1110 }
1111 }
1112
1113 /* Check command specific stuff */
1114 switch (frwl->fw_flg & IPV6_FW_F_COMMAND)
1115 {
1116 case IPV6_FW_F_REJECT:
1117 if (frwl->fw_reject_code >= 0x100
1118 && !(frwl->fw_prot == IPPROTO_TCP
1119 && frwl->fw_reject_code == IPV6_FW_REJECT_RST)) {
1120 dprintf(("%s unknown reject code\n", err_prefix));
1121 return(NULL);
1122 }
1123 break;
1124 case IPV6_FW_F_DIVERT: /* Diverting to port zero is invalid */
1125 case IPV6_FW_F_TEE:
1126 if (frwl->fw_divert_port == 0) {
1127 dprintf(("%s can't divert to port 0\n", err_prefix));
1128 return (NULL);
1129 }
1130 break;
1131 case IPV6_FW_F_DENY:
1132 case IPV6_FW_F_ACCEPT:
1133 case IPV6_FW_F_COUNT:
1134 case IPV6_FW_F_SKIPTO:
1135 break;
1136 default:
1137 dprintf(("%s invalid command\n", err_prefix));
1138 return(NULL);
1139 }
1140
1141 return frwl;
1142 }
1143
1144 static void
1145 ip6fw_kev_post_msg(u_int32_t event_code)
1146 {
1147 struct kev_msg ev_msg;
1148
1149 bzero(&ev_msg, sizeof(struct kev_msg));
1150
1151 ev_msg.vendor_code = KEV_VENDOR_APPLE;
1152 ev_msg.kev_class = KEV_FIREWALL_CLASS;
1153 ev_msg.kev_subclass = KEV_IP6FW_SUBCLASS;
1154 ev_msg.event_code = event_code;
1155
1156 kev_post_msg(&ev_msg);
1157
1158 }
1159
1160
1161 static void
1162 cp_to_user_64( struct ip6_fw_64 *userrule_64, struct ip6_fw *rule)
1163 {
1164 userrule_64->version = rule->version;
1165 userrule_64->context = CAST_USER_ADDR_T(rule->context);
1166 userrule_64->fw_pcnt = rule->fw_pcnt;
1167 userrule_64->fw_bcnt = rule->fw_bcnt;
1168 userrule_64->fw_src = rule->fw_src;
1169 userrule_64->fw_dst = rule->fw_dst;
1170 userrule_64->fw_smsk = rule->fw_smsk;
1171 userrule_64->fw_dmsk = rule->fw_dmsk;
1172 userrule_64->fw_number = rule->fw_number;
1173 userrule_64->fw_flg = rule->fw_flg;
1174 userrule_64->fw_ipflg = rule->fw_ipflg;
1175 bcopy( rule->fw_pts, userrule_64->fw_pts, IPV6_FW_MAX_PORTS);
1176 userrule_64->fw_ip6opt= rule->fw_ip6opt;
1177 userrule_64->fw_ip6nopt = rule->fw_ip6nopt;
1178 userrule_64->fw_tcpf = rule->fw_tcpf;
1179 userrule_64->fw_tcpnf = rule->fw_tcpnf;
1180 bcopy( rule->fw_icmp6types, userrule_64->fw_icmp6types, sizeof(userrule_64->fw_icmp6types));
1181 userrule_64->fw_in_if = rule->fw_in_if;
1182 userrule_64->fw_out_if = rule->fw_out_if;
1183 userrule_64->timestamp = rule->timestamp;
1184 userrule_64->fw_un.fu_divert_port = rule->fw_un.fu_divert_port;
1185 userrule_64->fw_prot = rule->fw_prot;
1186 userrule_64->fw_nports = rule->fw_nports;
1187 }
1188
1189
1190 static void
1191 cp_from_user_64( struct ip6_fw_64 *userrule_64, struct ip6_fw *rule)
1192 {
1193 rule->version = userrule_64->version;
1194 rule->context = CAST_DOWN(void *, userrule_64->context);
1195 rule->fw_pcnt = userrule_64->fw_pcnt;
1196 rule->fw_bcnt = userrule_64->fw_bcnt;
1197 rule->fw_src = userrule_64->fw_src;
1198 rule->fw_dst = userrule_64->fw_dst;
1199 rule->fw_smsk = userrule_64->fw_smsk;
1200 rule->fw_dmsk = userrule_64->fw_dmsk;
1201 rule->fw_number = userrule_64->fw_number;
1202 rule->fw_flg = userrule_64->fw_flg;
1203 rule->fw_ipflg = userrule_64->fw_ipflg;
1204 bcopy( userrule_64->fw_pts, rule->fw_pts, IPV6_FW_MAX_PORTS);
1205 rule->fw_ip6opt = userrule_64->fw_ip6opt;
1206 rule->fw_ip6nopt = userrule_64->fw_ip6nopt;
1207 rule->fw_tcpf = userrule_64->fw_tcpf;
1208 rule->fw_tcpnf = userrule_64->fw_tcpnf;
1209 bcopy( userrule_64->fw_icmp6types, rule->fw_icmp6types, sizeof(userrule_64->fw_icmp6types));
1210 rule->fw_in_if = userrule_64->fw_in_if;
1211 rule->fw_out_if = userrule_64->fw_out_if;
1212 rule->timestamp = CAST_DOWN( long, userrule_64->timestamp);
1213 rule->fw_un.fu_divert_port = userrule_64->fw_un.fu_divert_port;
1214 rule->fw_prot = userrule_64->fw_prot;
1215 rule->fw_nports = userrule_64->fw_nports;
1216 }
1217
1218
1219 static void
1220 cp_to_user_32( struct ip6_fw_32 *userrule_32, struct ip6_fw *rule)
1221 {
1222 userrule_32->version = rule->version;
1223 userrule_32->context = CAST_DOWN_EXPLICIT( user32_addr_t, rule->context);
1224 userrule_32->fw_pcnt = rule->fw_pcnt;
1225 userrule_32->fw_bcnt = rule->fw_bcnt;
1226 userrule_32->fw_src = rule->fw_src;
1227 userrule_32->fw_dst = rule->fw_dst;
1228 userrule_32->fw_smsk = rule->fw_smsk;
1229 userrule_32->fw_dmsk = rule->fw_dmsk;
1230 userrule_32->fw_number = rule->fw_number;
1231 userrule_32->fw_flg = rule->fw_flg;
1232 userrule_32->fw_ipflg = rule->fw_ipflg;
1233 bcopy( rule->fw_pts, userrule_32->fw_pts, IPV6_FW_MAX_PORTS);
1234 userrule_32->fw_ip6opt = rule->fw_ip6opt ;
1235 userrule_32->fw_ip6nopt = rule->fw_ip6nopt;
1236 userrule_32->fw_tcpf = rule->fw_tcpf;
1237 userrule_32->fw_tcpnf = rule->fw_tcpnf;
1238 bcopy( rule->fw_icmp6types, userrule_32->fw_icmp6types, sizeof(rule->fw_icmp6types));
1239 userrule_32->fw_in_if = rule->fw_in_if;
1240 userrule_32->fw_out_if = rule->fw_out_if;
1241 userrule_32->timestamp = rule->timestamp;
1242 userrule_32->fw_un.fu_divert_port = rule->fw_un.fu_divert_port;
1243 userrule_32->fw_prot = rule->fw_prot;
1244 userrule_32->fw_nports = rule->fw_nports;
1245 }
1246
1247
1248 static void
1249 cp_from_user_32( struct ip6_fw_32 *userrule_32, struct ip6_fw *rule)
1250 {
1251 rule->version = userrule_32->version;
1252 rule->context = CAST_DOWN(void *, userrule_32->context);
1253 rule->fw_pcnt = userrule_32->fw_pcnt;
1254 rule->fw_bcnt = userrule_32->fw_bcnt;
1255 rule->fw_src = userrule_32->fw_src;
1256 rule->fw_dst = userrule_32->fw_dst;
1257 rule->fw_smsk = userrule_32->fw_smsk;
1258 rule->fw_dmsk = userrule_32->fw_dmsk;
1259 rule->fw_number = userrule_32->fw_number;
1260 rule->fw_flg = userrule_32->fw_flg;
1261 rule->fw_ipflg = userrule_32->fw_ipflg;
1262 bcopy( userrule_32->fw_pts, rule->fw_pts, IPV6_FW_MAX_PORTS);
1263 rule->fw_ip6opt = userrule_32->fw_ip6opt;
1264 rule->fw_ip6nopt = userrule_32->fw_ip6nopt;
1265 rule->fw_tcpf = userrule_32->fw_tcpf;
1266 rule->fw_tcpnf = userrule_32->fw_tcpnf;
1267 bcopy( userrule_32->fw_icmp6types, rule->fw_icmp6types, sizeof(userrule_32->fw_icmp6types));
1268 rule->fw_in_if = userrule_32->fw_in_if;
1269 rule->fw_out_if = userrule_32->fw_out_if;
1270 rule->timestamp = CAST_DOWN(long, userrule_32->timestamp);
1271 rule->fw_un.fu_divert_port = userrule_32->fw_un.fu_divert_port;
1272 rule->fw_prot = userrule_32->fw_prot;
1273 rule->fw_nports = userrule_32->fw_nports;
1274 }
1275
1276 static int
1277 ip6_fw_ctl(struct sockopt *sopt)
1278 {
1279 int error = 0;
1280 int spl;
1281 int valsize;
1282 struct ip6_fw rule;
1283 int is64user=0;
1284 size_t userrulesize;
1285
1286 if (securelevel >= 3 &&
1287 (sopt->sopt_dir != SOPT_GET || sopt->sopt_name != IPV6_FW_GET))
1288 return (EPERM);
1289
1290 if ( proc_is64bit(sopt->sopt_p) ){
1291 is64user = 1;
1292 userrulesize = sizeof( struct ip6_fw_64 );
1293 } else
1294 userrulesize = sizeof( struct ip6_fw_32 );
1295
1296 /* We ALWAYS expect the client to pass in a rule structure so that we can
1297 * check the version of the API that they are using. In the case of a
1298 * IPV6_FW_GET operation, the first rule of the output buffer passed to us
1299 * must have the version set. */
1300 if (!sopt->sopt_val || sopt->sopt_valsize < userrulesize) return EINVAL;
1301
1302 /* save sopt->sopt_valsize */
1303 valsize = sopt->sopt_valsize;
1304
1305 if (is64user){
1306 struct ip6_fw_64 userrule_64;
1307
1308 if ((error = sooptcopyin(sopt, &userrule_64, userrulesize, userrulesize)))
1309 return error;
1310
1311 cp_from_user_64( &userrule_64, &rule );
1312 }
1313 else {
1314 struct ip6_fw_32 userrule_32;
1315
1316 if ((error = sooptcopyin(sopt, &userrule_32, userrulesize, userrulesize)))
1317 return error;
1318
1319 cp_from_user_32( &userrule_32, &rule );
1320 }
1321
1322 if (rule.version != IPV6_FW_CURRENT_API_VERSION) return EINVAL;
1323 rule.version = 0xFFFFFFFF; /* version is meaningless once rules "make it in the door". */
1324
1325 switch (sopt->sopt_name)
1326 {
1327 case IPV6_FW_GET:
1328 {
1329 struct ip6_fw_chain *fcp;
1330 struct ip6_fw *buf;
1331 size_t size = 0;
1332 size_t rulesize = 0;
1333
1334 spl = splnet();
1335
1336 if ( is64user )
1337 rulesize = sizeof(struct ip6_fw_64 );
1338 else
1339 rulesize = sizeof(struct ip6_fw_32 );
1340
1341 LIST_FOREACH(fcp, &ip6_fw_chain, chain)
1342 size += rulesize;
1343
1344 buf = _MALLOC(size, M_TEMP, M_WAITOK);
1345 if (!buf) error = ENOBUFS;
1346 else
1347 {
1348 //struct ip6_fw *bp = buf;
1349 caddr_t bp = (caddr_t)buf;
1350
1351 LIST_FOREACH(fcp, &ip6_fw_chain, chain)
1352 {
1353 //bcopy(fcp->rule, bp, sizeof *bp);
1354 if ( is64user ){
1355 cp_to_user_64( (struct ip6_fw_64*)bp, fcp->rule);
1356 }
1357 else {
1358 cp_to_user_32( (struct ip6_fw_32*)bp, fcp->rule);
1359 }
1360
1361 ( (struct ip6_fw*)bp)->version = IPV6_FW_CURRENT_API_VERSION;
1362 //bp++;
1363 bp += rulesize;
1364 }
1365 }
1366
1367 splx(spl);
1368 if (buf)
1369 {
1370 sopt->sopt_valsize = valsize;
1371 error = sooptcopyout(sopt, buf, size);
1372 FREE(buf, M_TEMP);
1373 }
1374
1375 break;
1376 }
1377
1378 case IPV6_FW_FLUSH:
1379 spl = splnet();
1380 while (ip6_fw_chain.lh_first &&
1381 ip6_fw_chain.lh_first->rule->fw_number != (u_short)-1)
1382 {
1383 struct ip6_fw_chain *fcp = ip6_fw_chain.lh_first;
1384 LIST_REMOVE(ip6_fw_chain.lh_first, chain);
1385 FREE(fcp->rule, M_IP6FW);
1386 FREE(fcp, M_IP6FW);
1387 }
1388 splx(spl);
1389 ip6fw_kev_post_msg(KEV_IP6FW_FLUSH);
1390 break;
1391
1392 case IPV6_FW_ZERO:
1393 error = zero_entry6(&rule);
1394 break;
1395
1396 case IPV6_FW_ADD:
1397 if (check_ip6fw_struct(&rule)) {
1398 error = add_entry6(&ip6_fw_chain, &rule);
1399
1400 ip6fw_kev_post_msg(KEV_IP6FW_ADD);
1401 } else
1402 error = EINVAL;
1403 break;
1404
1405 case IPV6_FW_DEL:
1406 if (rule.fw_number == (u_short)-1)
1407 {
1408 dprintf(("%s can't delete rule 65535\n", err_prefix));
1409 error = EINVAL;
1410 }
1411 else {
1412 error = del_entry6(&ip6_fw_chain, rule.fw_number);
1413
1414 ip6fw_kev_post_msg(KEV_IP6FW_DEL);
1415 }
1416 break;
1417
1418 default:
1419 dprintf(("%s invalid option %d\n", err_prefix, sopt->sopt_name));
1420 error = EINVAL;
1421 }
1422
1423 return error;
1424 }
1425
1426 void
1427 ip6_fw_init(void)
1428 {
1429 struct ip6_fw default_rule;
1430
1431 ip6_fw_chk_ptr = ip6_fw_chk;
1432 ip6_fw_ctl_ptr = ip6_fw_ctl;
1433 LIST_INIT(&ip6_fw_chain);
1434
1435 bzero(&default_rule, sizeof default_rule);
1436 default_rule.fw_prot = IPPROTO_IPV6;
1437 default_rule.fw_number = (u_short)-1;
1438 #ifdef IPV6FIREWALL_DEFAULT_TO_ACCEPT
1439 default_rule.fw_flg |= IPV6_FW_F_ACCEPT;
1440 #else
1441 default_rule.fw_flg |= IPV6_FW_F_DENY;
1442 #endif
1443 default_rule.fw_flg |= IPV6_FW_F_IN | IPV6_FW_F_OUT;
1444 if (check_ip6fw_struct(&default_rule) == NULL ||
1445 add_entry6(&ip6_fw_chain, &default_rule))
1446 panic("%s", __FUNCTION__);
1447
1448 printf("IPv6 packet filtering initialized, ");
1449 #ifdef IPV6FIREWALL_DEFAULT_TO_ACCEPT
1450 printf("default to accept, ");
1451 #endif
1452 #ifndef IPV6FIREWALL_VERBOSE
1453 printf("logging disabled\n");
1454 #else
1455 if (fw6_verbose_limit == 0)
1456 printf("unlimited logging\n");
1457 else
1458 printf("logging limited to %d packets/entry\n",
1459 fw6_verbose_limit);
1460 #endif
1461 }
1462