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