]>
git.saurik.com Git - apple/xnu.git/blob - bsd/netinet/ip_fw.c
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
23 * Copyright (c) 1993 Daniel Boulet
24 * Copyright (c) 1994 Ugen J.S.Antsilevich
25 * Copyright (c) 1996 Alex Nash
27 * Redistribution and use in source forms, with and without modification,
28 * are permitted provided that this entire comment appears intact.
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.
34 * This software is provided ``AS IS'' without any warranties of any kind.
39 * Implement IP packet firewall
43 #if !defined(KLD_MODULE) && !defined(IPFIREWALL_MODULE)
46 #include "opt_ipdivert.h"
51 #error IPFIREWALL requires INET.
54 #include <sys/param.h>
55 #include <sys/systm.h>
56 #include <sys/malloc.h>
58 #include <sys/kernel.h>
59 #include <sys/socket.h>
60 #include <sys/socketvar.h>
61 #include <sys/sysctl.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>
70 #include <net/route.h>
71 #include <netinet/ip_dummynet.h>
73 #include <netinet/tcp.h>
74 #include <netinet/tcp_timer.h>
75 #include <netinet/tcp_var.h>
77 #include <netinet/ip6.h>
79 #include <netinet/tcpip.h>
80 #include <netinet/udp.h>
81 #include <netinet/udp_var.h>
83 #include <netinet/if_ether.h> /* XXX ethertype_ip */
85 static int fw_debug
= 1;
86 #if IPFIREWALL_VERBOSE
87 static int fw_verbose
= 1;
89 static int fw_verbose
= 0;
91 static int fw_one_pass
= 0; /* XXX */
92 #if IPFIREWALL_VERBOSE_LIMIT
93 static int fw_verbose_limit
= IPFIREWALL_VERBOSE_LIMIT
;
95 static int fw_verbose_limit
= 0;
98 #define IPFW_DEFAULT_RULE ((u_int)(u_short)~0)
100 LIST_HEAD (ip_fw_head
, ip_fw_chain
) ip_fw_chain
;
102 MALLOC_DEFINE(M_IPFW
, "IpFw/IpAcct", "IpFw/IpAcct chain's");
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, "");
111 #define dprintf(a) if (!fw_debug); else printf a
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);
119 #define dprint_ip(a) if (!fw_debug); else print_ip(a)
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
));
126 iface_match
__P((struct ifnet
*ifp
, union ip_fw_if
*ifu
,
128 static int ipopts_match
__P((struct ip
*ip
, struct ip_fw
*f
));
130 port_match
__P((u_short
*portptr
, int nports
, u_short port
,
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
));
137 static void flush_rule_ptrs(void);
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
));
145 static char err_prefix
[] = "ip_fw_ctl:";
148 * Returns 1 if the port is matched by the vector, 0 otherwise
151 port_match(u_short
*portptr
, int nports
, u_short port
, int range_flag
)
156 if (portptr
[0] <= port
&& port
<= portptr
[1]) {
162 while (nports
-- > 0) {
163 if (*portptr
++ == port
) {
171 tcpflg_match(struct tcphdr
*tcp
, struct ip_fw
*f
)
173 u_char flg_set
, flg_clr
;
175 if ((f
->fw_tcpf
& IP_FW_TCPF_ESTAB
) &&
176 (tcp
->th_flags
& (IP_FW_TCPF_RST
| IP_FW_TCPF_ACK
)))
179 flg_set
= tcp
->th_flags
& f
->fw_tcpf
;
180 flg_clr
= tcp
->th_flags
& f
->fw_tcpnf
;
182 if (flg_set
!= f
->fw_tcpf
)
191 icmptype_match(struct icmp
*icmp
, struct ip_fw
*f
)
195 if (!(f
->fw_flg
& IP_FW_F_ICMPBIT
))
198 type
= icmp
->icmp_type
;
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))))))
206 return(0); /* no match */
210 is_icmp_query(struct ip
*ip
)
212 const struct icmp
*icmp
;
215 icmp
= (struct icmp
*)((u_int32_t
*)ip
+ ip
->ip_hl
);
216 icmp_type
= icmp
->icmp_type
;
218 if (icmp_type
== ICMP_ECHO
|| icmp_type
== ICMP_ROUTERSOLICIT
||
219 icmp_type
== ICMP_TSTAMP
|| icmp_type
== ICMP_IREQ
||
220 icmp_type
== ICMP_MASKREQ
)
227 ipopts_match(struct ip
*ip
, struct ip_fw
*f
)
230 int opt
, optlen
, cnt
;
231 u_char opts
, nopts
, nopts_sve
;
233 cp
= (u_char
*)(ip
+ 1);
234 cnt
= (ip
->ip_hl
<< 2) - sizeof (struct ip
);
236 nopts
= nopts_sve
= f
->fw_ipnopt
;
238 for (; cnt
> 0; cnt
-= optlen
, cp
+= optlen
) {
239 opt
= cp
[IPOPT_OPTVAL
];
240 if (opt
== IPOPT_EOL
)
242 if (opt
== IPOPT_NOP
)
245 optlen
= cp
[IPOPT_OLEN
];
246 if (optlen
<= 0 || optlen
> cnt
) {
256 opts
&= ~IP_FW_IPOPT_LSRR
;
257 nopts
&= ~IP_FW_IPOPT_LSRR
;
261 opts
&= ~IP_FW_IPOPT_SSRR
;
262 nopts
&= ~IP_FW_IPOPT_SSRR
;
266 opts
&= ~IP_FW_IPOPT_RR
;
267 nopts
&= ~IP_FW_IPOPT_RR
;
270 opts
&= ~IP_FW_IPOPT_TS
;
271 nopts
&= ~IP_FW_IPOPT_TS
;
277 if (opts
== 0 && nopts
== nopts_sve
)
284 iface_match(struct ifnet
*ifp
, union ip_fw_if
*ifu
, int byname
)
286 /* Check by name or by IP address */
288 /* Check unit number (-1 is wildcard) */
289 if (ifu
->fu_via_if
.unit
!= -1
290 && ifp
->if_unit
!= ifu
->fu_via_if
.unit
)
293 if (strncmp(ifp
->if_name
, ifu
->fu_via_if
.name
, FW_IFNLEN
))
296 } else if (ifu
->fu_via_ip
.s_addr
!= 0) { /* Zero == wildcard */
299 for (ia
= ifp
->if_addrhead
.tqh_first
;
300 ia
!= NULL
; ia
= ia
->ifa_link
.tqe_next
) {
301 if (ia
->ifa_addr
== NULL
)
303 if (ia
->ifa_addr
->sa_family
!= AF_INET
)
305 if (ifu
->fu_via_ip
.s_addr
!= ((struct sockaddr_in
*)
306 (ia
->ifa_addr
))->sin_addr
.s_addr
)
316 ipfw_report(struct ip_fw
*f
, struct ip
*ip
,
317 struct ifnet
*rif
, struct ifnet
*oif
)
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
);
326 count
= f
? f
->fw_pcnt
: ++counter
;
327 if (fw_verbose_limit
!= 0 && count
> fw_verbose_limit
)
330 /* Print command name */
331 printf("ipfw: %d ", f
? f
->fw_number
: -1);
335 switch (f
->fw_flg
& IP_FW_F_COMMAND
) {
340 if (f
->fw_reject_code
== IP_FW_REJECT_RST
)
352 printf("Divert %d", f
->fw_divert_port
);
355 printf("Tee %d", f
->fw_divert_port
);
358 printf("SkipTo %d", f
->fw_skipto_rule
);
362 printf("Pipe %d", f
->fw_skipto_rule
);
365 #if IPFIREWALL_FORWARD
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
);
382 print_ip(ip
->ip_src
);
383 if ((ip
->ip_off
& IP_OFFMASK
) == 0)
384 printf(":%d ", ntohs(tcp
->th_sport
));
387 print_ip(ip
->ip_dst
);
388 if ((ip
->ip_off
& IP_OFFMASK
) == 0)
389 printf(":%d", ntohs(tcp
->th_dport
));
393 print_ip(ip
->ip_src
);
394 if ((ip
->ip_off
& IP_OFFMASK
) == 0)
395 printf(":%d ", ntohs(udp
->uh_sport
));
398 print_ip(ip
->ip_dst
);
399 if ((ip
->ip_off
& IP_OFFMASK
) == 0)
400 printf(":%d", ntohs(udp
->uh_dport
));
403 if ((ip
->ip_off
& IP_OFFMASK
) == 0)
404 printf("ICMP:%u.%u ", icmp
->icmp_type
, icmp
->icmp_code
);
407 print_ip(ip
->ip_src
);
409 print_ip(ip
->ip_dst
);
412 printf("P:%d ", ip
->ip_p
);
413 print_ip(ip
->ip_src
);
415 print_ip(ip
->ip_dst
);
419 printf(" out via %s%d", oif
->if_name
, oif
->if_unit
);
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
);
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);
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
439 static struct ip_fw_chain
* lookup_next_rule(struct ip_fw_chain
*me
);
441 static struct ip_fw_chain
*
442 lookup_next_rule(struct ip_fw_chain
*me
)
444 struct ip_fw_chain
*chain
;
445 int rule
= me
->rule
->fw_skipto_rule
; /* guess... */
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
)
451 return me
->chain
.le_next
; /* failure or not a skipto */
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.
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).
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.
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
)
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
;
488 u_short src_port
, dst_port
;
489 u_int16_t skipto
= *cookie
;
491 if (pip
) { /* normal ip packet */
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
)) {
498 if ((*m
)->m_len
<sizeof(struct ether_header
) + sizeof(struct ip
))
500 ip
= (struct ip
*)(eh
+ 1 );
501 if (ip
->ip_v
!= IPVERSION
)
503 hlen
= ip
->ip_hl
<< 2;
504 if (hlen
< sizeof(struct ip
)) /* minimum header length */
506 if ((*m
)->m_len
< 14 + hlen
+ 14) {
507 printf("-- m_len %d, need more...\n", (*m
)->m_len
);
510 offset
= (ip
->ip_off
& IP_OFFMASK
);
520 return 0 ; /* accept if passed first test */
522 * pkt has already been tagged. Look for the next rule
523 * to restart processing
525 chain
= LIST_NEXT( *flow_id
, chain
);
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
;
533 * Go down the chain, looking for enlightment
534 * If we've been asked to start at a given rule immediatly, do so.
536 chain
= LIST_FIRST(&ip_fw_chain
);
538 if (skipto
>= IPFW_DEFAULT_RULE
)
540 while (chain
&& (chain
->rule
->fw_number
<= skipto
)) {
541 chain
= LIST_NEXT(chain
, chain
);
543 if (! chain
) goto dropit
;
547 for (; chain
; chain
= LIST_NEXT(chain
, chain
)) {
548 register struct ip_fw
* f
;
553 /* Check direction outbound */
554 if (!(f
->fw_flg
& IP_FW_F_OUT
))
557 /* Check direction inbound */
558 if (!(f
->fw_flg
& IP_FW_F_IN
))
563 * do relevant checks for non-ip packets:
564 * after this, only goto got_match or continue
566 struct ether_header
*eh
= mtod(*m
, struct ether_header
*);
569 * make default rule always match or we have a panic
571 if (f
->fw_number
== IPFW_DEFAULT_RULE
)
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
580 if ( f
->fw_src
.s_addr
!= 0 || f
->fw_prot
!= IPPROTO_UDP
581 || f
->fw_smsk
.s_addr
!= 0xffffffff )
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
) ) ) {
597 if ((f
->fw_flg
& IP_FW_F_FRAG
) && offset
== 0 )
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
))
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
))
610 /* Interface check */
611 if ((f
->fw_flg
& IF_FW_F_VIAHACK
) == IF_FW_F_VIAHACK
) {
612 struct ifnet
*const iface
= oif
? oif
: rif
;
614 /* Backwards compatibility hack for "via" */
615 if (!iface
|| !iface_match(iface
,
616 &f
->fw_in_if
, f
->fw_flg
& IP_FW_F_OIFNAME
))
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
)))
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
)))
631 /* Check IP options */
632 if (f
->fw_ipopt
!= f
->fw_ipnopt
&& !ipopts_match(ip
, f
))
635 /* Check protocol; if wildcard, match */
636 if (f
->fw_prot
== IPPROTO_IP
)
639 /* If different, don't match */
640 if (ip
->ip_p
!= f
->fw_prot
)
644 * here, pip==NULL for bridged pkts -- they include the ethernet
645 * header so i have to adjust lengths accordingly
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) \
652 ip = mtod(*m, struct ip *); \
656 ip = (struct ip *)((int)ip + 14); \
657 offset = (ip->ip_off & IP_OFFMASK); \
661 /* Protocol specific checks */
667 if (offset
== 1) /* cf. RFC 1858 */
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.
675 if (f
->fw_nports
!= 0 ||
676 f
->fw_tcpf
!= f
->fw_tcpnf
)
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
))
685 src_port
= ntohs(tcp
->th_sport
);
686 dst_port
= ntohs(tcp
->th_dport
);
696 * Port specification is unavailable -- if this
697 * rule specifies a port, we consider the rule
700 if (f
->fw_nports
!= 0)
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
);
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
))
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
))
725 if (offset
!= 0) /* Type isn't valid */
728 icmp
= (struct icmp
*) ((u_int32_t
*)ip
+ ip
->ip_hl
);
729 if (!icmptype_match(icmp
, f
))
737 ipfw_report(NULL
, ip
, rif
, oif
);
742 *flow_id
= chain
; /* XXX set flow id */
743 /* Update statistics */
746 f
->fw_bcnt
+= ip
->ip_len
;
748 f
->timestamp
= time_second
;
750 /* Log to console if desired */
751 if ((f
->fw_flg
& IP_FW_F_PRN
) && fw_verbose
)
752 ipfw_report(f
, ip
, rif
, oif
);
754 /* Take appropriate action */
755 switch (f
->fw_flg
& IP_FW_F_COMMAND
) {
762 *cookie
= f
->fw_number
;
763 return(f
->fw_divert_port
);
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.
775 case IP_FW_F_SKIPTO
: /* XXX check */
776 if ( f
->next_rule_ptr
)
777 chain
= f
->next_rule_ptr
;
779 chain
= lookup_next_rule(chain
) ;
780 if (! chain
) goto dropit
;
784 return(f
->fw_pipe_nr
| 0x10000 );
786 #if IPFIREWALL_FORWARD
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)
798 if (next_hop
!= NULL
) /* Make sure, first... */
799 *next_hop
= &(f
->fw_fwd_ip
);
800 return(0); /* Allow the packet */
804 /* Deny/reject this packet using this rule */
811 /* Rule IPFW_DEFAULT_RULE should always be there and should always match */
813 panic("ip_fw: chain");
817 * At this point, we're going to drop the packet.
818 * Send a reject notice if all of the following are true:
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
824 if ((rule
->fw_flg
& IP_FW_F_COMMAND
) == IP_FW_F_REJECT
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
:
832 struct tcphdr
*const tcp
=
833 (struct tcphdr
*) ((u_int32_t
*)ip
+ ip
->ip_hl
);
834 struct tcpiphdr ti
, *const tip
= (struct tcpiphdr
*) ip
;
836 if (offset
!= 0 || (tcp
->th_flags
& TH_RST
))
838 ti
.ti_i
= *((struct ipovly
*) ip
);
840 bcopy(&ti
, ip
, sizeof(ti
));
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);
848 if (tcp
->th_flags
& TH_SYN
)
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);
857 default: /* Send an ICMP unreachable using code */
858 icmp_error(*m
, ICMP_UNREACH
,
859 rule
->fw_reject_code
, 0L, 0);
867 * Finally, drop the packet.
869 /* *cookie = 0; */ /* XXX is this necessary ? */
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().
886 struct ip_fw_chain
*fcp
;
888 for (fcp
= ip_fw_chain
.lh_first
; fcp
; fcp
= fcp
->chain
.le_next
) {
889 fcp
->rule
->next_rule_ptr
= NULL
;
894 add_entry(struct ip_fw_head
*chainptr
, struct ip_fw
*frwl
)
896 struct ip_fw
*ftmp
= 0;
897 struct ip_fw_chain
*fwc
= 0, *fcp
, *fcpl
= 0;
901 fwc
= _MALLOC(sizeof *fwc
, M_IPFW
, M_NOWAIT
);
902 ftmp
= _MALLOC(sizeof *ftmp
, M_IPFW
, M_NOWAIT
);
904 dprintf(("%s MALLOC said no\n", err_prefix
));
905 if (fwc
) FREE(fwc
, M_IPFW
);
906 if (ftmp
) FREE(ftmp
, M_IPFW
);
910 bcopy(frwl
, ftmp
, sizeof(struct ip_fw
));
911 ftmp
->fw_in_if
.fu_via_if
.name
[FW_IFNLEN
- 1] = '\0';
914 ftmp
->next_rule_ptr
= NULL
;
915 ftmp
->pipe_ptr
= NULL
;
920 if (chainptr
->lh_first
== 0) {
921 LIST_INSERT_HEAD(chainptr
, fwc
, chain
);
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
;
934 if (nbr
< IPFW_DEFAULT_RULE
- 100)
936 ftmp
->fw_number
= nbr
;
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
) {
943 LIST_INSERT_AFTER(fcpl
, fwc
, chain
);
945 LIST_INSERT_HEAD(chainptr
, fwc
, chain
);
959 del_entry(struct ip_fw_head
*chainptr
, u_short number
)
961 struct ip_fw_chain
*fcp
;
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
) {
969 /* prevent access to rules while removing them */
971 while (fcp
&& fcp
->rule
->fw_number
== number
) {
972 struct ip_fw_chain
*next
;
974 next
= LIST_NEXT(fcp
, chain
);
975 LIST_REMOVE(fcp
, chain
);
977 dn_rule_delete(fcp
) ;
980 FREE(fcp
->rule
, M_IPFW
);
994 zero_entry(struct ip_fw
*frwl
)
996 struct ip_fw_chain
*fcp
;
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;
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.
1015 for (fcp
= LIST_FIRST(&ip_fw_chain
); fcp
; fcp
= LIST_NEXT(fcp
, chain
))
1016 if (frwl
->fw_number
== fcp
->rule
->fw_number
) {
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
);
1027 if (!cleared
) /* we didn't find any matching rules */
1033 printf("ipfw: Entry %d cleared.\n", frwl
->fw_number
);
1035 printf("ipfw: Accounting cleared.\n");
1042 check_ipfw_struct(struct ip_fw
*frwl
)
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
));
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
));
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
));
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",
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
)));
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
)));
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
)));
1089 * Protocols other than TCP/UDP don't use port range
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",
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.
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
));
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
));
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
));
1123 /* Check command specific stuff */
1124 switch (frwl
->fw_flg
& IP_FW_F_COMMAND
)
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
));
1134 case IP_FW_F_DIVERT
: /* Diverting to port zero is invalid */
1135 case IP_FW_F_PIPE
: /* piping through 0 is invalid */
1137 if (frwl
->fw_divert_port
== 0) {
1138 dprintf(("%s can't divert to port 0\n", err_prefix
));
1143 case IP_FW_F_ACCEPT
:
1145 case IP_FW_F_SKIPTO
:
1146 #if IPFIREWALL_FORWARD
1151 dprintf(("%s invalid command\n", err_prefix
));
1159 ip_fw_ctl(struct sockopt
*sopt
)
1164 struct ip_fw_chain
*fcp
;
1167 /* Disallow sets in really-really secure mode. */
1168 if (sopt
->sopt_dir
== SOPT_SET
&& securelevel
>= 3)
1172 switch (sopt
->sopt_name
) {
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
);
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
;
1188 error
= sooptcopyout(sopt
, buf
, size
);
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
) {
1197 LIST_REMOVE(fcp
, chain
);
1198 FREE(fcp
->rule
, M_IPFW
);
1205 if (sopt
->sopt_val
!= 0) {
1206 error
= sooptcopyin(sopt
, &frwl
, sizeof frwl
,
1208 if (error
|| (error
= zero_entry(&frwl
)))
1211 error
= zero_entry(0);
1216 error
= sooptcopyin(sopt
, &frwl
, sizeof frwl
, sizeof frwl
);
1217 if (error
|| (error
= check_ipfw_struct(&frwl
)))
1220 if (frwl
.fw_number
== IPFW_DEFAULT_RULE
) {
1221 dprintf(("%s can't add rule %u\n", err_prefix
,
1222 (unsigned)IPFW_DEFAULT_RULE
));
1225 error
= add_entry(&ip_fw_chain
, &frwl
);
1230 error
= sooptcopyin(sopt
, &frwl
, sizeof frwl
, sizeof frwl
);
1234 if (frwl
.fw_number
== IPFW_DEFAULT_RULE
) {
1235 dprintf(("%s can't delete rule %u\n", err_prefix
,
1236 (unsigned)IPFW_DEFAULT_RULE
));
1239 error
= del_entry(&ip_fw_chain
, frwl
.fw_number
);
1244 printf("ip_fw_ctl invalid option %d\n", sopt
->sopt_name
);
1251 struct ip_fw_chain
*ip_fw_default_rule
;
1256 struct ip_fw default_rule
;
1258 ip_fw_chk_ptr
= ip_fw_chk
;
1259 ip_fw_ctl_ptr
= ip_fw_ctl
;
1260 LIST_INIT(&ip_fw_chain
);
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
;
1268 default_rule
.fw_flg
|= IP_FW_F_DENY
;
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");
1275 ip_fw_default_rule
= ip_fw_chain
.lh_first
;
1276 printf("IP packet filtering initialized, "
1278 "divert enabled, ");
1280 "divert disabled, ");
1282 #if IPFIREWALL_FORWARD
1283 printf("rule-based forwarding enabled, ");
1285 printf("rule-based forwarding disabled, ");
1287 #if IPFIREWALL_DEFAULT_TO_ACCEPT
1288 printf("default to accept, ");
1290 #ifndef IPFIREWALL_VERBOSE
1291 printf("logging disabled\n");
1293 if (fw_verbose_limit
== 0)
1294 printf("unlimited logging\n");
1296 printf("logging limited to %d packets/entry\n",
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?
1308 * Note: ip_fw_init is called from div_init() in xnu
1311 static ip_fw_chk_t
*old_chk_ptr
;
1312 static ip_fw_ctl_t
*old_ctl_ptr
;
1314 #if defined(IPFIREWALL_MODULE) && !defined(KLD_MODULE)
1316 #include <sys/exec.h>
1317 #include <sys/sysent.h>
1318 #include <sys/lkm.h>
1323 ipfw_load(struct lkm_table
*lkmtp
, int cmd
)
1327 old_chk_ptr
= ip_fw_chk_ptr
;
1328 old_ctl_ptr
= ip_fw_ctl_ptr
;
1336 ipfw_unload(struct lkm_table
*lkmtp
, int cmd
)
1340 ip_fw_chk_ptr
= old_chk_ptr
;
1341 ip_fw_ctl_ptr
= old_ctl_ptr
;
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
);
1351 printf("IP firewall unloaded\n");
1356 ipfw_mod(struct lkm_table
*lkmtp
, int cmd
, int ver
)
1358 MOD_DISPATCH(ipfw
, lkmtp
, cmd
, ver
,
1359 ipfw_load
, ipfw_unload
, lkm_nullcmd
);
1363 ipfw_modevent(module_t mod
, int type
, void *unused
)
1371 old_chk_ptr
= ip_fw_chk_ptr
;
1372 old_ctl_ptr
= ip_fw_ctl_ptr
;
1380 ip_fw_chk_ptr
= old_chk_ptr
;
1381 ip_fw_ctl_ptr
= old_ctl_ptr
;
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
);
1391 printf("IP firewall unloaded\n");
1399 static moduledata_t ipfwmod
= {
1404 DECLARE_MODULE(ipfw
, ipfwmod
, SI_SUB_PSEUDO
, SI_ORDER_ANY
);
1407 #endif /* IPFIREWALL_KEXT */