FreeBSD/Linux Kernel Cross Reference
sys/netinet6/ip6_fw.c
1 /* $FreeBSD$ */
2 /* $KAME: ip6_fw.c,v 1.21 2001/01/24 01:25:32 itojun Exp $ */
3
4 /*
5 * Copyright (C) 1998, 1999, 2000 and 2001 WIDE Project.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33 /*
34 * Copyright (c) 1993 Daniel Boulet
35 * Copyright (c) 1994 Ugen J.S.Antsilevich
36 * Copyright (c) 1996 Alex Nash
37 *
38 * Redistribution and use in source forms, with and without modification,
39 * are permitted provided that this entire comment appears intact.
40 *
41 * Redistribution in binary form may occur without any restrictions.
42 * Obviously, it would be nice if you gave credit where credit is due
43 * but requiring it would be too onerous.
44 *
45 * This software is provided ``AS IS'' without any warranties of any kind.
46 */
47
48 /*
49 * Implement IPv6 packet firewall
50 */
51
52 #if !defined(KLD_MODULE)
53 #include "opt_ip6fw.h"
54 #include "opt_inet.h"
55 #include "opt_inet6.h"
56 #endif
57
58 #ifdef IP6DIVERT
59 #error "NOT SUPPORTED IPV6 DIVERT"
60 #endif
61 #ifdef IP6FW_DIVERT_RESTART
62 #error "NOT SUPPORTED IPV6 DIVERT"
63 #endif
64
65 #include <sys/param.h>
66 #include <sys/systm.h>
67 #include <sys/malloc.h>
68 #include <sys/mbuf.h>
69 #include <sys/queue.h>
70 #include <sys/kernel.h>
71 #include <sys/socket.h>
72 #include <sys/socketvar.h>
73 #include <sys/syslog.h>
74 #include <sys/time.h>
75 #include <net/if.h>
76 #include <net/route.h>
77 #include <netinet/in_systm.h>
78 #include <netinet/in.h>
79 #include <netinet/ip.h>
80
81 #include <netinet/ip6.h>
82 #include <netinet6/ip6_var.h>
83 #include <netinet6/in6_var.h>
84 #include <netinet/icmp6.h>
85
86 #include <netinet/in_pcb.h>
87
88 #include <netinet6/ip6_fw.h>
89 #include <netinet/ip_var.h>
90 #include <netinet/tcp.h>
91 #include <netinet/tcp_seq.h>
92 #include <netinet/tcp_timer.h>
93 #include <netinet/tcp_var.h>
94 #include <netinet/udp.h>
95
96 #include <sys/sysctl.h>
97
98 #include <net/net_osdep.h>
99
100 MALLOC_DEFINE(M_IP6FW, "Ip6Fw/Ip6Acct", "Ip6Fw/Ip6Acct chain's");
101
102 static int fw6_debug = 1;
103 #ifdef IPV6FIREWALL_VERBOSE
104 static int fw6_verbose = 1;
105 #else
106 static int fw6_verbose = 0;
107 #endif
108 #ifdef IPV6FIREWALL_VERBOSE_LIMIT
109 static int fw6_verbose_limit = IPV6FIREWALL_VERBOSE_LIMIT;
110 #else
111 static int fw6_verbose_limit = 0;
112 #endif
113
114 LIST_HEAD (ip6_fw_head, ip6_fw_chain) ip6_fw_chain;
115
116 #ifdef SYSCTL_NODE
117 SYSCTL_DECL(_net_inet6_ip6);
118 SYSCTL_NODE(_net_inet6_ip6, OID_AUTO, fw, CTLFLAG_RW|CTLFLAG_SECURE, 0, "Firewall");
119 SYSCTL_INT(_net_inet6_ip6_fw, OID_AUTO, enable, CTLFLAG_RW|CTLFLAG_SECURE,
120 &ip6_fw_enable, 0, "Enable ip6fw");
121 SYSCTL_INT(_net_inet6_ip6_fw, OID_AUTO, debug, CTLFLAG_RW, &fw6_debug, 0, "");
122 SYSCTL_INT(_net_inet6_ip6_fw, OID_AUTO, verbose, CTLFLAG_RW|CTLFLAG_SECURE, &fw6_verbose, 0, "");
123 SYSCTL_INT(_net_inet6_ip6_fw, OID_AUTO, verbose_limit, CTLFLAG_RW, &fw6_verbose_limit, 0, "");
124 #endif
125
126 #define dprintf(a) do { \
127 if (fw6_debug) \
128 printf a; \
129 } while (0)
130 #define SNPARGS(buf, len) buf + len, sizeof(buf) > len ? sizeof(buf) - len : 0
131
132 static int add_entry6 __P((struct ip6_fw_head *chainptr, struct ip6_fw *frwl));
133 static int del_entry6 __P((struct ip6_fw_head *chainptr, u_short number));
134 static int zero_entry6 __P((struct mbuf *m));
135 static struct ip6_fw *check_ip6fw_struct __P((struct ip6_fw *m));
136 static struct ip6_fw *check_ip6fw_mbuf __P((struct mbuf *fw));
137 static int ip6opts_match __P((struct ip6_hdr **ip6, struct ip6_fw *f,
138 struct mbuf **m,
139 int *off, int *nxt, u_short *offset));
140 static int port_match6 __P((u_short *portptr, int nports, u_short port,
141 int range_flag));
142 static int tcp6flg_match __P((struct tcphdr *tcp6, struct ip6_fw *f));
143 static int icmp6type_match __P((struct icmp6_hdr * icmp, struct ip6_fw * f));
144 static void ip6fw_report __P((struct ip6_fw *f, struct ip6_hdr *ip6,
145 struct ifnet *rif, struct ifnet *oif, int off, int nxt));
146
147 static int ip6_fw_chk __P((struct ip6_hdr **pip6,
148 struct ifnet *oif, u_int16_t *cookie, struct mbuf **m));
149 static int ip6_fw_ctl __P((int stage, struct mbuf **mm));
150
151 static char err_prefix[] = "ip6_fw_ctl:";
152
153 /*
154 * Returns 1 if the port is matched by the vector, 0 otherwise
155 */
156 static
157 __inline int
158 port_match6(u_short *portptr, int nports, u_short port, int range_flag)
159 {
160 if (!nports)
161 return 1;
162 if (range_flag) {
163 if (portptr[0] <= port && port <= portptr[1]) {
164 return 1;
165 }
166 nports -= 2;
167 portptr += 2;
168 }
169 while (nports-- > 0) {
170 if (*portptr++ == port) {
171 return 1;
172 }
173 }
174 return 0;
175 }
176
177 static int
178 tcp6flg_match(struct tcphdr *tcp6, struct ip6_fw *f)
179 {
180 u_char flg_set, flg_clr;
181
182 /*
183 * If an established connection is required, reject packets that
184 * have only SYN of RST|ACK|SYN set. Otherwise, fall through to
185 * other flag requirements.
186 */
187 if ((f->fw_ipflg & IPV6_FW_IF_TCPEST) &&
188 ((tcp6->th_flags & (IPV6_FW_TCPF_RST | IPV6_FW_TCPF_ACK |
189 IPV6_FW_TCPF_SYN)) == IPV6_FW_TCPF_SYN))
190 return 0;
191
192 flg_set = tcp6->th_flags & f->fw_tcpf;
193 flg_clr = tcp6->th_flags & f->fw_tcpnf;
194
195 if (flg_set != f->fw_tcpf)
196 return 0;
197 if (flg_clr)
198 return 0;
199
200 return 1;
201 }
202
203 static int
204 icmp6type_match(struct icmp6_hdr *icmp6, struct ip6_fw *f)
205 {
206 int type;
207
208 if (!(f->fw_flg & IPV6_FW_F_ICMPBIT))
209 return(1);
210
211 type = icmp6->icmp6_type;
212
213 /* check for matching type in the bitmap */
214 if (type < IPV6_FW_ICMPTYPES_DIM * sizeof(unsigned) * 8 &&
215 (f->fw_icmp6types[type / (sizeof(unsigned) * 8)] &
216 (1U << (type % (8 * sizeof(unsigned))))))
217 return(1);
218
219 return(0); /* no match */
220 }
221
222 static int
223 is_icmp6_query(struct ip6_hdr *ip6, int off)
224 {
225 const struct icmp6_hdr *icmp6;
226 int icmp6_type;
227
228 icmp6 = (struct icmp6_hdr *)((caddr_t)ip6 + off);
229 icmp6_type = icmp6->icmp6_type;
230
231 if (icmp6_type == ICMP6_ECHO_REQUEST ||
232 icmp6_type == ICMP6_MEMBERSHIP_QUERY ||
233 icmp6_type == ICMP6_WRUREQUEST ||
234 icmp6_type == ICMP6_FQDN_QUERY ||
235 icmp6_type == ICMP6_NI_QUERY)
236 return(1);
237
238 return(0);
239 }
240
241 static int
242 ip6opts_match(struct ip6_hdr **pip6, struct ip6_fw *f, struct mbuf **m,
243 int *off, int *nxt, u_short *offset)
244 {
245 int len;
246 struct ip6_hdr *ip6 = *pip6;
247 struct ip6_ext *ip6e;
248 u_char opts, nopts, nopts_sve;
249
250 opts = f->fw_ip6opt;
251 nopts = nopts_sve = f->fw_ip6nopt;
252
253 *nxt = ip6->ip6_nxt;
254 *off = sizeof(struct ip6_hdr);
255 len = ntohs(ip6->ip6_plen) + sizeof(struct ip6_hdr);
256 while (*off < len) {
257 ip6e = (struct ip6_ext *)((caddr_t) ip6 + *off);
258 if ((*m)->m_len < *off + sizeof(*ip6e))
259 goto opts_check; /* XXX */
260
261 switch(*nxt) {
262 case IPPROTO_FRAGMENT:
263 if ((*m)->m_len >= *off + sizeof(struct ip6_frag)) {
264 struct ip6_frag *ip6f;
265
266 ip6f = (struct ip6_frag *) ((caddr_t)ip6 + *off);
267 *offset = ip6f->ip6f_offlg & IP6F_OFF_MASK;
268 }
269 opts &= ~IPV6_FW_IP6OPT_FRAG;
270 nopts &= ~IPV6_FW_IP6OPT_FRAG;
271 *off += sizeof(struct ip6_frag);
272 break;
273 case IPPROTO_AH:
274 opts &= ~IPV6_FW_IP6OPT_AH;
275 nopts &= ~IPV6_FW_IP6OPT_AH;
276 *off += (ip6e->ip6e_len + 2) << 2;
277 break;
278 default:
279 switch (*nxt) {
280 case IPPROTO_HOPOPTS:
281 opts &= ~IPV6_FW_IP6OPT_HOPOPT;
282 nopts &= ~IPV6_FW_IP6OPT_HOPOPT;
283 break;
284 case IPPROTO_ROUTING:
285 opts &= ~IPV6_FW_IP6OPT_ROUTE;
286 nopts &= ~IPV6_FW_IP6OPT_ROUTE;
287 break;
288 case IPPROTO_ESP:
289 opts &= ~IPV6_FW_IP6OPT_ESP;
290 nopts &= ~IPV6_FW_IP6OPT_ESP;
291 goto opts_check;
292 case IPPROTO_NONE:
293 opts &= ~IPV6_FW_IP6OPT_NONXT;
294 nopts &= ~IPV6_FW_IP6OPT_NONXT;
295 goto opts_check;
296 case IPPROTO_DSTOPTS:
297 opts &= ~IPV6_FW_IP6OPT_OPTS;
298 nopts &= ~IPV6_FW_IP6OPT_OPTS;
299 break;
300 default:
301 goto opts_check;
302 }
303 *off += (ip6e->ip6e_len + 1) << 3;
304 break;
305 }
306 *nxt = ip6e->ip6e_nxt;
307
308 }
309 opts_check:
310 if (f->fw_ip6opt == f->fw_ip6nopt) /* XXX */
311 return 1;
312
313 if (opts == 0 && nopts == nopts_sve)
314 return 1;
315 else
316 return 0;
317 }
318
319 static
320 __inline int
321 iface_match(struct ifnet *ifp, union ip6_fw_if *ifu, int byname)
322 {
323 /* Check by name or by IP address */
324 if (byname) {
325 /* Check unit number (-1 is wildcard) */
326 if (ifu->fu_via_if.unit != -1
327 && ifp->if_unit != ifu->fu_via_if.unit)
328 return(0);
329 /* Check name */
330 if (strncmp(ifp->if_name, ifu->fu_via_if.name, IP6FW_IFNLEN))
331 return(0);
332 return(1);
333 } else if (!IN6_IS_ADDR_UNSPECIFIED(&ifu->fu_via_ip6)) { /* Zero == wildcard */
334 struct ifaddr *ia;
335
336 for (ia = ifp->if_addrlist.tqh_first; ia; ia = ia->ifa_list.tqe_next)
337 {
338
339 if (ia->ifa_addr == NULL)
340 continue;
341 if (ia->ifa_addr->sa_family != AF_INET6)
342 continue;
343 if (!IN6_ARE_ADDR_EQUAL(&ifu->fu_via_ip6,
344 &(((struct sockaddr_in6 *)
345 (ia->ifa_addr))->sin6_addr)))
346 continue;
347 return(1);
348 }
349 return(0);
350 }
351 return(1);
352 }
353
354 static void
355 ip6fw_report(struct ip6_fw *f, struct ip6_hdr *ip6,
356 struct ifnet *rif, struct ifnet *oif, int off, int nxt)
357 {
358 static int counter;
359 struct tcphdr *const tcp6 = (struct tcphdr *) ((caddr_t) ip6+ off);
360 struct udphdr *const udp = (struct udphdr *) ((caddr_t) ip6+ off);
361 struct icmp6_hdr *const icmp6 = (struct icmp6_hdr *) ((caddr_t) ip6+ off);
362 int count;
363 char *action;
364 char action2[32], proto[102], name[18];
365 int len;
366
367 count = f ? f->fw_pcnt : ++counter;
368 if (fw6_verbose_limit != 0 && count > fw6_verbose_limit)
369 return;
370
371 /* Print command name */
372 snprintf(SNPARGS(name, 0), "ip6fw: %d", f ? f->fw_number : -1);
373
374 action = action2;
375 if (!f)
376 action = "Refuse";
377 else {
378 switch (f->fw_flg & IPV6_FW_F_COMMAND) {
379 case IPV6_FW_F_DENY:
380 action = "Deny";
381 break;
382 case IPV6_FW_F_REJECT:
383 if (f->fw_reject_code == IPV6_FW_REJECT_RST)
384 action = "Reset";
385 else
386 action = "Unreach";
387 break;
388 case IPV6_FW_F_ACCEPT:
389 action = "Accept";
390 break;
391 case IPV6_FW_F_COUNT:
392 action = "Count";
393 break;
394 case IPV6_FW_F_DIVERT:
395 snprintf(SNPARGS(action2, 0), "Divert %d",
396 f->fw_divert_port);
397 break;
398 case IPV6_FW_F_TEE:
399 snprintf(SNPARGS(action2, 0), "Tee %d",
400 f->fw_divert_port);
401 break;
402 case IPV6_FW_F_SKIPTO:
403 snprintf(SNPARGS(action2, 0), "SkipTo %d",
404 f->fw_skipto_rule);
405 break;
406 default:
407 action = "UNKNOWN";
408 break;
409 }
410 }
411
412 switch (nxt) {
413 case IPPROTO_TCP:
414 len = snprintf(SNPARGS(proto, 0), "TCP [%s]",
415 ip6_sprintf(&ip6->ip6_src));
416 if (off > 0)
417 len += snprintf(SNPARGS(proto, len), ":%d ",
418 ntohs(tcp6->th_sport));
419 else
420 len += snprintf(SNPARGS(proto, len), " ");
421 len += snprintf(SNPARGS(proto, len), "[%s]",
422 ip6_sprintf(&ip6->ip6_dst));
423 if (off > 0)
424 snprintf(SNPARGS(proto, len), ":%d",
425 ntohs(tcp6->th_dport));
426 break;
427 case IPPROTO_UDP:
428 len = snprintf(SNPARGS(proto, 0), "UDP [%s]",
429 ip6_sprintf(&ip6->ip6_src));
430 if (off > 0)
431 len += snprintf(SNPARGS(proto, len), ":%d ",
432 ntohs(udp->uh_sport));
433 else
434 len += snprintf(SNPARGS(proto, len), " ");
435 len += snprintf(SNPARGS(proto, len), "[%s]",
436 ip6_sprintf(&ip6->ip6_dst));
437 if (off > 0)
438 snprintf(SNPARGS(proto, len), ":%d",
439 ntohs(udp->uh_dport));
440 break;
441 case IPPROTO_ICMPV6:
442 if (off > 0)
443 len = snprintf(SNPARGS(proto, 0), "IPV6-ICMP:%u.%u ",
444 icmp6->icmp6_type, icmp6->icmp6_code);
445 else
446 len = snprintf(SNPARGS(proto, 0), "IPV6-ICMP ");
447 len += snprintf(SNPARGS(proto, len), "[%s]",
448 ip6_sprintf(&ip6->ip6_src));
449 snprintf(SNPARGS(proto, len), " [%s]",
450 ip6_sprintf(&ip6->ip6_dst));
451 break;
452 default:
453 len = snprintf(SNPARGS(proto, 0), "P:%d [%s]", nxt,
454 ip6_sprintf(&ip6->ip6_src));
455 snprintf(SNPARGS(proto, len), " [%s]",
456 ip6_sprintf(&ip6->ip6_dst));
457 break;
458 }
459
460 if (oif)
461 log(LOG_SECURITY | LOG_INFO, "%s %s %s out via %s\n",
462 name, action, proto, if_name(oif));
463 else if (rif)
464 log(LOG_SECURITY | LOG_INFO, "%s %s %s in via %s\n",
465 name, action, proto, if_name(rif));
466 else
467 log(LOG_SECURITY | LOG_INFO, "%s %s %s",
468 name, action, proto);
469 if (fw6_verbose_limit != 0 && count == fw6_verbose_limit)
470 log(LOG_SECURITY | LOG_INFO, "ip6fw: limit reached on entry %d\n",
471 f ? f->fw_number : -1);
472 }
473
474 /*
475 * Parameters:
476 *
477 * ip Pointer to packet header (struct ip6_hdr *)
478 * hlen Packet header length
479 * oif Outgoing interface, or NULL if packet is incoming
480 * #ifndef IP6FW_DIVERT_RESTART
481 * *cookie Ignore all divert/tee rules to this port (if non-zero)
482 * #else
483 * *cookie Skip up to the first rule past this rule number;
484 * #endif
485 * *m The packet; we set to NULL when/if we nuke it.
486 *
487 * Return value:
488 *
489 * 0 The packet is to be accepted and routed normally OR
490 * the packet was denied/rejected and has been dropped;
491 * in the latter case, *m is equal to NULL upon return.
492 * port Divert the packet to port.
493 */
494
495 static int
496 ip6_fw_chk(struct ip6_hdr **pip6,
497 struct ifnet *oif, u_int16_t *cookie, struct mbuf **m)
498 {
499 struct ip6_fw_chain *chain;
500 struct ip6_fw *rule = NULL;
501 struct ip6_hdr *ip6 = *pip6;
502 struct ifnet *const rif = (*m)->m_pkthdr.rcvif;
503 u_short offset = 0;
504 int off = sizeof(struct ip6_hdr), nxt = ip6->ip6_nxt;
505 u_short src_port, dst_port;
506 #ifdef IP6FW_DIVERT_RESTART
507 u_int16_t skipto = *cookie;
508 #else
509 u_int16_t ignport = ntohs(*cookie);
510 #endif
511
512 *cookie = 0;
513 /*
514 * Go down the chain, looking for enlightment
515 * #ifdef IP6FW_DIVERT_RESTART
516 * If we've been asked to start at a given rule immediatly, do so.
517 * #endif
518 */
519 chain = LIST_FIRST(&ip6_fw_chain);
520 #ifdef IP6FW_DIVERT_RESTART
521 if (skipto) {
522 if (skipto >= 65535)
523 goto dropit;
524 while (chain && (chain->rule->fw_number <= skipto)) {
525 chain = LIST_NEXT(chain, chain);
526 }
527 if (! chain) goto dropit;
528 }
529 #endif /* IP6FW_DIVERT_RESTART */
530 for (; chain; chain = LIST_NEXT(chain, chain)) {
531 struct ip6_fw *const f = chain->rule;
532
533 if (oif) {
534 /* Check direction outbound */
535 if (!(f->fw_flg & IPV6_FW_F_OUT))
536 continue;
537 } else {
538 /* Check direction inbound */
539 if (!(f->fw_flg & IPV6_FW_F_IN))
540 continue;
541 }
542
543 #define IN6_ARE_ADDR_MASKEQUAL(x,y,z) (\
544 (((x)->s6_addr32[0] & (y)->s6_addr32[0]) == (z)->s6_addr32[0]) && \
545 (((x)->s6_addr32[1] & (y)->s6_addr32[1]) == (z)->s6_addr32[1]) && \
546 (((x)->s6_addr32[2] & (y)->s6_addr32[2]) == (z)->s6_addr32[2]) && \
547 (((x)->s6_addr32[3] & (y)->s6_addr32[3]) == (z)->s6_addr32[3]))
548
549 /* If src-addr doesn't match, not this rule. */
550 if (((f->fw_flg & IPV6_FW_F_INVSRC) != 0) ^
551 (!IN6_ARE_ADDR_MASKEQUAL(&ip6->ip6_src,&f->fw_smsk,&f->fw_src)))
552 continue;
553
554 /* If dest-addr doesn't match, not this rule. */
555 if (((f->fw_flg & IPV6_FW_F_INVDST) != 0) ^
556 (!IN6_ARE_ADDR_MASKEQUAL(&ip6->ip6_dst,&f->fw_dmsk,&f->fw_dst)))
557 continue;
558
559 #undef IN6_ARE_ADDR_MASKEQUAL
560 /* Interface check */
561 if ((f->fw_flg & IF6_FW_F_VIAHACK) == IF6_FW_F_VIAHACK) {
562 struct ifnet *const iface = oif ? oif : rif;
563
564 /* Backwards compatibility hack for "via" */
565 if (!iface || !iface_match(iface,
566 &f->fw_in_if, f->fw_flg & IPV6_FW_F_OIFNAME))
567 continue;
568 } else {
569 /* Check receive interface */
570 if ((f->fw_flg & IPV6_FW_F_IIFACE)
571 && (!rif || !iface_match(rif,
572 &f->fw_in_if, f->fw_flg & IPV6_FW_F_IIFNAME)))
573 continue;
574 /* Check outgoing interface */
575 if ((f->fw_flg & IPV6_FW_F_OIFACE)
576 && (!oif || !iface_match(oif,
577 &f->fw_out_if, f->fw_flg & IPV6_FW_F_OIFNAME)))
578 continue;
579 }
580
581 /* Check IP options */
582 if (!ip6opts_match(&ip6, f, m, &off, &nxt, &offset))
583 continue;
584
585 /* Fragments */
586 if ((f->fw_flg & IPV6_FW_F_FRAG) && !offset)
587 continue;
588
589 /* Check protocol; if wildcard, match */
590 if (f->fw_prot == IPPROTO_IPV6)
591 goto got_match;
592
593 /* If different, don't match */
594 if (nxt != f->fw_prot)
595 continue;
596
597 #define PULLUP_TO(len) do { \
598 if ((*m)->m_len < (len) \
599 && (*m = m_pullup(*m, (len))) == 0) { \
600 goto dropit; \
601 } \
602 *pip6 = ip6 = mtod(*m, struct ip6_hdr *); \
603 } while (0)
604
605 /* Protocol specific checks */
606 switch (nxt) {
607 case IPPROTO_TCP:
608 {
609 struct tcphdr *tcp6;
610
611 if (offset == 1) { /* cf. RFC 1858 */
612 PULLUP_TO(off + 4); /* XXX ? */
613 goto bogusfrag;
614 }
615 if (offset != 0) {
616 /*
617 * TCP flags and ports aren't available in this
618 * packet -- if this rule specified either one,
619 * we consider the rule a non-match.
620 */
621 if (f->fw_nports != 0 ||
622 f->fw_tcpf != f->fw_tcpnf)
623 continue;
624
625 break;
626 }
627 PULLUP_TO(off + 14);
628 tcp6 = (struct tcphdr *) ((caddr_t)ip6 + off);
629 if (((f->fw_tcpf != f->fw_tcpnf) ||
630 (f->fw_ipflg & IPV6_FW_IF_TCPEST)) &&
631 !tcp6flg_match(tcp6, f))
632 continue;
633 src_port = ntohs(tcp6->th_sport);
634 dst_port = ntohs(tcp6->th_dport);
635 goto check_ports;
636 }
637
638 case IPPROTO_UDP:
639 {
640 struct udphdr *udp;
641
642 if (offset != 0) {
643 /*
644 * Port specification is unavailable -- if this
645 * rule specifies a port, we consider the rule
646 * a non-match.
647 */
648 if (f->fw_nports != 0)
649 continue;
650
651 break;
652 }
653 PULLUP_TO(off + 4);
654 udp = (struct udphdr *) ((caddr_t)ip6 + off);
655 src_port = ntohs(udp->uh_sport);
656 dst_port = ntohs(udp->uh_dport);
657 check_ports:
658 if (!port_match6(&f->fw_pts[0],
659 IPV6_FW_GETNSRCP(f), src_port,
660 f->fw_flg & IPV6_FW_F_SRNG))
661 continue;
662 if (!port_match6(&f->fw_pts[IPV6_FW_GETNSRCP(f)],
663 IPV6_FW_GETNDSTP(f), dst_port,
664 f->fw_flg & IPV6_FW_F_DRNG))
665 continue;
666 break;
667 }
668
669 case IPPROTO_ICMPV6:
670 {
671 struct icmp6_hdr *icmp;
672
673 if (offset != 0) /* Type isn't valid */
674 break;
675 PULLUP_TO(off + 2);
676 icmp = (struct icmp6_hdr *) ((caddr_t)ip6 + off);
677 if (!icmp6type_match(icmp, f))
678 continue;
679 break;
680 }
681 #undef PULLUP_TO
682
683 bogusfrag:
684 if (fw6_verbose)
685 ip6fw_report(NULL, ip6, rif, oif, off, nxt);
686 goto dropit;
687 }
688
689 got_match:
690 #ifndef IP6FW_DIVERT_RESTART
691 /* Ignore divert/tee rule if socket port is "ignport" */
692 switch (f->fw_flg & IPV6_FW_F_COMMAND) {
693 case IPV6_FW_F_DIVERT:
694 case IPV6_FW_F_TEE:
695 if (f->fw_divert_port == ignport)
696 continue; /* ignore this rule */
697 break;
698 }
699
700 #endif /* IP6FW_DIVERT_RESTART */
701 /* Update statistics */
702 f->fw_pcnt += 1;
703 f->fw_bcnt += ntohs(ip6->ip6_plen);
704 f->timestamp = time_second;
705
706 /* Log to console if desired */
707 if ((f->fw_flg & IPV6_FW_F_PRN) && fw6_verbose)
708 ip6fw_report(f, ip6, rif, oif, off, nxt);
709
710 /* Take appropriate action */
711 switch (f->fw_flg & IPV6_FW_F_COMMAND) {
712 case IPV6_FW_F_ACCEPT:
713 return(0);
714 case IPV6_FW_F_COUNT:
715 continue;
716 case IPV6_FW_F_DIVERT:
717 #ifdef IP6FW_DIVERT_RESTART
718 *cookie = f->fw_number;
719 #else
720 *cookie = htons(f->fw_divert_port);
721 #endif /* IP6FW_DIVERT_RESTART */
722 return(f->fw_divert_port);
723 case IPV6_FW_F_TEE:
724 /*
725 * XXX someday tee packet here, but beware that you
726 * can't use m_copym() or m_copypacket() because
727 * the divert input routine modifies the mbuf
728 * (and these routines only increment reference
729 * counts in the case of mbuf clusters), so need
730 * to write custom routine.
731 */
732 continue;
733 case IPV6_FW_F_SKIPTO:
734 #ifdef DIAGNOSTIC
735 while (chain->chain.le_next
736 && chain->chain.le_next->rule->fw_number
737 < f->fw_skipto_rule)
738 #else
739 while (chain->chain.le_next->rule->fw_number
740 < f->fw_skipto_rule)
741 #endif
742 chain = chain->chain.le_next;
743 continue;
744 }
745
746 /* Deny/reject this packet using this rule */
747 rule = f;
748 break;
749 }
750
751 #ifdef DIAGNOSTIC
752 /* Rule 65535 should always be there and should always match */
753 if (!chain)
754 panic("ip6_fw: chain");
755 #endif
756
757 /*
758 * At this point, we're going to drop the packet.
759 * Send a reject notice if all of the following are true:
760 *
761 * - The packet matched a reject rule
762 * - The packet is not an ICMP packet, or is an ICMP query packet
763 * - The packet is not a multicast or broadcast packet
764 */
765 if ((rule->fw_flg & IPV6_FW_F_COMMAND) == IPV6_FW_F_REJECT
766 && (nxt != IPPROTO_ICMPV6 || is_icmp6_query(ip6, off))
767 && !((*m)->m_flags & (M_BCAST|M_MCAST))
768 && !IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
769 switch (rule->fw_reject_code) {
770 case IPV6_FW_REJECT_RST:
771 {
772 struct tcphdr *const tcp =
773 (struct tcphdr *) ((caddr_t)ip6 + off);
774 struct {
775 struct ip6_hdr ip6;
776 struct tcphdr th;
777 } ti;
778 tcp_seq ack, seq;
779 int flags;
780
781 if (offset != 0 || (tcp->th_flags & TH_RST))
782 break;
783
784 ti.ip6 = *ip6;
785 ti.th = *tcp;
786 NTOHL(ti.th.th_seq);
787 NTOHL(ti.th.th_ack);
788 ti.ip6.ip6_nxt = IPPROTO_TCP;
789 if (ti.th.th_flags & TH_ACK) {
790 ack = 0;
791 seq = ti.th.th_ack;
792 flags = TH_RST;
793 } else {
794 ack = ti.th.th_seq;
795 if (((*m)->m_flags & M_PKTHDR) != 0) {
796 ack += (*m)->m_pkthdr.len - off
797 - (ti.th.th_off << 2);
798 } else if (ip6->ip6_plen) {
799 ack += ntohs(ip6->ip6_plen) + sizeof(*ip6)
800 - off - (ti.th.th_off << 2);
801 } else {
802 m_freem(*m);
803 *m = 0;
804 break;
805 }
806 if (tcp->th_flags & TH_SYN)
807 ack++;
808 seq = 0;
809 flags = TH_RST|TH_ACK;
810 }
811 bcopy(&ti, ip6, sizeof(ti));
812 tcp_respond(NULL, ip6, (struct tcphdr *)(ip6 + 1),
813 *m, ack, seq, flags);
814 *m = NULL;
815 break;
816 }
817 default: /* Send an ICMP unreachable using code */
818 if (oif)
819 (*m)->m_pkthdr.rcvif = oif;
820 icmp6_error(*m, ICMP6_DST_UNREACH,
821 rule->fw_reject_code, 0);
822 *m = NULL;
823 break;
824 }
825 }
826
827 dropit:
828 /*
829 * Finally, drop the packet.
830 */
831 if (*m) {
832 m_freem(*m);
833 *m = NULL;
834 }
835 return(0);
836 }
837
838 static int
839 add_entry6(struct ip6_fw_head *chainptr, struct ip6_fw *frwl)
840 {
841 struct ip6_fw *ftmp = 0;
842 struct ip6_fw_chain *fwc = 0, *fcp, *fcpl = 0;
843 u_short nbr = 0;
844 int s;
845
846 fwc = malloc(sizeof *fwc, M_IP6FW, M_DONTWAIT);
847 ftmp = malloc(sizeof *ftmp, M_IP6FW, M_DONTWAIT);
848 if (!fwc || !ftmp) {
849 dprintf(("%s malloc said no\n", err_prefix));
850 if (fwc) free(fwc, M_IP6FW);
851 if (ftmp) free(ftmp, M_IP6FW);
852 return (ENOSPC);
853 }
854
855 bcopy(frwl, ftmp, sizeof(struct ip6_fw));
856 ftmp->fw_in_if.fu_via_if.name[IP6FW_IFNLEN - 1] = '\0';
857 ftmp->fw_pcnt = 0L;
858 ftmp->fw_bcnt = 0L;
859 fwc->rule = ftmp;
860
861 s = splnet();
862
863 if (!chainptr->lh_first) {
864 LIST_INSERT_HEAD(chainptr, fwc, chain);
865 splx(s);
866 return(0);
867 } else if (ftmp->fw_number == (u_short)-1) {
868 if (fwc) free(fwc, M_IP6FW);
869 if (ftmp) free(ftmp, M_IP6FW);
870 splx(s);
871 dprintf(("%s bad rule number\n", err_prefix));
872 return (EINVAL);
873 }
874
875 /* If entry number is 0, find highest numbered rule and add 100 */
876 if (ftmp->fw_number == 0) {
877 for (fcp = chainptr->lh_first; fcp; fcp = fcp->chain.le_next) {
878 if (fcp->rule->fw_number != (u_short)-1)
879 nbr = fcp->rule->fw_number;
880 else
881 break;
882 }
883 if (nbr < (u_short)-1 - 100)
884 nbr += 100;
885 ftmp->fw_number = nbr;
886 }
887
888 /* Got a valid number; now insert it, keeping the list ordered */
889 for (fcp = chainptr->lh_first; fcp; fcp = fcp->chain.le_next) {
890 if (fcp->rule->fw_number > ftmp->fw_number) {
891 if (fcpl) {
892 LIST_INSERT_AFTER(fcpl, fwc, chain);
893 } else {
894 LIST_INSERT_HEAD(chainptr, fwc, chain);
895 }
896 break;
897 } else {
898 fcpl = fcp;
899 }
900 }
901
902 splx(s);
903 return (0);
904 }
905
906 static int
907 del_entry6(struct ip6_fw_head *chainptr, u_short number)
908 {
909 struct ip6_fw_chain *fcp;
910 int s;
911
912 s = splnet();
913
914 fcp = chainptr->lh_first;
915 if (number != (u_short)-1) {
916 for (; fcp; fcp = fcp->chain.le_next) {
917 if (fcp->rule->fw_number == number) {
918 LIST_REMOVE(fcp, chain);
919 splx(s);
920 free(fcp->rule, M_IP6FW);
921 free(fcp, M_IP6FW);
922 return 0;
923 }
924 }
925 }
926
927 splx(s);
928 return (EINVAL);
929 }
930
931 static int
932 zero_entry6(struct mbuf *m)
933 {
934 struct ip6_fw *frwl;
935 struct ip6_fw_chain *fcp;
936 int s;
937
938 if (m && m->m_len != 0) {
939 if (m->m_len != sizeof(struct ip6_fw))
940 return(EINVAL);
941 frwl = mtod(m, struct ip6_fw *);
942 }
943 else
944 frwl = NULL;
945
946 /*
947 * It's possible to insert multiple chain entries with the
948 * same number, so we don't stop after finding the first
949 * match if zeroing a specific entry.
950 */
951 s = splnet();
952 for (fcp = ip6_fw_chain.lh_first; fcp; fcp = fcp->chain.le_next)
953 if (!frwl || frwl->fw_number == fcp->rule->fw_number) {
954 fcp->rule->fw_bcnt = fcp->rule->fw_pcnt = 0;
955 fcp->rule->timestamp = 0;
956 }
957 splx(s);
958
959 if (fw6_verbose) {
960 if (frwl)
961 log(LOG_SECURITY | LOG_NOTICE,
962 "ip6fw: Entry %d cleared.\n", frwl->fw_number);
963 else
964 log(LOG_SECURITY | LOG_NOTICE,
965 "ip6fw: Accounting cleared.\n");
966 }
967
968 return(0);
969 }
970
971 static struct ip6_fw *
972 check_ip6fw_mbuf(struct mbuf *m)
973 {
974 /* Check length */
975 if (m->m_len != sizeof(struct ip6_fw)) {
976 dprintf(("%s len=%d, want %d\n", err_prefix, m->m_len,
977 sizeof(struct ip6_fw)));
978 return (NULL);
979 }
980 return(check_ip6fw_struct(mtod(m, struct ip6_fw *)));
981 }
982
983 static struct ip6_fw *
984 check_ip6fw_struct(struct ip6_fw *frwl)
985 {
986 /* Check for invalid flag bits */
987 if ((frwl->fw_flg & ~IPV6_FW_F_MASK) != 0) {
988 dprintf(("%s undefined flag bits set (flags=%x)\n",
989 err_prefix, frwl->fw_flg));
990 return (NULL);
991 }
992 /* Must apply to incoming or outgoing (or both) */
993 if (!(frwl->fw_flg & (IPV6_FW_F_IN | IPV6_FW_F_OUT))) {
994 dprintf(("%s neither in nor out\n", err_prefix));
995 return (NULL);
996 }
997 /* Empty interface name is no good */
998 if (((frwl->fw_flg & IPV6_FW_F_IIFNAME)
999 && !*frwl->fw_in_if.fu_via_if.name)
1000 || ((frwl->fw_flg & IPV6_FW_F_OIFNAME)
1001 && !*frwl->fw_out_if.fu_via_if.name)) {
1002 dprintf(("%s empty interface name\n", err_prefix));
1003 return (NULL);
1004 }
1005 /* Sanity check interface matching */
1006 if ((frwl->fw_flg & IF6_FW_F_VIAHACK) == IF6_FW_F_VIAHACK) {
1007 ; /* allow "via" backwards compatibility */
1008 } else if ((frwl->fw_flg & IPV6_FW_F_IN)
1009 && (frwl->fw_flg & IPV6_FW_F_OIFACE)) {
1010 dprintf(("%s outgoing interface check on incoming\n",
1011 err_prefix));
1012 return (NULL);
1013 }
1014 /* Sanity check port ranges */
1015 if ((frwl->fw_flg & IPV6_FW_F_SRNG) && IPV6_FW_GETNSRCP(frwl) < 2) {
1016 dprintf(("%s src range set but n_src_p=%d\n",
1017 err_prefix, IPV6_FW_GETNSRCP(frwl)));
1018 return (NULL);
1019 }
1020 if ((frwl->fw_flg & IPV6_FW_F_DRNG) && IPV6_FW_GETNDSTP(frwl) < 2) {
1021 dprintf(("%s dst range set but n_dst_p=%d\n",
1022 err_prefix, IPV6_FW_GETNDSTP(frwl)));
1023 return (NULL);
1024 }
1025 if (IPV6_FW_GETNSRCP(frwl) + IPV6_FW_GETNDSTP(frwl) > IPV6_FW_MAX_PORTS) {
1026 dprintf(("%s too many ports (%d+%d)\n",
1027 err_prefix, IPV6_FW_GETNSRCP(frwl), IPV6_FW_GETNDSTP(frwl)));
1028 return (NULL);
1029 }
1030 /*
1031 * Protocols other than TCP/UDP don't use port range
1032 */
1033 if ((frwl->fw_prot != IPPROTO_TCP) &&
1034 (frwl->fw_prot != IPPROTO_UDP) &&
1035 (IPV6_FW_GETNSRCP(frwl) || IPV6_FW_GETNDSTP(frwl))) {
1036 dprintf(("%s port(s) specified for non TCP/UDP rule\n",
1037 err_prefix));
1038 return(NULL);
1039 }
1040
1041 /*
1042 * Rather than modify the entry to make such entries work,
1043 * we reject this rule and require user level utilities
1044 * to enforce whatever policy they deem appropriate.
1045 */
1046 if ((frwl->fw_src.s6_addr32[0] & (~frwl->fw_smsk.s6_addr32[0])) ||
1047 (frwl->fw_src.s6_addr32[1] & (~frwl->fw_smsk.s6_addr32[1])) ||
1048 (frwl->fw_src.s6_addr32[2] & (~frwl->fw_smsk.s6_addr32[2])) ||
1049 (frwl->fw_src.s6_addr32[3] & (~frwl->fw_smsk.s6_addr32[3])) ||
1050 (frwl->fw_dst.s6_addr32[0] & (~frwl->fw_dmsk.s6_addr32[0])) ||
1051 (frwl->fw_dst.s6_addr32[1] & (~frwl->fw_dmsk.s6_addr32[1])) ||
1052 (frwl->fw_dst.s6_addr32[2] & (~frwl->fw_dmsk.s6_addr32[2])) ||
1053 (frwl->fw_dst.s6_addr32[3] & (~frwl->fw_dmsk.s6_addr32[3]))) {
1054 dprintf(("%s rule never matches\n", err_prefix));
1055 return(NULL);
1056 }
1057
1058 if ((frwl->fw_flg & IPV6_FW_F_FRAG) &&
1059 (frwl->fw_prot == IPPROTO_UDP || frwl->fw_prot == IPPROTO_TCP)) {
1060 if (frwl->fw_nports) {
1061 dprintf(("%s cannot mix 'frag' and ports\n", err_prefix));
1062 return(NULL);
1063 }
1064 if (frwl->fw_prot == IPPROTO_TCP &&
1065 frwl->fw_tcpf != frwl->fw_tcpnf) {
1066 dprintf(("%s cannot mix 'frag' with TCP flags\n", err_prefix));
1067 return(NULL);
1068 }
1069 }
1070
1071 /* Check command specific stuff */
1072 switch (frwl->fw_flg & IPV6_FW_F_COMMAND)
1073 {
1074 case IPV6_FW_F_REJECT:
1075 if (frwl->fw_reject_code >= 0x100
1076 && !(frwl->fw_prot == IPPROTO_TCP
1077 && frwl->fw_reject_code == IPV6_FW_REJECT_RST)) {
1078 dprintf(("%s unknown reject code\n", err_prefix));
1079 return(NULL);
1080 }
1081 break;
1082 case IPV6_FW_F_DIVERT: /* Diverting to port zero is invalid */
1083 case IPV6_FW_F_TEE:
1084 if (frwl->fw_divert_port == 0) {
1085 dprintf(("%s can't divert to port 0\n", err_prefix));
1086 return (NULL);
1087 }
1088 break;
1089 case IPV6_FW_F_DENY:
1090 case IPV6_FW_F_ACCEPT:
1091 case IPV6_FW_F_COUNT:
1092 case IPV6_FW_F_SKIPTO:
1093 break;
1094 default:
1095 dprintf(("%s invalid command\n", err_prefix));
1096 return(NULL);
1097 }
1098
1099 return frwl;
1100 }
1101
1102 static int
1103 ip6_fw_ctl(int stage, struct mbuf **mm)
1104 {
1105 int error;
1106 struct mbuf *m;
1107
1108 if (stage == IPV6_FW_GET) {
1109 struct ip6_fw_chain *fcp = ip6_fw_chain.lh_first;
1110 *mm = m = m_get(M_WAIT, MT_DATA); /* XXX */
1111 if (!m)
1112 return(ENOBUFS);
1113 if (sizeof *(fcp->rule) > MLEN) {
1114 MCLGET(m, M_WAIT);
1115 if ((m->m_flags & M_EXT) == 0) {
1116 m_free(m);
1117 return(ENOBUFS);
1118 }
1119 }
1120 for (; fcp; fcp = fcp->chain.le_next) {
1121 bcopy(fcp->rule, m->m_data, sizeof *(fcp->rule));
1122 m->m_len = sizeof *(fcp->rule);
1123 m->m_next = m_get(M_WAIT, MT_DATA); /* XXX */
1124 if (!m->m_next) {
1125 m_freem(*mm);
1126 return(ENOBUFS);
1127 }
1128 m = m->m_next;
1129 if (sizeof *(fcp->rule) > MLEN) {
1130 MCLGET(m, M_WAIT);
1131 if ((m->m_flags & M_EXT) == 0) {
1132 m_freem(*mm);
1133 return(ENOBUFS);
1134 }
1135 }
1136 m->m_len = 0;
1137 }
1138 return (0);
1139 }
1140 m = *mm;
1141 /* only allow get calls if secure mode > 2 */
1142 if (securelevel > 2) {
1143 if (m) {
1144 (void)m_freem(m);
1145 *mm = 0;
1146 }
1147 return(EPERM);
1148 }
1149 if (stage == IPV6_FW_FLUSH) {
1150 while (ip6_fw_chain.lh_first != NULL &&
1151 ip6_fw_chain.lh_first->rule->fw_number != (u_short)-1) {
1152 struct ip6_fw_chain *fcp = ip6_fw_chain.lh_first;
1153 int s = splnet();
1154 LIST_REMOVE(ip6_fw_chain.lh_first, chain);
1155 splx(s);
1156 free(fcp->rule, M_IP6FW);
1157 free(fcp, M_IP6FW);
1158 }
1159 if (m) {
1160 (void)m_freem(m);
1161 *mm = 0;
1162 }
1163 return (0);
1164 }
1165 if (stage == IPV6_FW_ZERO) {
1166 error = zero_entry6(m);
1167 if (m) {
1168 (void)m_freem(m);
1169 *mm = 0;
1170 }
1171 return (error);
1172 }
1173 if (m == NULL) {
1174 printf("%s NULL mbuf ptr\n", err_prefix);
1175 return (EINVAL);
1176 }
1177
1178 if (stage == IPV6_FW_ADD) {
1179 struct ip6_fw *frwl = check_ip6fw_mbuf(m);
1180
1181 if (!frwl)
1182 error = EINVAL;
1183 else
1184 error = add_entry6(&ip6_fw_chain, frwl);
1185 if (m) {
1186 (void)m_freem(m);
1187 *mm = 0;
1188 }
1189 return error;
1190 }
1191 if (stage == IPV6_FW_DEL) {
1192 if (m->m_len != sizeof(struct ip6_fw)) {
1193 dprintf(("%s len=%d, want %d\n", err_prefix, m->m_len,
1194 sizeof(struct ip6_fw)));
1195 error = EINVAL;
1196 } else if (mtod(m, struct ip6_fw *)->fw_number == (u_short)-1) {
1197 dprintf(("%s can't delete rule 65535\n", err_prefix));
1198 error = EINVAL;
1199 } else
1200 error = del_entry6(&ip6_fw_chain,
1201 mtod(m, struct ip6_fw *)->fw_number);
1202 if (m) {
1203 (void)m_freem(m);
1204 *mm = 0;
1205 }
1206 return error;
1207 }
1208
1209 dprintf(("%s unknown request %d\n", err_prefix, stage));
1210 if (m) {
1211 (void)m_freem(m);
1212 *mm = 0;
1213 }
1214 return (EINVAL);
1215 }
1216
1217 void
1218 ip6_fw_init(void)
1219 {
1220 struct ip6_fw default_rule;
1221
1222 ip6_fw_chk_ptr = ip6_fw_chk;
1223 ip6_fw_ctl_ptr = ip6_fw_ctl;
1224 LIST_INIT(&ip6_fw_chain);
1225
1226 bzero(&default_rule, sizeof default_rule);
1227 default_rule.fw_prot = IPPROTO_IPV6;
1228 default_rule.fw_number = (u_short)-1;
1229 #ifdef IPV6FIREWALL_DEFAULT_TO_ACCEPT
1230 default_rule.fw_flg |= IPV6_FW_F_ACCEPT;
1231 #else
1232 default_rule.fw_flg |= IPV6_FW_F_DENY;
1233 #endif
1234 default_rule.fw_flg |= IPV6_FW_F_IN | IPV6_FW_F_OUT;
1235 if (check_ip6fw_struct(&default_rule) == NULL ||
1236 add_entry6(&ip6_fw_chain, &default_rule))
1237 panic(__FUNCTION__);
1238
1239 printf("IPv6 packet filtering initialized, ");
1240 #ifdef IPV6FIREWALL_DEFAULT_TO_ACCEPT
1241 printf("default to accept, ");
1242 #endif
1243 #ifndef IPV6FIREWALL_VERBOSE
1244 printf("logging disabled\n");
1245 #else
1246 if (fw6_verbose_limit == 0)
1247 printf("unlimited logging\n");
1248 else
1249 printf("logging limited to %d packets/entry\n",
1250 fw6_verbose_limit);
1251 #endif
1252 }
1253
1254 static ip6_fw_chk_t *old_chk_ptr;
1255 static ip6_fw_ctl_t *old_ctl_ptr;
1256
1257 static int
1258 ip6fw_modevent(module_t mod, int type, void *unused)
1259 {
1260 int s;
1261
1262 switch (type) {
1263 case MOD_LOAD:
1264 s = splnet();
1265
1266 old_chk_ptr = ip6_fw_chk_ptr;
1267 old_ctl_ptr = ip6_fw_ctl_ptr;
1268
1269 ip6_fw_init();
1270 splx(s);
1271 return 0;
1272 case MOD_UNLOAD:
1273 s = splnet();
1274 ip6_fw_chk_ptr = old_chk_ptr;
1275 ip6_fw_ctl_ptr = old_ctl_ptr;
1276 while (LIST_FIRST(&ip6_fw_chain) != NULL) {
1277 struct ip6_fw_chain *fcp = LIST_FIRST(&ip6_fw_chain);
1278 LIST_REMOVE(LIST_FIRST(&ip6_fw_chain), chain);
1279 free(fcp->rule, M_IP6FW);
1280 free(fcp, M_IP6FW);
1281 }
1282
1283 splx(s);
1284 printf("IPv6 firewall unloaded\n");
1285 return 0;
1286 default:
1287 break;
1288 }
1289 return 0;
1290 }
1291
1292 static moduledata_t ip6fwmod = {
1293 "ip6fw",
1294 ip6fw_modevent,
1295 0
1296 };
1297 DECLARE_MODULE(ip6fw, ip6fwmod, SI_SUB_PSEUDO, SI_ORDER_ANY);
Cache object: bc47db89e4a31595e1f32552b744ec62
|