]> git.saurik.com Git - apple/xnu.git/blob - bsd/netinet/ip_fw.c
xnu-201.42.3.tar.gz
[apple/xnu.git] / bsd / netinet / ip_fw.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*
23 * Copyright (c) 1993 Daniel Boulet
24 * Copyright (c) 1994 Ugen J.S.Antsilevich
25 * Copyright (c) 1996 Alex Nash
26 *
27 * Redistribution and use in source forms, with and without modification,
28 * are permitted provided that this entire comment appears intact.
29 *
30 * Redistribution in binary form may occur without any restrictions.
31 * Obviously, it would be nice if you gave credit where credit is due
32 * but requiring it would be too onerous.
33 *
34 * This software is provided ``AS IS'' without any warranties of any kind.
35 *
36 */
37
38 /*
39 * Implement IP packet firewall
40 */
41 #if !IPFIREWALL_KEXT
42 #if ISFB31
43 #if !defined(KLD_MODULE) && !defined(IPFIREWALL_MODULE)
44 #include "opt_ipfw.h"
45 #include "opt_ipdn.h"
46 #include "opt_ipdivert.h"
47 #include "opt_inet.h"
48 #endif
49 #endif
50 #ifndef INET
51 #error IPFIREWALL requires INET.
52 #endif /* INET */
53
54 #include <sys/param.h>
55 #include <sys/systm.h>
56 #include <sys/malloc.h>
57 #include <sys/mbuf.h>
58 #include <sys/kernel.h>
59 #include <sys/socket.h>
60 #include <sys/socketvar.h>
61 #include <sys/sysctl.h>
62 #include <net/if.h>
63 #include <netinet/in.h>
64 #include <netinet/in_systm.h>
65 #include <netinet/ip.h>
66 #include <netinet/ip_var.h>
67 #include <netinet/ip_icmp.h>
68 #include <netinet/ip_fw.h>
69 #if DUMMYNET
70 #include <net/route.h>
71 #include <netinet/ip_dummynet.h>
72 #endif
73 #include <netinet/tcp.h>
74 #include <netinet/tcp_timer.h>
75 #include <netinet/tcp_var.h>
76 #ifdef INET6
77 #include <netinet/ip6.h>
78 #endif
79 #include <netinet/tcpip.h>
80 #include <netinet/udp.h>
81 #include <netinet/udp_var.h>
82
83 #include <netinet/if_ether.h> /* XXX ethertype_ip */
84
85 static int fw_debug = 1;
86 #if IPFIREWALL_VERBOSE
87 static int fw_verbose = 1;
88 #else
89 static int fw_verbose = 0;
90 #endif
91 static int fw_one_pass = 0; /* XXX */
92 #if IPFIREWALL_VERBOSE_LIMIT
93 static int fw_verbose_limit = IPFIREWALL_VERBOSE_LIMIT;
94 #else
95 static int fw_verbose_limit = 0;
96 #endif
97
98 #define IPFW_DEFAULT_RULE ((u_int)(u_short)~0)
99
100 LIST_HEAD (ip_fw_head, ip_fw_chain) ip_fw_chain;
101
102 MALLOC_DEFINE(M_IPFW, "IpFw/IpAcct", "IpFw/IpAcct chain's");
103
104 SYSCTL_DECL(_net_inet_ip);
105 SYSCTL_NODE(_net_inet_ip, OID_AUTO, fw, CTLFLAG_RW, 0, "Firewall");
106 SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, debug, CTLFLAG_RW, &fw_debug, 0, "");
107 SYSCTL_INT(_net_inet_ip_fw, OID_AUTO,one_pass,CTLFLAG_RW, &fw_one_pass, 0, "");
108 SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, verbose, CTLFLAG_RW, &fw_verbose, 0, "");
109 SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, verbose_limit, CTLFLAG_RW, &fw_verbose_limit, 0, "");
110
111 #define dprintf(a) if (!fw_debug); else printf a
112
113 #define print_ip(a) printf("%d.%d.%d.%d", \
114 (int)(ntohl(a.s_addr) >> 24) & 0xFF, \
115 (int)(ntohl(a.s_addr) >> 16) & 0xFF, \
116 (int)(ntohl(a.s_addr) >> 8) & 0xFF, \
117 (int)(ntohl(a.s_addr)) & 0xFF);
118
119 #define dprint_ip(a) if (!fw_debug); else print_ip(a)
120
121 static int add_entry __P((struct ip_fw_head *chainptr, struct ip_fw *frwl));
122 static int del_entry __P((struct ip_fw_head *chainptr, u_short number));
123 static int zero_entry __P((struct ip_fw *));
124 static int check_ipfw_struct __P((struct ip_fw *m));
125 static __inline int
126 iface_match __P((struct ifnet *ifp, union ip_fw_if *ifu,
127 int byname));
128 static int ipopts_match __P((struct ip *ip, struct ip_fw *f));
129 static __inline int
130 port_match __P((u_short *portptr, int nports, u_short port,
131 int range_flag));
132 static int tcpflg_match __P((struct tcphdr *tcp, struct ip_fw *f));
133 static int icmptype_match __P((struct icmp * icmp, struct ip_fw * f));
134 static void ipfw_report __P((struct ip_fw *f, struct ip *ip,
135 struct ifnet *rif, struct ifnet *oif));
136
137 static void flush_rule_ptrs(void);
138
139 static int ip_fw_chk __P((struct ip **pip, int hlen,
140 struct ifnet *oif, u_int16_t *cookie, struct mbuf **m,
141 struct ip_fw_chain **flow_id,
142 struct sockaddr_in **next_hop));
143 static int ip_fw_ctl __P((struct sockopt *sopt));
144
145 static char err_prefix[] = "ip_fw_ctl:";
146
147 /*
148 * Returns 1 if the port is matched by the vector, 0 otherwise
149 */
150 static __inline int
151 port_match(u_short *portptr, int nports, u_short port, int range_flag)
152 {
153 if (!nports)
154 return 1;
155 if (range_flag) {
156 if (portptr[0] <= port && port <= portptr[1]) {
157 return 1;
158 }
159 nports -= 2;
160 portptr += 2;
161 }
162 while (nports-- > 0) {
163 if (*portptr++ == port) {
164 return 1;
165 }
166 }
167 return 0;
168 }
169
170 static int
171 tcpflg_match(struct tcphdr *tcp, struct ip_fw *f)
172 {
173 u_char flg_set, flg_clr;
174
175 if ((f->fw_tcpf & IP_FW_TCPF_ESTAB) &&
176 (tcp->th_flags & (IP_FW_TCPF_RST | IP_FW_TCPF_ACK)))
177 return 1;
178
179 flg_set = tcp->th_flags & f->fw_tcpf;
180 flg_clr = tcp->th_flags & f->fw_tcpnf;
181
182 if (flg_set != f->fw_tcpf)
183 return 0;
184 if (flg_clr)
185 return 0;
186
187 return 1;
188 }
189
190 static int
191 icmptype_match(struct icmp *icmp, struct ip_fw *f)
192 {
193 int type;
194
195 if (!(f->fw_flg & IP_FW_F_ICMPBIT))
196 return(1);
197
198 type = icmp->icmp_type;
199
200 /* check for matching type in the bitmap */
201 if (type < IP_FW_ICMPTYPES_MAX &&
202 (f->fw_uar.fw_icmptypes[type / (sizeof(unsigned) * 8)] &
203 (1U << (type % (8 * sizeof(unsigned))))))
204 return(1);
205
206 return(0); /* no match */
207 }
208
209 static int
210 is_icmp_query(struct ip *ip)
211 {
212 const struct icmp *icmp;
213 int icmp_type;
214
215 icmp = (struct icmp *)((u_int32_t *)ip + ip->ip_hl);
216 icmp_type = icmp->icmp_type;
217
218 if (icmp_type == ICMP_ECHO || icmp_type == ICMP_ROUTERSOLICIT ||
219 icmp_type == ICMP_TSTAMP || icmp_type == ICMP_IREQ ||
220 icmp_type == ICMP_MASKREQ)
221 return(1);
222
223 return(0);
224 }
225
226 static int
227 ipopts_match(struct ip *ip, struct ip_fw *f)
228 {
229 register u_char *cp;
230 int opt, optlen, cnt;
231 u_char opts, nopts, nopts_sve;
232
233 cp = (u_char *)(ip + 1);
234 cnt = (ip->ip_hl << 2) - sizeof (struct ip);
235 opts = f->fw_ipopt;
236 nopts = nopts_sve = f->fw_ipnopt;
237
238 for (; cnt > 0; cnt -= optlen, cp += optlen) {
239 opt = cp[IPOPT_OPTVAL];
240 if (opt == IPOPT_EOL)
241 break;
242 if (opt == IPOPT_NOP)
243 optlen = 1;
244 else {
245 optlen = cp[IPOPT_OLEN];
246 if (optlen <= 0 || optlen > cnt) {
247 return 0; /*XXX*/
248 }
249 }
250 switch (opt) {
251
252 default:
253 break;
254
255 case IPOPT_LSRR:
256 opts &= ~IP_FW_IPOPT_LSRR;
257 nopts &= ~IP_FW_IPOPT_LSRR;
258 break;
259
260 case IPOPT_SSRR:
261 opts &= ~IP_FW_IPOPT_SSRR;
262 nopts &= ~IP_FW_IPOPT_SSRR;
263 break;
264
265 case IPOPT_RR:
266 opts &= ~IP_FW_IPOPT_RR;
267 nopts &= ~IP_FW_IPOPT_RR;
268 break;
269 case IPOPT_TS:
270 opts &= ~IP_FW_IPOPT_TS;
271 nopts &= ~IP_FW_IPOPT_TS;
272 break;
273 }
274 if (opts == nopts)
275 break;
276 }
277 if (opts == 0 && nopts == nopts_sve)
278 return 1;
279 else
280 return 0;
281 }
282
283 static __inline int
284 iface_match(struct ifnet *ifp, union ip_fw_if *ifu, int byname)
285 {
286 /* Check by name or by IP address */
287 if (byname) {
288 /* Check unit number (-1 is wildcard) */
289 if (ifu->fu_via_if.unit != -1
290 && ifp->if_unit != ifu->fu_via_if.unit)
291 return(0);
292 /* Check name */
293 if (strncmp(ifp->if_name, ifu->fu_via_if.name, FW_IFNLEN))
294 return(0);
295 return(1);
296 } else if (ifu->fu_via_ip.s_addr != 0) { /* Zero == wildcard */
297 struct ifaddr *ia;
298
299 for (ia = ifp->if_addrhead.tqh_first;
300 ia != NULL; ia = ia->ifa_link.tqe_next) {
301 if (ia->ifa_addr == NULL)
302 continue;
303 if (ia->ifa_addr->sa_family != AF_INET)
304 continue;
305 if (ifu->fu_via_ip.s_addr != ((struct sockaddr_in *)
306 (ia->ifa_addr))->sin_addr.s_addr)
307 continue;
308 return(1);
309 }
310 return(0);
311 }
312 return(1);
313 }
314
315 static void
316 ipfw_report(struct ip_fw *f, struct ip *ip,
317 struct ifnet *rif, struct ifnet *oif)
318 {
319 if (ip) {
320 static u_int64_t counter;
321 struct tcphdr *const tcp = (struct tcphdr *) ((u_int32_t *) ip+ ip->ip_hl);
322 struct udphdr *const udp = (struct udphdr *) ((u_int32_t *) ip+ ip->ip_hl);
323 struct icmp *const icmp = (struct icmp *) ((u_int32_t *) ip + ip->ip_hl);
324 int count;
325
326 count = f ? f->fw_pcnt : ++counter;
327 if (fw_verbose_limit != 0 && count > fw_verbose_limit)
328 return;
329
330 /* Print command name */
331 printf("ipfw: %d ", f ? f->fw_number : -1);
332 if (!f)
333 printf("Refuse");
334 else
335 switch (f->fw_flg & IP_FW_F_COMMAND) {
336 case IP_FW_F_DENY:
337 printf("Deny");
338 break;
339 case IP_FW_F_REJECT:
340 if (f->fw_reject_code == IP_FW_REJECT_RST)
341 printf("Reset");
342 else
343 printf("Unreach");
344 break;
345 case IP_FW_F_ACCEPT:
346 printf("Accept");
347 break;
348 case IP_FW_F_COUNT:
349 printf("Count");
350 break;
351 case IP_FW_F_DIVERT:
352 printf("Divert %d", f->fw_divert_port);
353 break;
354 case IP_FW_F_TEE:
355 printf("Tee %d", f->fw_divert_port);
356 break;
357 case IP_FW_F_SKIPTO:
358 printf("SkipTo %d", f->fw_skipto_rule);
359 break;
360 #if DUMMYNET
361 case IP_FW_F_PIPE:
362 printf("Pipe %d", f->fw_skipto_rule);
363 break;
364 #endif
365 #if IPFIREWALL_FORWARD
366 case IP_FW_F_FWD:
367 printf("Forward to ");
368 print_ip(f->fw_fwd_ip.sin_addr);
369 if (f->fw_fwd_ip.sin_port)
370 printf(":%d", f->fw_fwd_ip.sin_port);
371 break;
372 #endif
373 default:
374 printf("UNKNOWN");
375 break;
376 }
377 printf(" ");
378
379 switch (ip->ip_p) {
380 case IPPROTO_TCP:
381 printf("TCP ");
382 print_ip(ip->ip_src);
383 if ((ip->ip_off & IP_OFFMASK) == 0)
384 printf(":%d ", ntohs(tcp->th_sport));
385 else
386 printf(" ");
387 print_ip(ip->ip_dst);
388 if ((ip->ip_off & IP_OFFMASK) == 0)
389 printf(":%d", ntohs(tcp->th_dport));
390 break;
391 case IPPROTO_UDP:
392 printf("UDP ");
393 print_ip(ip->ip_src);
394 if ((ip->ip_off & IP_OFFMASK) == 0)
395 printf(":%d ", ntohs(udp->uh_sport));
396 else
397 printf(" ");
398 print_ip(ip->ip_dst);
399 if ((ip->ip_off & IP_OFFMASK) == 0)
400 printf(":%d", ntohs(udp->uh_dport));
401 break;
402 case IPPROTO_ICMP:
403 if ((ip->ip_off & IP_OFFMASK) == 0)
404 printf("ICMP:%u.%u ", icmp->icmp_type, icmp->icmp_code);
405 else
406 printf("ICMP ");
407 print_ip(ip->ip_src);
408 printf(" ");
409 print_ip(ip->ip_dst);
410 break;
411 default:
412 printf("P:%d ", ip->ip_p);
413 print_ip(ip->ip_src);
414 printf(" ");
415 print_ip(ip->ip_dst);
416 break;
417 }
418 if (oif)
419 printf(" out via %s%d", oif->if_name, oif->if_unit);
420 else if (rif)
421 printf(" in via %s%d", rif->if_name, rif->if_unit);
422 if ((ip->ip_off & IP_OFFMASK))
423 printf(" Fragment = %d",ip->ip_off & IP_OFFMASK);
424 printf("\n");
425 if (fw_verbose_limit != 0 && count == fw_verbose_limit)
426 printf("ipfw: limit reached on rule #%d\n",
427 f ? f->fw_number : -1);
428 }
429 }
430
431 /*
432 * given an ip_fw_chain *, lookup_next_rule will return a pointer
433 * of the same type to the next one. This can be either the jump
434 * target (for skipto instructions) or the next one in the chain (in
435 * all other cases including a missing jump target).
436 * Backward jumps are not allowed, so start looking from the next
437 * rule...
438 */
439 static struct ip_fw_chain * lookup_next_rule(struct ip_fw_chain *me);
440
441 static struct ip_fw_chain *
442 lookup_next_rule(struct ip_fw_chain *me)
443 {
444 struct ip_fw_chain *chain ;
445 int rule = me->rule->fw_skipto_rule ; /* guess... */
446
447 if ( (me->rule->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_SKIPTO )
448 for (chain = me->chain.le_next; chain ; chain = chain->chain.le_next )
449 if (chain->rule->fw_number >= rule)
450 return chain ;
451 return me->chain.le_next ; /* failure or not a skipto */
452 }
453
454 /*
455 * Parameters:
456 *
457 * pip Pointer to packet header (struct ip **)
458 * bridge_ipfw extension: pip = NULL means a complete ethernet packet
459 * including ethernet header in the mbuf. Other fields
460 * are ignored/invalid.
461 *
462 * hlen Packet header length
463 * oif Outgoing interface, or NULL if packet is incoming
464 * *cookie Skip up to the first rule past this rule number;
465 * *m The packet; we set to NULL when/if we nuke it.
466 * *flow_id pointer to the last matching rule (in/out)
467 * *next_hop socket we are forwarding to (in/out).
468 *
469 * Return value:
470 *
471 * 0 The packet is to be accepted and routed normally OR
472 * the packet was denied/rejected and has been dropped;
473 * in the latter case, *m is equal to NULL upon return.
474 * port Divert the packet to port.
475 */
476
477 static int
478 ip_fw_chk(struct ip **pip, int hlen,
479 struct ifnet *oif, u_int16_t *cookie, struct mbuf **m,
480 struct ip_fw_chain **flow_id,
481 struct sockaddr_in **next_hop)
482 {
483 struct ip_fw_chain *chain;
484 struct ip_fw *rule = NULL;
485 struct ip *ip = NULL ;
486 struct ifnet *const rif = (*m)->m_pkthdr.rcvif;
487 u_short offset = 0 ;
488 u_short src_port, dst_port;
489 u_int16_t skipto = *cookie;
490
491 if (pip) { /* normal ip packet */
492 ip = *pip;
493 offset = (ip->ip_off & IP_OFFMASK);
494 } else { /* bridged or non-ip packet */
495 struct ether_header *eh = mtod(*m, struct ether_header *);
496 switch (ntohs(eh->ether_type)) {
497 case ETHERTYPE_IP :
498 if ((*m)->m_len<sizeof(struct ether_header) + sizeof(struct ip))
499 goto non_ip ;
500 ip = (struct ip *)(eh + 1 );
501 if (ip->ip_v != IPVERSION)
502 goto non_ip ;
503 hlen = ip->ip_hl << 2;
504 if (hlen < sizeof(struct ip)) /* minimum header length */
505 goto non_ip ;
506 if ((*m)->m_len < 14 + hlen + 14) {
507 printf("-- m_len %d, need more...\n", (*m)->m_len);
508 goto non_ip ;
509 }
510 offset = (ip->ip_off & IP_OFFMASK);
511 break ;
512 default :
513 non_ip: ip = NULL ;
514 break ;
515 }
516 }
517
518 if (*flow_id) {
519 if (fw_one_pass)
520 return 0 ; /* accept if passed first test */
521 /*
522 * pkt has already been tagged. Look for the next rule
523 * to restart processing
524 */
525 chain = LIST_NEXT( *flow_id, chain);
526
527 if ( (chain = (*flow_id)->rule->next_rule_ptr) == NULL )
528 chain = (*flow_id)->rule->next_rule_ptr =
529 lookup_next_rule(*flow_id) ;
530 if (! chain) goto dropit;
531 } else {
532 /*
533 * Go down the chain, looking for enlightment
534 * If we've been asked to start at a given rule immediatly, do so.
535 */
536 chain = LIST_FIRST(&ip_fw_chain);
537 if ( skipto ) {
538 if (skipto >= IPFW_DEFAULT_RULE)
539 goto dropit;
540 while (chain && (chain->rule->fw_number <= skipto)) {
541 chain = LIST_NEXT(chain, chain);
542 }
543 if (! chain) goto dropit;
544 }
545 }
546 *cookie = 0;
547 for (; chain; chain = LIST_NEXT(chain, chain)) {
548 register struct ip_fw * f ;
549 again:
550 f = chain->rule;
551
552 if (oif) {
553 /* Check direction outbound */
554 if (!(f->fw_flg & IP_FW_F_OUT))
555 continue;
556 } else {
557 /* Check direction inbound */
558 if (!(f->fw_flg & IP_FW_F_IN))
559 continue;
560 }
561 if (ip == NULL ) {
562 /*
563 * do relevant checks for non-ip packets:
564 * after this, only goto got_match or continue
565 */
566 struct ether_header *eh = mtod(*m, struct ether_header *);
567
568 /*
569 * make default rule always match or we have a panic
570 */
571 if (f->fw_number == IPFW_DEFAULT_RULE)
572 goto got_match ;
573 /*
574 * temporary hack:
575 * udp from 0.0.0.0 means this rule applies.
576 * 1 src port is match ether type
577 * 2 src ports (interval) is match ether type
578 * 3 src ports is match ether address
579 */
580 if ( f->fw_src.s_addr != 0 || f->fw_prot != IPPROTO_UDP
581 || f->fw_smsk.s_addr != 0xffffffff )
582 continue;
583 switch (IP_FW_GETNSRCP(f)) {
584 case 1: /* match one type */
585 if ( /* ( (f->fw_flg & IP_FW_F_INVSRC) != 0) ^ */
586 ( f->fw_uar.fw_pts[0] == ntohs(eh->ether_type) ) ) {
587 goto got_match ;
588 }
589 break ;
590 default:
591 break ;
592 }
593 continue ;
594 }
595
596 /* Fragments */
597 if ((f->fw_flg & IP_FW_F_FRAG) && offset == 0 )
598 continue;
599
600 /* If src-addr doesn't match, not this rule. */
601 if (((f->fw_flg & IP_FW_F_INVSRC) != 0) ^ ((ip->ip_src.s_addr
602 & f->fw_smsk.s_addr) != f->fw_src.s_addr))
603 continue;
604
605 /* If dest-addr doesn't match, not this rule. */
606 if (((f->fw_flg & IP_FW_F_INVDST) != 0) ^ ((ip->ip_dst.s_addr
607 & f->fw_dmsk.s_addr) != f->fw_dst.s_addr))
608 continue;
609
610 /* Interface check */
611 if ((f->fw_flg & IF_FW_F_VIAHACK) == IF_FW_F_VIAHACK) {
612 struct ifnet *const iface = oif ? oif : rif;
613
614 /* Backwards compatibility hack for "via" */
615 if (!iface || !iface_match(iface,
616 &f->fw_in_if, f->fw_flg & IP_FW_F_OIFNAME))
617 continue;
618 } else {
619 /* Check receive interface */
620 if ((f->fw_flg & IP_FW_F_IIFACE)
621 && (!rif || !iface_match(rif,
622 &f->fw_in_if, f->fw_flg & IP_FW_F_IIFNAME)))
623 continue;
624 /* Check outgoing interface */
625 if ((f->fw_flg & IP_FW_F_OIFACE)
626 && (!oif || !iface_match(oif,
627 &f->fw_out_if, f->fw_flg & IP_FW_F_OIFNAME)))
628 continue;
629 }
630
631 /* Check IP options */
632 if (f->fw_ipopt != f->fw_ipnopt && !ipopts_match(ip, f))
633 continue;
634
635 /* Check protocol; if wildcard, match */
636 if (f->fw_prot == IPPROTO_IP)
637 goto got_match;
638
639 /* If different, don't match */
640 if (ip->ip_p != f->fw_prot)
641 continue;
642
643 /*
644 * here, pip==NULL for bridged pkts -- they include the ethernet
645 * header so i have to adjust lengths accordingly
646 */
647 #define PULLUP_TO(l) do { \
648 int len = (pip ? l : l + 14 ) ; \
649 if ((*m)->m_len < (len) ) { \
650 if ( (*m = m_pullup(*m, (len))) == 0) \
651 goto bogusfrag; \
652 ip = mtod(*m, struct ip *); \
653 if (pip) \
654 *pip = ip ; \
655 else \
656 ip = (struct ip *)((int)ip + 14); \
657 offset = (ip->ip_off & IP_OFFMASK); \
658 } \
659 } while (0)
660
661 /* Protocol specific checks */
662 switch (ip->ip_p) {
663 case IPPROTO_TCP:
664 {
665 struct tcphdr *tcp;
666
667 if (offset == 1) /* cf. RFC 1858 */
668 goto bogusfrag;
669 if (offset != 0) {
670 /*
671 * TCP flags and ports aren't available in this
672 * packet -- if this rule specified either one,
673 * we consider the rule a non-match.
674 */
675 if (f->fw_nports != 0 ||
676 f->fw_tcpf != f->fw_tcpnf)
677 continue;
678
679 break;
680 }
681 PULLUP_TO(hlen + 14);
682 tcp = (struct tcphdr *) ((u_int32_t *)ip + ip->ip_hl);
683 if (f->fw_tcpf != f->fw_tcpnf && !tcpflg_match(tcp, f))
684 continue;
685 src_port = ntohs(tcp->th_sport);
686 dst_port = ntohs(tcp->th_dport);
687 goto check_ports;
688 }
689
690 case IPPROTO_UDP:
691 {
692 struct udphdr *udp;
693
694 if (offset != 0) {
695 /*
696 * Port specification is unavailable -- if this
697 * rule specifies a port, we consider the rule
698 * a non-match.
699 */
700 if (f->fw_nports != 0)
701 continue;
702
703 break;
704 }
705 PULLUP_TO(hlen + 4);
706 udp = (struct udphdr *) ((u_int32_t *)ip + ip->ip_hl);
707 src_port = ntohs(udp->uh_sport);
708 dst_port = ntohs(udp->uh_dport);
709 check_ports:
710 if (!port_match(&f->fw_uar.fw_pts[0],
711 IP_FW_GETNSRCP(f), src_port,
712 f->fw_flg & IP_FW_F_SRNG))
713 continue;
714 if (!port_match(&f->fw_uar.fw_pts[IP_FW_GETNSRCP(f)],
715 IP_FW_GETNDSTP(f), dst_port,
716 f->fw_flg & IP_FW_F_DRNG))
717 continue;
718 break;
719 }
720
721 case IPPROTO_ICMP:
722 {
723 struct icmp *icmp;
724
725 if (offset != 0) /* Type isn't valid */
726 break;
727 PULLUP_TO(hlen + 2);
728 icmp = (struct icmp *) ((u_int32_t *)ip + ip->ip_hl);
729 if (!icmptype_match(icmp, f))
730 continue;
731 break;
732 }
733 #undef PULLUP_TO
734
735 bogusfrag:
736 if (fw_verbose)
737 ipfw_report(NULL, ip, rif, oif);
738 goto dropit;
739 }
740
741 got_match:
742 *flow_id = chain ; /* XXX set flow id */
743 /* Update statistics */
744 f->fw_pcnt += 1;
745 if (ip) {
746 f->fw_bcnt += ip->ip_len;
747 }
748 f->timestamp = time_second;
749
750 /* Log to console if desired */
751 if ((f->fw_flg & IP_FW_F_PRN) && fw_verbose)
752 ipfw_report(f, ip, rif, oif);
753
754 /* Take appropriate action */
755 switch (f->fw_flg & IP_FW_F_COMMAND) {
756 case IP_FW_F_ACCEPT:
757 return(0);
758 case IP_FW_F_COUNT:
759 continue;
760 #if IPDIVERT
761 case IP_FW_F_DIVERT:
762 *cookie = f->fw_number;
763 return(f->fw_divert_port);
764 #endif
765 case IP_FW_F_TEE:
766 /*
767 * XXX someday tee packet here, but beware that you
768 * can't use m_copym() or m_copypacket() because
769 * the divert input routine modifies the mbuf
770 * (and these routines only increment reference
771 * counts in the case of mbuf clusters), so need
772 * to write custom routine.
773 */
774 continue;
775 case IP_FW_F_SKIPTO: /* XXX check */
776 if ( f->next_rule_ptr )
777 chain = f->next_rule_ptr ;
778 else
779 chain = lookup_next_rule(chain) ;
780 if (! chain) goto dropit;
781 goto again ;
782 #if DUMMYNET
783 case IP_FW_F_PIPE:
784 return(f->fw_pipe_nr | 0x10000 );
785 #endif
786 #if IPFIREWALL_FORWARD
787 case IP_FW_F_FWD:
788 /* Change the next-hop address for this packet.
789 * Initially we'll only worry about directly
790 * reachable next-hop's, but ultimately
791 * we will work out for next-hops that aren't
792 * direct the route we would take for it. We
793 * [cs]ould leave this latter problem to
794 * ip_output.c. We hope to high [name the abode of
795 * your favourite deity] that ip_output doesn't modify
796 * the new value of next_hop (which is dst there)
797 */
798 if (next_hop != NULL) /* Make sure, first... */
799 *next_hop = &(f->fw_fwd_ip);
800 return(0); /* Allow the packet */
801 #endif
802 }
803
804 /* Deny/reject this packet using this rule */
805 rule = f;
806 break;
807
808 }
809
810 #if DIAGNOSTIC
811 /* Rule IPFW_DEFAULT_RULE should always be there and should always match */
812 if (!chain)
813 panic("ip_fw: chain");
814 #endif
815
816 /*
817 * At this point, we're going to drop the packet.
818 * Send a reject notice if all of the following are true:
819 *
820 * - The packet matched a reject rule
821 * - The packet is not an ICMP packet, or is an ICMP query packet
822 * - The packet is not a multicast or broadcast packet
823 */
824 if ((rule->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_REJECT
825 && ip
826 && (ip->ip_p != IPPROTO_ICMP || is_icmp_query(ip))
827 && !((*m)->m_flags & (M_BCAST|M_MCAST))
828 && !IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
829 switch (rule->fw_reject_code) {
830 case IP_FW_REJECT_RST:
831 {
832 struct tcphdr *const tcp =
833 (struct tcphdr *) ((u_int32_t *)ip + ip->ip_hl);
834 struct tcpiphdr ti, *const tip = (struct tcpiphdr *) ip;
835
836 if (offset != 0 || (tcp->th_flags & TH_RST))
837 break;
838 ti.ti_i = *((struct ipovly *) ip);
839 ti.ti_t = *tcp;
840 bcopy(&ti, ip, sizeof(ti));
841 NTOHL(tip->ti_seq);
842 NTOHL(tip->ti_ack);
843 tip->ti_len = ip->ip_len - hlen - (tip->ti_off << 2);
844 if (tcp->th_flags & TH_ACK) {
845 tcp_respond(NULL, (void *)tip, &tip->ti_t, *m,
846 (tcp_seq)0, ntohl(tcp->th_ack), TH_RST, 0);
847 } else {
848 if (tcp->th_flags & TH_SYN)
849 tip->ti_len++;
850 tcp_respond(NULL, (void *)tip, &tip->ti_t, *m,
851 tip->ti_seq + tip->ti_len,
852 (tcp_seq)0, TH_RST|TH_ACK, 0);
853 }
854 *m = NULL;
855 break;
856 }
857 default: /* Send an ICMP unreachable using code */
858 icmp_error(*m, ICMP_UNREACH,
859 rule->fw_reject_code, 0L, 0);
860 *m = NULL;
861 break;
862 }
863 }
864
865 dropit:
866 /*
867 * Finally, drop the packet.
868 */
869 /* *cookie = 0; */ /* XXX is this necessary ? */
870 if (*m) {
871 m_freem(*m);
872 *m = NULL;
873 }
874 return(0);
875 }
876
877 /*
878 * when a rule is added/deleted, zero the direct pointers within
879 * all firewall rules. These will be reconstructed on the fly
880 * as packets are matched.
881 * Must be called at splnet().
882 */
883 static void
884 flush_rule_ptrs()
885 {
886 struct ip_fw_chain *fcp ;
887
888 for (fcp = ip_fw_chain.lh_first; fcp; fcp = fcp->chain.le_next) {
889 fcp->rule->next_rule_ptr = NULL ;
890 }
891 }
892
893 static int
894 add_entry(struct ip_fw_head *chainptr, struct ip_fw *frwl)
895 {
896 struct ip_fw *ftmp = 0;
897 struct ip_fw_chain *fwc = 0, *fcp, *fcpl = 0;
898 u_short nbr = 0;
899 int s;
900
901 fwc = _MALLOC(sizeof *fwc, M_IPFW, M_NOWAIT);
902 ftmp = _MALLOC(sizeof *ftmp, M_IPFW, M_NOWAIT);
903 if (!fwc || !ftmp) {
904 dprintf(("%s MALLOC said no\n", err_prefix));
905 if (fwc) FREE(fwc, M_IPFW);
906 if (ftmp) FREE(ftmp, M_IPFW);
907 return (ENOSPC);
908 }
909
910 bcopy(frwl, ftmp, sizeof(struct ip_fw));
911 ftmp->fw_in_if.fu_via_if.name[FW_IFNLEN - 1] = '\0';
912 ftmp->fw_pcnt = 0L;
913 ftmp->fw_bcnt = 0L;
914 ftmp->next_rule_ptr = NULL ;
915 ftmp->pipe_ptr = NULL ;
916 fwc->rule = ftmp;
917
918 s = splnet();
919
920 if (chainptr->lh_first == 0) {
921 LIST_INSERT_HEAD(chainptr, fwc, chain);
922 splx(s);
923 return(0);
924 }
925
926 /* If entry number is 0, find highest numbered rule and add 100 */
927 if (ftmp->fw_number == 0) {
928 for (fcp = LIST_FIRST(chainptr); fcp; fcp = LIST_NEXT(fcp, chain)) {
929 if (fcp->rule->fw_number != (u_short)-1)
930 nbr = fcp->rule->fw_number;
931 else
932 break;
933 }
934 if (nbr < IPFW_DEFAULT_RULE - 100)
935 nbr += 100;
936 ftmp->fw_number = nbr;
937 }
938
939 /* Got a valid number; now insert it, keeping the list ordered */
940 for (fcp = LIST_FIRST(chainptr); fcp; fcp = LIST_NEXT(fcp, chain)) {
941 if (fcp->rule->fw_number > ftmp->fw_number) {
942 if (fcpl) {
943 LIST_INSERT_AFTER(fcpl, fwc, chain);
944 } else {
945 LIST_INSERT_HEAD(chainptr, fwc, chain);
946 }
947 break;
948 } else {
949 fcpl = fcp;
950 }
951 }
952 flush_rule_ptrs();
953
954 splx(s);
955 return (0);
956 }
957
958 static int
959 del_entry(struct ip_fw_head *chainptr, u_short number)
960 {
961 struct ip_fw_chain *fcp;
962
963 fcp = LIST_FIRST(chainptr);
964 if (number != (u_short)-1) {
965 for (; fcp; fcp = LIST_NEXT(fcp, chain)) {
966 if (fcp->rule->fw_number == number) {
967 int s;
968
969 /* prevent access to rules while removing them */
970 s = splnet();
971 while (fcp && fcp->rule->fw_number == number) {
972 struct ip_fw_chain *next;
973
974 next = LIST_NEXT(fcp, chain);
975 LIST_REMOVE(fcp, chain);
976 #if DUMMYNET
977 dn_rule_delete(fcp) ;
978 #endif
979 flush_rule_ptrs();
980 FREE(fcp->rule, M_IPFW);
981 FREE(fcp, M_IPFW);
982 fcp = next;
983 }
984 splx(s);
985 return 0;
986 }
987 }
988 }
989
990 return (EINVAL);
991 }
992
993 static int
994 zero_entry(struct ip_fw *frwl)
995 {
996 struct ip_fw_chain *fcp;
997 int s, cleared;
998
999 if (frwl == 0) {
1000 s = splnet();
1001 for (fcp = LIST_FIRST(&ip_fw_chain); fcp; fcp = LIST_NEXT(fcp, chain)) {
1002 fcp->rule->fw_bcnt = fcp->rule->fw_pcnt = 0;
1003 fcp->rule->timestamp = 0;
1004 }
1005 splx(s);
1006 }
1007 else {
1008 cleared = 0;
1009
1010 /*
1011 * It's possible to insert multiple chain entries with the
1012 * same number, so we don't stop after finding the first
1013 * match if zeroing a specific entry.
1014 */
1015 for (fcp = LIST_FIRST(&ip_fw_chain); fcp; fcp = LIST_NEXT(fcp, chain))
1016 if (frwl->fw_number == fcp->rule->fw_number) {
1017 s = splnet();
1018 while (fcp && frwl->fw_number == fcp->rule->fw_number) {
1019 fcp->rule->fw_bcnt = fcp->rule->fw_pcnt = 0;
1020 fcp->rule->timestamp = 0;
1021 fcp = LIST_NEXT(fcp, chain);
1022 }
1023 splx(s);
1024 cleared = 1;
1025 break;
1026 }
1027 if (!cleared) /* we didn't find any matching rules */
1028 return (EINVAL);
1029 }
1030
1031 if (fw_verbose) {
1032 if (frwl)
1033 printf("ipfw: Entry %d cleared.\n", frwl->fw_number);
1034 else
1035 printf("ipfw: Accounting cleared.\n");
1036 }
1037
1038 return (0);
1039 }
1040
1041 static int
1042 check_ipfw_struct(struct ip_fw *frwl)
1043 {
1044 /* Check for invalid flag bits */
1045 if ((frwl->fw_flg & ~IP_FW_F_MASK) != 0) {
1046 dprintf(("%s undefined flag bits set (flags=%x)\n",
1047 err_prefix, frwl->fw_flg));
1048 return (EINVAL);
1049 }
1050 /* Must apply to incoming or outgoing (or both) */
1051 if (!(frwl->fw_flg & (IP_FW_F_IN | IP_FW_F_OUT))) {
1052 dprintf(("%s neither in nor out\n", err_prefix));
1053 return (EINVAL);
1054 }
1055 /* Empty interface name is no good */
1056 if (((frwl->fw_flg & IP_FW_F_IIFNAME)
1057 && !*frwl->fw_in_if.fu_via_if.name)
1058 || ((frwl->fw_flg & IP_FW_F_OIFNAME)
1059 && !*frwl->fw_out_if.fu_via_if.name)) {
1060 dprintf(("%s empty interface name\n", err_prefix));
1061 return (EINVAL);
1062 }
1063 /* Sanity check interface matching */
1064 if ((frwl->fw_flg & IF_FW_F_VIAHACK) == IF_FW_F_VIAHACK) {
1065 ; /* allow "via" backwards compatibility */
1066 } else if ((frwl->fw_flg & IP_FW_F_IN)
1067 && (frwl->fw_flg & IP_FW_F_OIFACE)) {
1068 dprintf(("%s outgoing interface check on incoming\n",
1069 err_prefix));
1070 return (EINVAL);
1071 }
1072 /* Sanity check port ranges */
1073 if ((frwl->fw_flg & IP_FW_F_SRNG) && IP_FW_GETNSRCP(frwl) < 2) {
1074 dprintf(("%s src range set but n_src_p=%d\n",
1075 err_prefix, IP_FW_GETNSRCP(frwl)));
1076 return (EINVAL);
1077 }
1078 if ((frwl->fw_flg & IP_FW_F_DRNG) && IP_FW_GETNDSTP(frwl) < 2) {
1079 dprintf(("%s dst range set but n_dst_p=%d\n",
1080 err_prefix, IP_FW_GETNDSTP(frwl)));
1081 return (EINVAL);
1082 }
1083 if (IP_FW_GETNSRCP(frwl) + IP_FW_GETNDSTP(frwl) > IP_FW_MAX_PORTS) {
1084 dprintf(("%s too many ports (%d+%d)\n",
1085 err_prefix, IP_FW_GETNSRCP(frwl), IP_FW_GETNDSTP(frwl)));
1086 return (EINVAL);
1087 }
1088 /*
1089 * Protocols other than TCP/UDP don't use port range
1090 */
1091 if ((frwl->fw_prot != IPPROTO_TCP) &&
1092 (frwl->fw_prot != IPPROTO_UDP) &&
1093 (IP_FW_GETNSRCP(frwl) || IP_FW_GETNDSTP(frwl))) {
1094 dprintf(("%s port(s) specified for non TCP/UDP rule\n",
1095 err_prefix));
1096 return (EINVAL);
1097 }
1098
1099 /*
1100 * Rather than modify the entry to make such entries work,
1101 * we reject this rule and require user level utilities
1102 * to enforce whatever policy they deem appropriate.
1103 */
1104 if ((frwl->fw_src.s_addr & (~frwl->fw_smsk.s_addr)) ||
1105 (frwl->fw_dst.s_addr & (~frwl->fw_dmsk.s_addr))) {
1106 dprintf(("%s rule never matches\n", err_prefix));
1107 return (EINVAL);
1108 }
1109
1110 if ((frwl->fw_flg & IP_FW_F_FRAG) &&
1111 (frwl->fw_prot == IPPROTO_UDP || frwl->fw_prot == IPPROTO_TCP)) {
1112 if (frwl->fw_nports) {
1113 dprintf(("%s cannot mix 'frag' and ports\n", err_prefix));
1114 return (EINVAL);
1115 }
1116 if (frwl->fw_prot == IPPROTO_TCP &&
1117 frwl->fw_tcpf != frwl->fw_tcpnf) {
1118 dprintf(("%s cannot mix 'frag' and TCP flags\n", err_prefix));
1119 return (EINVAL);
1120 }
1121 }
1122
1123 /* Check command specific stuff */
1124 switch (frwl->fw_flg & IP_FW_F_COMMAND)
1125 {
1126 case IP_FW_F_REJECT:
1127 if (frwl->fw_reject_code >= 0x100
1128 && !(frwl->fw_prot == IPPROTO_TCP
1129 && frwl->fw_reject_code == IP_FW_REJECT_RST)) {
1130 dprintf(("%s unknown reject code\n", err_prefix));
1131 return (EINVAL);
1132 }
1133 break;
1134 case IP_FW_F_DIVERT: /* Diverting to port zero is invalid */
1135 case IP_FW_F_PIPE: /* piping through 0 is invalid */
1136 case IP_FW_F_TEE:
1137 if (frwl->fw_divert_port == 0) {
1138 dprintf(("%s can't divert to port 0\n", err_prefix));
1139 return (EINVAL);
1140 }
1141 break;
1142 case IP_FW_F_DENY:
1143 case IP_FW_F_ACCEPT:
1144 case IP_FW_F_COUNT:
1145 case IP_FW_F_SKIPTO:
1146 #if IPFIREWALL_FORWARD
1147 case IP_FW_F_FWD:
1148 #endif
1149 break;
1150 default:
1151 dprintf(("%s invalid command\n", err_prefix));
1152 return (EINVAL);
1153 }
1154
1155 return 0;
1156 }
1157
1158 static int
1159 ip_fw_ctl(struct sockopt *sopt)
1160 {
1161 int error, s;
1162 size_t size;
1163 char *buf, *bp;
1164 struct ip_fw_chain *fcp;
1165 struct ip_fw frwl;
1166
1167 /* Disallow sets in really-really secure mode. */
1168 if (sopt->sopt_dir == SOPT_SET && securelevel >= 3)
1169 return (EPERM);
1170 error = 0;
1171
1172 switch (sopt->sopt_name) {
1173 case IP_FW_GET:
1174 for (fcp = LIST_FIRST(&ip_fw_chain), size = 0; fcp;
1175 fcp = LIST_NEXT(fcp, chain))
1176 size += sizeof *fcp->rule;
1177 buf = _MALLOC(size, M_TEMP, M_WAITOK);
1178 if (buf == 0) {
1179 error = ENOBUFS;
1180 break;
1181 }
1182
1183 for (fcp = LIST_FIRST(&ip_fw_chain), bp = buf; fcp;
1184 fcp = LIST_NEXT(fcp, chain)) {
1185 bcopy(fcp->rule, bp, sizeof *fcp->rule);
1186 bp += sizeof *fcp->rule;
1187 }
1188 error = sooptcopyout(sopt, buf, size);
1189 FREE(buf, M_TEMP);
1190 break;
1191
1192 case IP_FW_FLUSH:
1193 for (fcp = ip_fw_chain.lh_first;
1194 fcp != 0 && fcp->rule->fw_number != IPFW_DEFAULT_RULE;
1195 fcp = ip_fw_chain.lh_first) {
1196 s = splnet();
1197 LIST_REMOVE(fcp, chain);
1198 FREE(fcp->rule, M_IPFW);
1199 FREE(fcp, M_IPFW);
1200 splx(s);
1201 }
1202 break;
1203
1204 case IP_FW_ZERO:
1205 if (sopt->sopt_val != 0) {
1206 error = sooptcopyin(sopt, &frwl, sizeof frwl,
1207 sizeof frwl);
1208 if (error || (error = zero_entry(&frwl)))
1209 break;
1210 } else {
1211 error = zero_entry(0);
1212 }
1213 break;
1214
1215 case IP_FW_ADD:
1216 error = sooptcopyin(sopt, &frwl, sizeof frwl, sizeof frwl);
1217 if (error || (error = check_ipfw_struct(&frwl)))
1218 break;
1219
1220 if (frwl.fw_number == IPFW_DEFAULT_RULE) {
1221 dprintf(("%s can't add rule %u\n", err_prefix,
1222 (unsigned)IPFW_DEFAULT_RULE));
1223 error = EINVAL;
1224 } else {
1225 error = add_entry(&ip_fw_chain, &frwl);
1226 }
1227 break;
1228
1229 case IP_FW_DEL:
1230 error = sooptcopyin(sopt, &frwl, sizeof frwl, sizeof frwl);
1231 if (error)
1232 break;
1233
1234 if (frwl.fw_number == IPFW_DEFAULT_RULE) {
1235 dprintf(("%s can't delete rule %u\n", err_prefix,
1236 (unsigned)IPFW_DEFAULT_RULE));
1237 error = EINVAL;
1238 } else {
1239 error = del_entry(&ip_fw_chain, frwl.fw_number);
1240 }
1241 break;
1242
1243 default:
1244 printf("ip_fw_ctl invalid option %d\n", sopt->sopt_name);
1245 error = EINVAL ;
1246 }
1247
1248 return (error);
1249 }
1250
1251 struct ip_fw_chain *ip_fw_default_rule ;
1252
1253 void
1254 ip_fw_init(void)
1255 {
1256 struct ip_fw default_rule;
1257
1258 ip_fw_chk_ptr = ip_fw_chk;
1259 ip_fw_ctl_ptr = ip_fw_ctl;
1260 LIST_INIT(&ip_fw_chain);
1261
1262 bzero(&default_rule, sizeof default_rule);
1263 default_rule.fw_prot = IPPROTO_IP;
1264 default_rule.fw_number = IPFW_DEFAULT_RULE;
1265 #if IPFIREWALL_DEFAULT_TO_ACCEPT
1266 default_rule.fw_flg |= IP_FW_F_ACCEPT;
1267 #else
1268 default_rule.fw_flg |= IP_FW_F_DENY;
1269 #endif
1270 default_rule.fw_flg |= IP_FW_F_IN | IP_FW_F_OUT;
1271 if (check_ipfw_struct(&default_rule) != 0 ||
1272 add_entry(&ip_fw_chain, &default_rule))
1273 panic("ip_fw_init");
1274
1275 ip_fw_default_rule = ip_fw_chain.lh_first ;
1276 printf("IP packet filtering initialized, "
1277 #if IPDIVERT
1278 "divert enabled, ");
1279 #else
1280 "divert disabled, ");
1281 #endif
1282 #if IPFIREWALL_FORWARD
1283 printf("rule-based forwarding enabled, ");
1284 #else
1285 printf("rule-based forwarding disabled, ");
1286 #endif
1287 #if IPFIREWALL_DEFAULT_TO_ACCEPT
1288 printf("default to accept, ");
1289 #endif
1290 #ifndef IPFIREWALL_VERBOSE
1291 printf("logging disabled\n");
1292 #else
1293 if (fw_verbose_limit == 0)
1294 printf("unlimited logging\n");
1295 else
1296 printf("logging limited to %d packets/entry\n",
1297 fw_verbose_limit);
1298 #endif
1299 }
1300
1301 #if ISFB31
1302
1303 /*
1304 * ### LD 08/04/99: This is used if IPFIREWALL is a FreeBSD "KLD" module
1305 * Right now, we're linked to the kernel all the time
1306 * will be fixed with the use of an NKE?
1307 *
1308 * Note: ip_fw_init is called from div_init() in xnu
1309 */
1310
1311 static ip_fw_chk_t *old_chk_ptr;
1312 static ip_fw_ctl_t *old_ctl_ptr;
1313
1314 #if defined(IPFIREWALL_MODULE) && !defined(KLD_MODULE)
1315
1316 #include <sys/exec.h>
1317 #include <sys/sysent.h>
1318 #include <sys/lkm.h>
1319
1320 MOD_MISC(ipfw);
1321
1322 static int
1323 ipfw_load(struct lkm_table *lkmtp, int cmd)
1324 {
1325 int s=splnet();
1326
1327 old_chk_ptr = ip_fw_chk_ptr;
1328 old_ctl_ptr = ip_fw_ctl_ptr;
1329
1330 ip_fw_init();
1331 splx(s);
1332 return 0;
1333 }
1334
1335 static int
1336 ipfw_unload(struct lkm_table *lkmtp, int cmd)
1337 {
1338 int s=splnet();
1339
1340 ip_fw_chk_ptr = old_chk_ptr;
1341 ip_fw_ctl_ptr = old_ctl_ptr;
1342
1343 while (LIST_FIRST(&ip_fw_chain) != NULL) {
1344 struct ip_fw_chain *fcp = LIST_FIRST(&ip_fw_chain);
1345 LIST_REMOVE(LIST_FIRST(&ip_fw_chain), chain);
1346 FREE(fcp->rule, M_IPFW);
1347 FREE(fcp, M_IPFW);
1348 }
1349
1350 splx(s);
1351 printf("IP firewall unloaded\n");
1352 return 0;
1353 }
1354
1355 int
1356 ipfw_mod(struct lkm_table *lkmtp, int cmd, int ver)
1357 {
1358 MOD_DISPATCH(ipfw, lkmtp, cmd, ver,
1359 ipfw_load, ipfw_unload, lkm_nullcmd);
1360 }
1361 #else
1362 static int
1363 ipfw_modevent(module_t mod, int type, void *unused)
1364 {
1365 int s;
1366
1367 switch (type) {
1368 case MOD_LOAD:
1369 s = splnet();
1370
1371 old_chk_ptr = ip_fw_chk_ptr;
1372 old_ctl_ptr = ip_fw_ctl_ptr;
1373
1374 ip_fw_init();
1375 splx(s);
1376 return 0;
1377 case MOD_UNLOAD:
1378 s = splnet();
1379
1380 ip_fw_chk_ptr = old_chk_ptr;
1381 ip_fw_ctl_ptr = old_ctl_ptr;
1382
1383 while (LIST_FIRST(&ip_fw_chain) != NULL) {
1384 struct ip_fw_chain *fcp = LIST_FIRST(&ip_fw_chain);
1385 LIST_REMOVE(LIST_FIRST(&ip_fw_chain), chain);
1386 FREE(fcp->rule, M_IPFW);
1387 FREE(fcp, M_IPFW);
1388 }
1389
1390 splx(s);
1391 printf("IP firewall unloaded\n");
1392 return 0;
1393 default:
1394 break;
1395 }
1396 return 0;
1397 }
1398
1399 static moduledata_t ipfwmod = {
1400 "ipfw",
1401 ipfw_modevent,
1402 0
1403 };
1404 DECLARE_MODULE(ipfw, ipfwmod, SI_SUB_PSEUDO, SI_ORDER_ANY);
1405 #endif
1406 #endif /* ISFB31 */
1407 #endif /* IPFIREWALL_KEXT */
1408