2 * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 * Copyright (c) 2002-2003 Luigi Rizzo
27 * Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp
28 * Copyright (c) 1994 Ugen J.S.Antsilevich
30 * Idea and grammar partially left from:
31 * Copyright (c) 1993 Daniel Boulet
33 * Redistribution and use in source forms, with and without modification,
34 * are permitted provided that this entire comment appears intact.
36 * Redistribution in binary form may occur without any restrictions.
37 * Obviously, it would be nice if you gave credit where credit is due
38 * but requiring it would be too onerous.
40 * This software is provided ``AS IS'' without any warranties of any kind.
42 * NEW command line interface for IP firewall facility
44 * $FreeBSD: /repoman/r/ncvs/src/sbin/ipfw/ipfw2.c,v 1.4.2.18 2003/09/15 10:27:03 luigi Exp $
47 #include <sys/param.h>
49 #include <sys/socket.h>
50 #include <sys/sockio.h>
51 #include <sys/sysctl.h>
71 #include <netinet/in.h>
72 #include <netinet/in_systm.h>
73 #include <netinet/ip.h>
74 #include <netinet/ip_icmp.h>
76 #include <netinet/ip_fw.h>
78 #include <net/route.h> /* def. of struct route */
79 #include <netinet/ip_dummynet.h>
80 #include <netinet/tcp.h>
81 #include <arpa/inet.h>
84 do_resolv
, /* Would try to resolve all */
85 do_time
, /* Show time stamps */
86 do_quiet
, /* Be quiet in add and flush */
87 do_pipe
, /* this cmd refers to a pipe */
88 do_sort
, /* field to sort results (0 = no) */
89 do_dynamic
, /* display dynamic rules */
90 do_expired
, /* display expired dynamic rules */
91 do_compact
, /* show rules in compact mode */
92 show_sets
, /* display rule sets */
93 test_only
, /* only check syntax */
96 #define IP_MASK_ALL 0xffffffff
99 * _s_x is a structure that stores a string <-> token pairs, used in
100 * various places in the parser. Entries are stored in arrays,
101 * with an entry with s=NULL as terminator.
102 * The search routines are match_token() and match_value().
103 * Often, an element with x=0 contains an error string.
111 static struct _s_x f_tcpflags
[] = {
122 static struct _s_x f_tcpopts
[] = {
123 { "mss", IP_FW_TCPOPT_MSS
},
124 { "maxseg", IP_FW_TCPOPT_MSS
},
125 { "window", IP_FW_TCPOPT_WINDOW
},
126 { "sack", IP_FW_TCPOPT_SACK
},
127 { "ts", IP_FW_TCPOPT_TS
},
128 { "timestamp", IP_FW_TCPOPT_TS
},
129 { "cc", IP_FW_TCPOPT_CC
},
135 * IP options span the range 0 to 255 so we need to remap them
136 * (though in fact only the low 5 bits are significant).
138 static struct _s_x f_ipopts
[] = {
139 { "ssrr", IP_FW_IPOPT_SSRR
},
140 { "lsrr", IP_FW_IPOPT_LSRR
},
141 { "rr", IP_FW_IPOPT_RR
},
142 { "ts", IP_FW_IPOPT_TS
},
147 static struct _s_x f_iptos
[] = {
148 { "lowdelay", IPTOS_LOWDELAY
},
149 { "throughput", IPTOS_THROUGHPUT
},
150 { "reliability", IPTOS_RELIABILITY
},
151 { "mincost", IPTOS_MINCOST
},
152 { "congestion", IPTOS_CE
},
153 { "ecntransport", IPTOS_ECT
},
154 { "ip tos option", 0},
158 static struct _s_x limit_masks
[] = {
159 {"all", DYN_SRC_ADDR
|DYN_SRC_PORT
|DYN_DST_ADDR
|DYN_DST_PORT
},
160 {"src-addr", DYN_SRC_ADDR
},
161 {"src-port", DYN_SRC_PORT
},
162 {"dst-addr", DYN_DST_ADDR
},
163 {"dst-port", DYN_DST_PORT
},
168 * we use IPPROTO_ETHERTYPE as a fake protocol id to call the print routines
169 * This is only used in this code.
171 #define IPPROTO_ETHERTYPE 0x1000
172 static struct _s_x ether_types
[] = {
174 * Note, we cannot use "-:&/" in the names because they are field
175 * separators in the type specifications. Also, we use s = NULL as
176 * end-delimiter, because a type of 0 can be legal.
189 { "pppoe_disc", 0x8863 },
190 { "pppoe_sess", 0x8864 },
191 { "ipx_8022", 0x00E0 },
192 { "ipx_8023", 0x0000 },
193 { "ipx_ii", 0x8137 },
194 { "ipx_snap", 0x8137 },
200 static void show_usage(void);
274 struct _s_x dummynet_params
[] = {
276 { "noerror", TOK_NOERROR
},
277 { "buckets", TOK_BUCKETS
},
278 { "dst-ip", TOK_DSTIP
},
279 { "src-ip", TOK_SRCIP
},
280 { "dst-port", TOK_DSTPORT
},
281 { "src-port", TOK_SRCPORT
},
282 { "proto", TOK_PROTO
},
283 { "weight", TOK_WEIGHT
},
285 { "mask", TOK_MASK
},
286 { "droptail", TOK_DROPTAIL
},
288 { "gred", TOK_GRED
},
290 { "bandwidth", TOK_BW
},
291 { "delay", TOK_DELAY
},
292 { "pipe", TOK_PIPE
},
293 { "queue", TOK_QUEUE
},
294 { "dummynet-params", TOK_NULL
},
295 { NULL
, 0 } /* terminator */
298 struct _s_x rule_actions
[] = {
299 { "accept", TOK_ACCEPT
},
300 { "pass", TOK_ACCEPT
},
301 { "allow", TOK_ACCEPT
},
302 { "permit", TOK_ACCEPT
},
303 { "count", TOK_COUNT
},
304 { "pipe", TOK_PIPE
},
305 { "queue", TOK_QUEUE
},
306 { "divert", TOK_DIVERT
},
308 { "fwd", TOK_FORWARD
},
309 { "forward", TOK_FORWARD
},
310 { "skipto", TOK_SKIPTO
},
311 { "deny", TOK_DENY
},
312 { "drop", TOK_DENY
},
313 { "reject", TOK_REJECT
},
314 { "reset", TOK_RESET
},
315 { "unreach", TOK_UNREACH
},
316 { "check-state", TOK_CHECKSTATE
},
317 { "//", TOK_COMMENT
},
318 { NULL
, 0 } /* terminator */
321 struct _s_x rule_options
[] = {
325 { "limit", TOK_LIMIT
},
326 { "keep-state", TOK_KEEPSTATE
},
327 { "bridged", TOK_LAYER2
},
328 { "layer2", TOK_LAYER2
},
330 { "xmit", TOK_XMIT
},
331 { "recv", TOK_RECV
},
333 { "fragment", TOK_FRAG
},
334 { "frag", TOK_FRAG
},
335 { "ipoptions", TOK_IPOPTS
},
336 { "ipopts", TOK_IPOPTS
},
337 { "iplen", TOK_IPLEN
},
338 { "ipid", TOK_IPID
},
339 { "ipprecedence", TOK_IPPRECEDENCE
},
340 { "iptos", TOK_IPTOS
},
341 { "ipttl", TOK_IPTTL
},
342 { "ipversion", TOK_IPVER
},
343 { "ipver", TOK_IPVER
},
344 { "estab", TOK_ESTAB
},
345 { "established", TOK_ESTAB
},
346 { "setup", TOK_SETUP
},
347 { "tcpflags", TOK_TCPFLAGS
},
348 { "tcpflgs", TOK_TCPFLAGS
},
349 { "tcpoptions", TOK_TCPOPTS
},
350 { "tcpopts", TOK_TCPOPTS
},
351 { "tcpseq", TOK_TCPSEQ
},
352 { "tcpack", TOK_TCPACK
},
353 { "tcpwin", TOK_TCPWIN
},
354 { "icmptype", TOK_ICMPTYPES
},
355 { "icmptypes", TOK_ICMPTYPES
},
356 { "dst-ip", TOK_DSTIP
},
357 { "src-ip", TOK_SRCIP
},
358 { "dst-port", TOK_DSTPORT
},
359 { "src-port", TOK_SRCPORT
},
360 { "proto", TOK_PROTO
},
363 { "mac-type", TOK_MACTYPE
},
364 { "verrevpath", TOK_VERREVPATH
},
365 { "ipsec", TOK_IPSEC
},
366 { "//", TOK_COMMENT
},
368 { "not", TOK_NOT
}, /* pseudo option */
369 { "!", /* escape ? */ TOK_NOT
}, /* pseudo option */
370 { "or", TOK_OR
}, /* pseudo option */
371 { "|", /* escape */ TOK_OR
}, /* pseudo option */
372 { "{", TOK_STARTBRACE
}, /* pseudo option */
373 { "(", TOK_STARTBRACE
}, /* pseudo option */
374 { "}", TOK_ENDBRACE
}, /* pseudo option */
375 { ")", TOK_ENDBRACE
}, /* pseudo option */
376 { NULL
, 0 } /* terminator */
379 static __inline
uint64_t
380 align_uint64(uint64_t *pll
) {
383 bcopy (pll
, &ret
, sizeof(ret
));
388 * conditionally runs the command.
391 do_cmd(int optname
, void *optval
, uintptr_t optlen
)
393 static int s
= -1; /* the socket */
400 s
= socket(AF_INET
, SOCK_RAW
, IPPROTO_RAW
);
402 err(EX_UNAVAILABLE
, "socket");
411 ((struct ip_fw
*)optval
)->version
= IP_FW_CURRENT_API_VERSION
;
416 if (optname
== IP_FW_GET
|| optname
== IP_DUMMYNET_GET
||
417 optname
== IP_FW_ADD
)
418 i
= getsockopt(s
, IPPROTO_IP
, optname
, optval
,
419 (socklen_t
*)optlen
);
421 i
= setsockopt(s
, IPPROTO_IP
, optname
, optval
, optlen
);
426 * match_token takes a table and a string, returns the value associated
427 * with the string (-1 in case of failure).
430 match_token(struct _s_x
*table
, char *string
)
433 uint i
= strlen(string
);
435 for (pt
= table
; i
&& pt
->s
!= NULL
; pt
++)
436 if (strlen(pt
->s
) == i
&& !bcmp(string
, pt
->s
, i
))
442 * match_value takes a table and a value, returns the string associated
443 * with the value (NULL in case of failure).
446 match_value(struct _s_x
*p
, int value
)
448 for (; p
->s
!= NULL
; p
++)
455 * prints one port, symbolic or numeric
458 print_port(int proto
, uint16_t port
)
461 if (proto
== IPPROTO_ETHERTYPE
) {
464 if (do_resolv
&& (s
= match_value(ether_types
, port
)) )
467 printf("0x%04x", port
);
469 struct servent
*se
= NULL
;
471 struct protoent
*pe
= getprotobynumber(proto
);
473 se
= getservbyport(htons(port
), pe
? pe
->p_name
: NULL
);
476 printf("%s", se
->s_name
);
482 struct _s_x _port_name
[] = {
483 {"dst-port", O_IP_DSTPORT
},
484 {"src-port", O_IP_SRCPORT
},
488 {"mac-type", O_MAC_TYPE
},
493 * Print the values in a list 16-bit items of the types above.
494 * XXX todo: add support for mask.
497 print_newports(ipfw_insn_u16
*cmd
, int proto
, int opcode
)
499 uint16_t *p
= cmd
->ports
;
503 if (cmd
->o
.len
& F_NOT
)
506 sep
= match_value(_port_name
, opcode
);
512 for (i
= F_LEN((ipfw_insn
*)cmd
) - 1; i
> 0; i
--, p
+= 2) {
514 print_port(proto
, p
[0]);
517 print_port(proto
, p
[1]);
524 * Like strtol, but also translates service names into port numbers
525 * for some protocols.
527 * proto == -1 disables the protocol check;
528 * proto == IPPROTO_ETHERTYPE looks up an internal table
529 * proto == <some value in /etc/protocols> matches the values there.
530 * Returns *end == s in case the parameter is not found.
533 strtoport(char *s
, char **end
, int base
, int proto
)
539 *end
= s
; /* default - not found */
541 return 0; /* not found */
544 return strtol(s
, end
, base
);
547 * find separator. '\\' escapes the next char.
549 for (s1
= s
; *s1
&& (isalnum(*s1
) || *s1
== '\\') ; s1
++)
550 if (*s1
== '\\' && s1
[1] != '\0')
553 buf
= malloc(s1
- s
+ 1);
558 * copy into a buffer skipping backslashes
560 for (p
= s
, i
= 0; p
!= s1
; p
++)
565 if (proto
== IPPROTO_ETHERTYPE
) {
566 i
= match_token(ether_types
, buf
);
568 if (i
!= -1) { /* found */
573 struct protoent
*pe
= NULL
;
577 pe
= getprotobynumber(proto
);
579 se
= getservbyname(buf
, pe
? pe
->p_name
: NULL
);
583 return ntohs(se
->s_port
);
586 return 0; /* not found */
590 * Fill the body of the command with the list of port ranges.
593 fill_newports(ipfw_insn_u16
*cmd
, char *av
, int proto
)
595 uint16_t a
, b
, *p
= cmd
->ports
;
600 a
= strtoport(av
, &s
, 0, proto
);
601 if (s
== av
) /* no parameter */
603 if (*s
== '-') { /* a range */
605 b
= strtoport(av
, &s
, 0, proto
);
606 if (s
== av
) /* no parameter */
610 } else if (*s
== ',' || *s
== '\0' )
612 else /* invalid separator */
613 errx(EX_DATAERR
, "invalid separator <%c> in <%s>\n",
620 if (i
+1 > F_LEN_MASK
)
621 errx(EX_DATAERR
, "too many ports/ranges\n");
622 cmd
->o
.len
|= i
+1; /* leave F_NOT and F_OR untouched */
627 static struct _s_x icmpcodes
[] = {
628 { "net", ICMP_UNREACH_NET
},
629 { "host", ICMP_UNREACH_HOST
},
630 { "protocol", ICMP_UNREACH_PROTOCOL
},
631 { "port", ICMP_UNREACH_PORT
},
632 { "needfrag", ICMP_UNREACH_NEEDFRAG
},
633 { "srcfail", ICMP_UNREACH_SRCFAIL
},
634 { "net-unknown", ICMP_UNREACH_NET_UNKNOWN
},
635 { "host-unknown", ICMP_UNREACH_HOST_UNKNOWN
},
636 { "isolated", ICMP_UNREACH_ISOLATED
},
637 { "net-prohib", ICMP_UNREACH_NET_PROHIB
},
638 { "host-prohib", ICMP_UNREACH_HOST_PROHIB
},
639 { "tosnet", ICMP_UNREACH_TOSNET
},
640 { "toshost", ICMP_UNREACH_TOSHOST
},
641 { "filter-prohib", ICMP_UNREACH_FILTER_PROHIB
},
642 { "host-precedence", ICMP_UNREACH_HOST_PRECEDENCE
},
643 { "precedence-cutoff", ICMP_UNREACH_PRECEDENCE_CUTOFF
},
648 fill_reject_code(u_short
*codep
, char *str
)
653 val
= strtoul(str
, &s
, 0);
654 if (s
== str
|| *s
!= '\0' || val
>= 0x100)
655 val
= match_token(icmpcodes
, str
);
657 errx(EX_DATAERR
, "unknown ICMP unreachable code ``%s''", str
);
663 print_reject_code(uint16_t code
)
665 char const *s
= match_value(icmpcodes
, code
);
668 printf("unreach %s", s
);
670 printf("unreach %u", code
);
674 * Returns the number of bits set (from left) in a contiguous bitmask,
675 * or -1 if the mask is not contiguous.
676 * XXX this needs a proper fix.
677 * This effectively works on masks in big-endian (network) format.
678 * when compiled on little endian architectures.
680 * First bit is bit 7 of the first byte -- note, for MAC addresses,
681 * the first bit on the wire is bit 0 of the first byte.
682 * len is the max length in bits.
685 contigmask(uint8_t *p
, int len
)
689 for (i
=0; i
<len
; i
++)
690 if ( (p
[i
/8] & (1 << (7 - (i%8
)))) == 0) /* first bit unset */
692 for (n
=i
+1; n
< len
; n
++)
693 if ( (p
[n
/8] & (1 << (7 - (n%8
)))) != 0)
694 return -1; /* mask not contiguous */
699 * print flags set/clear in the two bitmasks passed as parameters.
700 * There is a specialized check for f_tcpflags.
703 print_flags(char const *name
, ipfw_insn
*cmd
, struct _s_x
*list
)
705 char const *comma
= "";
707 uint8_t set
= cmd
->arg1
& 0xff;
708 uint8_t clear
= (cmd
->arg1
>> 8) & 0xff;
710 if (list
== f_tcpflags
&& set
== TH_SYN
&& clear
== TH_ACK
) {
715 printf(" %s ", name
);
716 for (i
=0; list
[i
].x
!= 0; i
++) {
717 if (set
& list
[i
].x
) {
719 printf("%s%s", comma
, list
[i
].s
);
722 if (clear
& list
[i
].x
) {
724 printf("%s!%s", comma
, list
[i
].s
);
731 * Print the ip address contained in a command.
734 print_ip(ipfw_insn_ip
*cmd
, char const *s
)
736 struct hostent
*he
= NULL
;
737 int len
= F_LEN((ipfw_insn
*)cmd
);
738 uint32_t *a
= ((ipfw_insn_u32
*)cmd
)->d
;
740 printf("%s%s ", cmd
->o
.len
& F_NOT
? " not": "", s
);
742 if (cmd
->o
.opcode
== O_IP_SRC_ME
|| cmd
->o
.opcode
== O_IP_DST_ME
) {
746 if (cmd
->o
.opcode
== O_IP_SRC_SET
|| cmd
->o
.opcode
== O_IP_DST_SET
) {
747 uint32_t x
, *map
= (uint32_t *)&(cmd
->mask
);
753 cmd
->addr
.s_addr
= htonl(cmd
->addr
.s_addr
);
754 printf("%s/%d", inet_ntoa(cmd
->addr
),
755 contigmask((uint8_t *)&x
, 32));
756 x
= cmd
->addr
.s_addr
= htonl(cmd
->addr
.s_addr
);
757 x
&= 0xff; /* base */
759 * Print bits and ranges.
760 * Locate first bit set (i), then locate first bit unset (j).
761 * If we have 3+ consecutive bits set, then print them as a
762 * range, otherwise only print the initial bit and rescan.
764 for (i
=0; i
< cmd
->o
.arg1
; i
++)
765 if (map
[i
/32] & (1<<(i
& 31))) {
766 for (j
=i
+1; j
< cmd
->o
.arg1
; j
++)
767 if (!(map
[ j
/32] & (1<<(j
& 31))))
769 printf("%c%d", comma
, i
+x
);
770 if (j
>i
+2) { /* range has at least 3 elements */
771 printf("-%d", j
-1+x
);
780 * len == 2 indicates a single IP, whereas lists of 1 or more
781 * addr/mask pairs have len = (2n+1). We convert len to n so we
782 * use that to count the number of entries.
784 for (len
= len
/ 2; len
> 0; len
--, a
+= 2) {
785 int mb
= /* mask length */
786 (cmd
->o
.opcode
== O_IP_SRC
|| cmd
->o
.opcode
== O_IP_DST
) ?
787 32 : contigmask((uint8_t *)&(a
[1]), 32);
788 if (mb
== 32 && do_resolv
)
789 he
= gethostbyaddr((char *)&(a
[0]), sizeof(u_long
), AF_INET
);
790 if (he
!= NULL
) /* resolved to name */
791 printf("%s", he
->h_name
);
792 else if (mb
== 0) /* any */
794 else { /* numeric IP followed by some kind of mask */
795 printf("%s", inet_ntoa( *((struct in_addr
*)&a
[0]) ) );
797 printf(":%s", inet_ntoa( *((struct in_addr
*)&a
[1]) ) );
807 * prints a MAC address/mask pair
810 print_mac(uint8_t *addr
, uint8_t *mask
)
812 int l
= contigmask(mask
, 48);
817 printf(" %02x:%02x:%02x:%02x:%02x:%02x",
818 addr
[0], addr
[1], addr
[2], addr
[3], addr
[4], addr
[5]);
820 printf("&%02x:%02x:%02x:%02x:%02x:%02x",
821 mask
[0], mask
[1], mask
[2],
822 mask
[3], mask
[4], mask
[5]);
829 fill_icmptypes(ipfw_insn_u32
*cmd
, char *av
)
838 type
= strtoul(av
, &av
, 0);
840 if (*av
!= ',' && *av
!= '\0')
841 errx(EX_DATAERR
, "invalid ICMP type");
844 errx(EX_DATAERR
, "ICMP type out of range");
846 cmd
->d
[0] |= 1 << type
;
848 cmd
->o
.opcode
= O_ICMPTYPE
;
849 cmd
->o
.len
|= F_INSN_SIZE(ipfw_insn_u32
);
853 print_icmptypes(ipfw_insn_u32
*cmd
)
858 printf(" icmptypes");
859 for (i
= 0; i
< 32; i
++) {
860 if ( (cmd
->d
[0] & (1 << (i
))) == 0)
862 printf("%c%d", sep
, i
);
868 * show_ipfw() prints the body of an ipfw rule.
869 * Because the standard rule has at least proto src_ip dst_ip, we use
870 * a helper function to produce these entries if not provided explicitly.
871 * The first argument is the list of fields we have, the second is
872 * the list of fields we want to be printed.
874 * Special cases if we have provided a MAC header:
875 * + if the rule does not contain IP addresses/ports, do not print them;
876 * + if the rule does not contain an IP proto, print "all" instead of "ip";
878 * Once we have 'have_options', IP header fields are printed as options.
880 #define HAVE_PROTO 0x0001
881 #define HAVE_SRCIP 0x0002
882 #define HAVE_DSTIP 0x0004
883 #define HAVE_MAC 0x0008
884 #define HAVE_MACTYPE 0x0010
885 #define HAVE_OPTIONS 0x8000
887 #define HAVE_IP (HAVE_PROTO | HAVE_SRCIP | HAVE_DSTIP)
889 show_prerequisites(int *flags
, int want
, int cmd
)
891 if ( (*flags
& HAVE_IP
) == HAVE_IP
)
892 *flags
|= HAVE_OPTIONS
;
894 if ( (*flags
& (HAVE_MAC
|HAVE_MACTYPE
|HAVE_OPTIONS
)) == HAVE_MAC
&&
897 * mac-type was optimized out by the compiler,
901 *flags
|= HAVE_MACTYPE
| HAVE_OPTIONS
;
904 if ( !(*flags
& HAVE_OPTIONS
)) {
905 if ( !(*flags
& HAVE_PROTO
) && (want
& HAVE_PROTO
))
907 if ( !(*flags
& HAVE_SRCIP
) && (want
& HAVE_SRCIP
))
909 if ( !(*flags
& HAVE_DSTIP
) && (want
& HAVE_DSTIP
))
916 show_ipfw(struct ip_fw
*rule
, int pcwidth
, int bcwidth
)
918 static int twidth
= 0;
921 char *comment
= NULL
; /* ptr to comment if we have one */
922 int proto
= 0; /* default */
923 int flags
= 0; /* prerequisites */
924 ipfw_insn_log
*logptr
= NULL
; /* set if we find an O_LOG */
925 int or_block
= 0; /* we are in an or block */
926 uint32_t set_disable
;
928 bcopy(&rule
->next_rule
, &set_disable
, sizeof(set_disable
));
930 if (set_disable
& (1 << rule
->set
)) { /* disabled */
934 printf("# DISABLED ");
936 printf("%05u ", rule
->rulenum
);
938 if (pcwidth
>0 || bcwidth
>0)
939 printf("%*llu %*llu ", pcwidth
, align_uint64(&rule
->pcnt
),
940 bcwidth
, align_uint64(&rule
->bcnt
));
943 printf("%10u ", rule
->timestamp
);
944 else if (do_time
== 1) {
946 time_t t
= (time_t)0;
949 strcpy(timestr
, ctime(&t
));
950 *strchr(timestr
, '\n') = '\0';
951 twidth
= strlen(timestr
);
953 if (rule
->timestamp
) {
954 #if _FreeBSD_version < 500000 /* XXX check */
955 #define _long_to_time(x) (time_t)(x)
957 t
= _long_to_time(rule
->timestamp
);
959 strcpy(timestr
, ctime(&t
));
960 *strchr(timestr
, '\n') = '\0';
961 printf("%s ", timestr
);
963 printf("%*s", twidth
, " ");
968 printf("set %d ", rule
->set
);
971 * print the optional "match probability"
973 if (rule
->cmd_len
> 0) {
975 if (cmd
->opcode
== O_PROB
) {
976 ipfw_insn_u32
*p
= (ipfw_insn_u32
*)cmd
;
977 double d
= 1.0 * p
->d
[0];
979 d
= (d
/ 0x7fffffff);
980 printf("prob %f ", d
);
985 * first print actions
987 for (l
= rule
->cmd_len
- rule
->act_ofs
, cmd
= ACTION_PTR(rule
);
988 l
> 0 ; l
-= F_LEN(cmd
), cmd
+= F_LEN(cmd
)) {
989 switch(cmd
->opcode
) {
991 printf("check-state");
992 flags
= HAVE_IP
; /* avoid printing anything else */
1008 if (cmd
->arg1
== ICMP_REJECT_RST
)
1010 else if (cmd
->arg1
== ICMP_UNREACH_HOST
)
1013 print_reject_code(cmd
->arg1
);
1017 printf("skipto %u", cmd
->arg1
);
1021 printf("pipe %u", cmd
->arg1
);
1025 printf("queue %u", cmd
->arg1
);
1029 printf("divert %u", cmd
->arg1
);
1033 printf("tee %u", cmd
->arg1
);
1038 ipfw_insn_sa
*s
= (ipfw_insn_sa
*)cmd
;
1040 printf("fwd %s", inet_ntoa(s
->sa
.sin_addr
));
1042 printf(",%d", s
->sa
.sin_port
);
1046 case O_LOG
: /* O_LOG is printed last */
1047 logptr
= (ipfw_insn_log
*)cmd
;
1051 printf("** unrecognized action %d len %d",
1052 cmd
->opcode
, cmd
->len
);
1056 if (logptr
->max_log
> 0)
1057 printf(" log logamount %d", logptr
->max_log
);
1063 * then print the body.
1065 if (rule
->_pad
& 1) { /* empty rules before options */
1067 printf(" ip from any to any");
1068 flags
|= HAVE_IP
| HAVE_OPTIONS
;
1071 for (l
= rule
->act_ofs
, cmd
= rule
->cmd
;
1072 l
> 0 ; l
-= F_LEN(cmd
) , cmd
+= F_LEN(cmd
)) {
1074 ipfw_insn_u32
*cmd32
= (ipfw_insn_u32
*)cmd
;
1076 show_prerequisites(&flags
, 0, cmd
->opcode
);
1078 switch(cmd
->opcode
) {
1080 break; /* done already */
1083 break; /* no need to print anything here */
1086 ipfw_insn_mac
*m
= (ipfw_insn_mac
*)cmd
;
1088 if ((cmd
->len
& F_OR
) && !or_block
)
1090 if (cmd
->len
& F_NOT
)
1094 print_mac(m
->addr
, m
->mask
);
1095 print_mac(m
->addr
+ 6, m
->mask
+ 6);
1100 if ((cmd
->len
& F_OR
) && !or_block
)
1102 print_newports((ipfw_insn_u16
*)cmd
, IPPROTO_ETHERTYPE
,
1103 (flags
& HAVE_OPTIONS
) ? cmd
->opcode
: 0);
1104 flags
|= HAVE_MAC
| HAVE_MACTYPE
| HAVE_OPTIONS
;
1111 show_prerequisites(&flags
, HAVE_PROTO
, 0);
1112 if (!(flags
& HAVE_SRCIP
))
1114 if ((cmd
->len
& F_OR
) && !or_block
)
1116 print_ip((ipfw_insn_ip
*)cmd
,
1117 (flags
& HAVE_OPTIONS
) ? " src-ip" : "");
1118 flags
|= HAVE_SRCIP
;
1125 show_prerequisites(&flags
, HAVE_PROTO
|HAVE_SRCIP
, 0);
1126 if (!(flags
& HAVE_DSTIP
))
1128 if ((cmd
->len
& F_OR
) && !or_block
)
1130 print_ip((ipfw_insn_ip
*)cmd
,
1131 (flags
& HAVE_OPTIONS
) ? " dst-ip" : "");
1132 flags
|= HAVE_DSTIP
;
1136 show_prerequisites(&flags
, HAVE_IP
, 0);
1138 show_prerequisites(&flags
, HAVE_PROTO
|HAVE_SRCIP
, 0);
1139 if ((cmd
->len
& F_OR
) && !or_block
)
1141 print_newports((ipfw_insn_u16
*)cmd
, proto
,
1142 (flags
& HAVE_OPTIONS
) ? cmd
->opcode
: 0);
1146 struct protoent
*pe
;
1148 if ((cmd
->len
& F_OR
) && !or_block
)
1150 if (cmd
->len
& F_NOT
)
1153 pe
= getprotobynumber(cmd
->arg1
);
1154 if (flags
& HAVE_OPTIONS
)
1157 printf(" %s", pe
->p_name
);
1159 printf(" %u", cmd
->arg1
);
1161 flags
|= HAVE_PROTO
;
1164 default: /*options ... */
1165 show_prerequisites(&flags
, HAVE_IP
| HAVE_OPTIONS
, 0);
1166 if ((cmd
->len
& F_OR
) && !or_block
)
1168 if (cmd
->len
& F_NOT
&& cmd
->opcode
!= O_IN
)
1170 switch(cmd
->opcode
) {
1176 printf(cmd
->len
& F_NOT
? " out" : " in");
1186 ipfw_insn_if
*cmdif
= (ipfw_insn_if
*)cmd
;
1188 if (cmd
->opcode
== O_XMIT
)
1190 else if (cmd
->opcode
== O_RECV
)
1192 else /* if (cmd->opcode == O_VIA) */
1194 if (cmdif
->name
[0] == '\0')
1196 inet_ntoa(cmdif
->p
.ip
));
1197 else if (cmdif
->p
.unit
== -1)
1198 printf(" %s %s*", s
, cmdif
->name
);
1200 printf(" %s %s%d", s
, cmdif
->name
,
1206 if (F_LEN(cmd
) == 1)
1207 printf(" ipid %u", cmd
->arg1
);
1209 print_newports((ipfw_insn_u16
*)cmd
, 0,
1214 if (F_LEN(cmd
) == 1)
1215 printf(" ipttl %u", cmd
->arg1
);
1217 print_newports((ipfw_insn_u16
*)cmd
, 0,
1222 printf(" ipver %u", cmd
->arg1
);
1225 case O_IPPRECEDENCE
:
1226 printf(" ipprecedence %u", (cmd
->arg1
) >> 5 );
1230 if (F_LEN(cmd
) == 1)
1231 printf(" iplen %u", cmd
->arg1
);
1233 print_newports((ipfw_insn_u16
*)cmd
, 0,
1238 print_flags("ipoptions", cmd
, f_ipopts
);
1242 print_flags("iptos", cmd
, f_iptos
);
1246 print_icmptypes((ipfw_insn_u32
*)cmd
);
1250 printf(" established");
1254 print_flags("tcpflags", cmd
, f_tcpflags
);
1258 print_flags("tcpoptions", cmd
, f_tcpopts
);
1262 printf(" tcpwin %d", ntohs(cmd
->arg1
));
1266 printf(" tcpack %ld", ntohl(cmd32
->d
[0]));
1270 printf(" tcpseq %ld", ntohl(cmd32
->d
[0]));
1275 struct passwd
*pwd
= getpwuid(cmd32
->d
[0]);
1278 printf(" uid %s", pwd
->pw_name
);
1280 printf(" uid %u", cmd32
->d
[0]);
1286 struct group
*grp
= getgrgid(cmd32
->d
[0]);
1289 printf(" gid %s", grp
->gr_name
);
1291 printf(" gid %u", cmd32
->d
[0]);
1296 printf(" verrevpath");
1304 comment
= (char *)(cmd
+ 1);
1308 printf(" keep-state");
1313 struct _s_x
*p
= limit_masks
;
1314 ipfw_insn_limit
*c
= (ipfw_insn_limit
*)cmd
;
1315 uint8_t x
= c
->limit_mask
;
1316 char const *comma
= " ";
1319 for (; p
->x
!= 0 ; p
++)
1320 if ((x
& p
->x
) == p
->x
) {
1322 printf("%s%s", comma
, p
->s
);
1325 printf(" %d", c
->conn_limit
);
1330 printf(" [opcode %d len %d]",
1331 cmd
->opcode
, cmd
->len
);
1334 if (cmd
->len
& F_OR
) {
1337 } else if (or_block
) {
1342 show_prerequisites(&flags
, HAVE_IP
, 0);
1344 printf(" // %s", comment
);
1349 show_dyn_ipfw(ipfw_dyn_rule
*d
, int pcwidth
, int bcwidth
)
1351 struct protoent
*pe
;
1356 if (!d
->expire
&& !(d
->dyn_type
== O_LIMIT_PARENT
))
1359 bcopy(&d
->rule
, &rulenum
, sizeof(rulenum
));
1360 printf("%05d", rulenum
);
1361 if (pcwidth
>0 || bcwidth
>0)
1362 printf(" %*llu %*llu (%ds)", pcwidth
,
1363 align_uint64(&d
->pcnt
), bcwidth
,
1364 align_uint64(&d
->bcnt
), d
->expire
);
1365 switch (d
->dyn_type
) {
1366 case O_LIMIT_PARENT
:
1367 printf(" PARENT %d", d
->count
);
1372 case O_KEEP_STATE
: /* bidir, no mask */
1377 if ((pe
= getprotobynumber(d
->id
.proto
)) != NULL
)
1378 printf(" %s", pe
->p_name
);
1380 printf(" proto %u", d
->id
.proto
);
1382 a
.s_addr
= htonl(d
->id
.src_ip
);
1383 printf(" %s %d", inet_ntoa(a
), d
->id
.src_port
);
1385 a
.s_addr
= htonl(d
->id
.dst_ip
);
1386 printf(" <-> %s %d", inet_ntoa(a
), d
->id
.dst_port
);
1391 sort_q(const void *pa
, const void *pb
)
1393 int rev
= (do_sort
< 0);
1394 int field
= rev
? -do_sort
: do_sort
;
1396 const struct dn_flow_queue
*a
= pa
;
1397 const struct dn_flow_queue
*b
= pb
;
1401 res
= a
->len
- b
->len
;
1404 res
= a
->len_bytes
- b
->len_bytes
;
1407 case 3: /* tot pkts */
1408 res
= a
->tot_pkts
- b
->tot_pkts
;
1411 case 4: /* tot bytes */
1412 res
= a
->tot_bytes
- b
->tot_bytes
;
1419 return (int)(rev
? res
: -res
);
1423 list_queues(struct dn_flow_set
*fs
, struct dn_flow_queue
*q
)
1427 printf(" mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n",
1428 fs
->flow_mask
.proto
,
1429 fs
->flow_mask
.src_ip
, fs
->flow_mask
.src_port
,
1430 fs
->flow_mask
.dst_ip
, fs
->flow_mask
.dst_port
);
1431 if (fs
->rq_elements
== 0)
1434 printf("BKT Prot ___Source IP/port____ "
1435 "____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp\n");
1437 heapsort(q
, fs
->rq_elements
, sizeof *q
, sort_q
);
1438 for (l
= 0; l
< fs
->rq_elements
; l
++) {
1440 struct protoent
*pe
;
1442 ina
.s_addr
= htonl(q
[l
].id
.src_ip
);
1443 printf("%3d ", q
[l
].hash_slot
);
1444 pe
= getprotobynumber(q
[l
].id
.proto
);
1446 printf("%-4s ", pe
->p_name
);
1448 printf("%4u ", q
[l
].id
.proto
);
1449 printf("%15s/%-5d ",
1450 inet_ntoa(ina
), q
[l
].id
.src_port
);
1451 ina
.s_addr
= htonl(q
[l
].id
.dst_ip
);
1452 printf("%15s/%-5d ",
1453 inet_ntoa(ina
), q
[l
].id
.dst_port
);
1454 printf("%4qu %8qu %2u %4u %3u\n",
1455 q
[l
].tot_pkts
, q
[l
].tot_bytes
,
1456 q
[l
].len
, q
[l
].len_bytes
, q
[l
].drops
);
1458 printf(" S %20qd F %20qd\n",
1464 print_flowset_parms(struct dn_flow_set
*fs
, char *prefix
)
1469 char red
[90]; /* Display RED parameters */
1472 if (fs
->flags_fs
& DN_QSIZE_IS_BYTES
) {
1474 sprintf(qs
, "%d KB", l
/ 1024);
1476 sprintf(qs
, "%d B", l
);
1478 sprintf(qs
, "%3d sl.", l
);
1480 sprintf(plr
, "plr %f", 1.0 * fs
->plr
/ (double)(0x7fffffff));
1483 if (fs
->flags_fs
& DN_IS_RED
) /* RED parameters */
1485 "\n\t %cRED w_q %f min_th %d max_th %d max_p %f",
1486 (fs
->flags_fs
& DN_IS_GENTLE_RED
) ? 'G' : ' ',
1487 1.0 * fs
->w_q
/ (double)(1 << SCALE_RED
),
1488 SCALE_VAL(fs
->min_th
),
1489 SCALE_VAL(fs
->max_th
),
1490 1.0 * fs
->max_p
/ (double)(1 << SCALE_RED
));
1492 sprintf(red
, "droptail");
1494 printf("%s %s%s %d queues (%d buckets) %s\n",
1495 prefix
, qs
, plr
, fs
->rq_elements
, fs
->rq_size
, red
);
1499 list_pipes(void *data
, uint nbytes
, int ac
, char *av
[])
1503 struct dn_pipe
*p
= (struct dn_pipe
*) data
;
1504 struct dn_flow_set
*fs
;
1505 struct dn_flow_queue
*q
;
1509 rulenum
= strtoul(*av
++, NULL
, 10);
1512 for (; nbytes
>= sizeof *p
; p
= (struct dn_pipe
*)next
) {
1513 double b
= p
->bandwidth
;
1517 if (p
->next
!= (struct dn_pipe
*)DN_IS_PIPE
)
1518 break; /* done with pipes, now queues */
1521 * compute length, as pipe have variable size
1523 l
= sizeof(*p
) + p
->fs
.rq_elements
* sizeof(*q
);
1524 next
= (char *)p
+ l
;
1527 if (rulenum
!= 0 && rulenum
!= p
->pipe_nr
)
1531 * Print rate (or clocking interface)
1533 if (p
->if_name
[0] != '\0')
1534 sprintf(buf
, "%s", p
->if_name
);
1536 sprintf(buf
, "unlimited");
1537 else if (b
>= 1000000)
1538 sprintf(buf
, "%7.3f Mbit/s", b
/1000000);
1540 sprintf(buf
, "%7.3f Kbit/s", b
/1000);
1542 sprintf(buf
, "%7.3f bit/s ", b
);
1544 sprintf(prefix
, "%05d: %s %4d ms ",
1545 p
->pipe_nr
, buf
, p
->delay
);
1546 print_flowset_parms(&(p
->fs
), prefix
);
1548 printf(" V %20qd\n", p
->V
>> MY_M
);
1550 q
= (struct dn_flow_queue
*)(p
+1);
1551 list_queues(&(p
->fs
), q
);
1553 for (fs
= next
; nbytes
>= sizeof *fs
; fs
= next
) {
1556 if (fs
->next
!= (struct dn_flow_set
*)DN_IS_QUEUE
)
1558 l
= sizeof(*fs
) + fs
->rq_elements
* sizeof(*q
);
1559 next
= (char *)fs
+ l
;
1561 q
= (struct dn_flow_queue
*)(fs
+1);
1562 sprintf(prefix
, "q%05d: weight %d pipe %d ",
1563 fs
->fs_nr
, fs
->weight
, fs
->parent_nr
);
1564 print_flowset_parms(fs
, prefix
);
1570 * This one handles all set-related commands
1571 * ipfw set { show | enable | disable }
1573 * ipfw set move X to Y
1574 * ipfw set move rule X to Y
1577 sets_handler(int ac
, char *av
[])
1579 uint32_t set_disable
, masks
[2];
1582 uint8_t cmd
, new_set
;
1588 errx(EX_USAGE
, "set needs command");
1589 if (!strncmp(*av
, "show", strlen(*av
)) ) {
1593 nbytes
= sizeof(struct ip_fw
);
1594 if ((data
= calloc(1, nbytes
)) == NULL
)
1595 err(EX_OSERR
, "calloc");
1597 if (do_cmd(IP_FW_GET
, data
, (uintptr_t)&nbytes
) < 0)
1598 err(EX_OSERR
, "getsockopt(IP_FW_GET)");
1599 bcopy(&((struct ip_fw
*)data
)->next_rule
,
1600 &set_disable
, sizeof(set_disable
));
1602 for (i
= 0, msg
= "disable" ; i
< RESVD_SET
; i
++)
1603 if ((set_disable
& (1<<i
))) {
1604 printf("%s %d", msg
, i
);
1607 msg
= (set_disable
) ? " enable" : "enable";
1608 for (i
= 0; i
< RESVD_SET
; i
++)
1609 if (!(set_disable
& (1<<i
))) {
1610 printf("%s %d", msg
, i
);
1614 } else if (!strncmp(*av
, "swap", strlen(*av
))) {
1618 errx(EX_USAGE
, "set swap needs 2 set numbers\n");
1619 rulenum
= atoi(av
[0]);
1620 new_set
= atoi(av
[1]);
1621 if (!isdigit(*(av
[0])) || rulenum
> RESVD_SET
)
1622 errx(EX_DATAERR
, "invalid set number %s\n", av
[0]);
1623 if (!isdigit(*(av
[1])) || new_set
> RESVD_SET
)
1624 errx(EX_DATAERR
, "invalid set number %s\n", av
[1]);
1625 masks
[0] = (4 << 24) | (new_set
<< 16) | (rulenum
);
1627 bzero(&rule
, sizeof(rule
));
1628 rule
.rulenum
= masks
[0];
1630 i
= do_cmd(IP_FW_DEL
, &rule
, sizeof(rule
));
1631 } else if (!strncmp(*av
, "move", strlen(*av
))) {
1634 if (ac
&& !strncmp(*av
, "rule", strlen(*av
))) {
1639 if (ac
!= 3 || strncmp(av
[1], "to", strlen(*av
)))
1640 errx(EX_USAGE
, "syntax: set move [rule] X to Y\n");
1641 rulenum
= atoi(av
[0]);
1642 new_set
= atoi(av
[2]);
1643 if (!isdigit(*(av
[0])) || (cmd
== 3 && rulenum
> RESVD_SET
) ||
1644 (cmd
== 2 && rulenum
== 65535) )
1645 errx(EX_DATAERR
, "invalid source number %s\n", av
[0]);
1646 if (!isdigit(*(av
[2])) || new_set
> RESVD_SET
)
1647 errx(EX_DATAERR
, "invalid dest. set %s\n", av
[1]);
1648 masks
[0] = (cmd
<< 24) | (new_set
<< 16) | (rulenum
);
1650 bzero(&rule
, sizeof(rule
));
1651 rule
.rulenum
= masks
[0];
1653 i
= do_cmd(IP_FW_DEL
, &rule
, sizeof(rule
));
1654 } else if (!strncmp(*av
, "disable", strlen(*av
)) ||
1655 !strncmp(*av
, "enable", strlen(*av
)) ) {
1656 int which
= !strncmp(*av
, "enable", strlen(*av
)) ? 1 : 0;
1660 masks
[0] = masks
[1] = 0;
1663 if (isdigit(**av
)) {
1665 if (i
< 0 || i
> RESVD_SET
)
1667 "invalid set number %d\n", i
);
1668 masks
[which
] |= (1<<i
);
1669 } else if (!strncmp(*av
, "disable", strlen(*av
)))
1671 else if (!strncmp(*av
, "enable", strlen(*av
)))
1675 "invalid set command %s\n", *av
);
1678 if ( (masks
[0] & masks
[1]) != 0 )
1680 "cannot enable and disable the same set\n");
1682 bzero(&rule
, sizeof(rule
));
1683 rule
.set_masks
[0] = masks
[0];
1684 rule
.set_masks
[1] = masks
[1];
1686 i
= do_cmd(IP_FW_DEL
, &rule
, sizeof(rule
));
1688 warn("set enable/disable: setsockopt(IP_FW_DEL)");
1690 errx(EX_USAGE
, "invalid set command %s\n", *av
);
1694 sysctl_handler(int ac
, char *av
[], int which
)
1700 warnx("missing keyword to enable/disable\n");
1701 } else if (strncmp(*av
, "firewall", strlen(*av
)) == 0) {
1702 sysctlbyname("net.inet.ip.fw.enable", NULL
, 0,
1703 &which
, sizeof(which
));
1704 } else if (strncmp(*av
, "one_pass", strlen(*av
)) == 0) {
1705 sysctlbyname("net.inet.ip.fw.one_pass", NULL
, 0,
1706 &which
, sizeof(which
));
1707 } else if (strncmp(*av
, "debug", strlen(*av
)) == 0) {
1708 sysctlbyname("net.inet.ip.fw.debug", NULL
, 0,
1709 &which
, sizeof(which
));
1710 } else if (strncmp(*av
, "verbose", strlen(*av
)) == 0) {
1711 sysctlbyname("net.inet.ip.fw.verbose", NULL
, 0,
1712 &which
, sizeof(which
));
1713 } else if (strncmp(*av
, "dyn_keepalive", strlen(*av
)) == 0) {
1714 sysctlbyname("net.inet.ip.fw.dyn_keepalive", NULL
, 0,
1715 &which
, sizeof(which
));
1717 warnx("unrecognize enable/disable keyword: %s\n", *av
);
1722 list(int ac
, char *av
[], int show_counters
)
1725 ipfw_dyn_rule
*dynrules
, *d
;
1727 #define NEXT(r) ((struct ip_fw *)((char *)r + RULESIZE(r)))
1730 int bcwidth
, n
, nbytes
, nstat
, ndyn
, pcwidth
, width
;
1731 int exitval
= EX_OK
;
1738 const int ocmd
= do_pipe
? IP_DUMMYNET_GET
: IP_FW_GET
;
1739 int nalloc
= 1024; /* start somewhere... */
1742 fprintf(stderr
, "Testing only, list disabled\n");
1749 /* get rules or pipes from kernel, resizing array as necessary */
1752 while (nbytes
>= nalloc
) {
1753 nalloc
= nalloc
* 2 + 200;
1755 if ((data
= realloc(data
, nbytes
)) == NULL
)
1756 err(EX_OSERR
, "realloc");
1758 if (do_cmd(ocmd
, data
, (uintptr_t)&nbytes
) < 0)
1759 err(EX_OSERR
, "getsockopt(IP_%s_GET)",
1760 do_pipe
? "DUMMYNET" : "FW");
1764 list_pipes(data
, nbytes
, ac
, av
);
1769 * Count static rules. They have variable size so we
1770 * need to scan the list to count them.
1772 for (nstat
= 1, r
= data
, lim
= (char *)data
+ nbytes
;
1773 r
->rulenum
< 65535 && (char *)r
< lim
;
1774 ++nstat
, r
= NEXT(r
) )
1778 * Count dynamic rules. This is easier as they have
1782 dynrules
= (ipfw_dyn_rule
*)r
;
1783 n
= (char *)r
- (char *)data
;
1784 ndyn
= (nbytes
- n
) / sizeof *dynrules
;
1786 /* if showing stats, figure out column widths ahead of time */
1787 bcwidth
= pcwidth
= 0;
1788 if (show_counters
) {
1789 for (n
= 0, r
= data
; n
< nstat
; n
++, r
= NEXT(r
)) {
1790 /* packet counter */
1791 width
= snprintf(NULL
, 0, "%llu",
1792 align_uint64(&r
->pcnt
));
1793 if (width
> pcwidth
)
1797 width
= snprintf(NULL
, 0, "%llu",
1798 align_uint64(&r
->bcnt
));
1799 if (width
> bcwidth
)
1803 if (do_dynamic
&& ndyn
) {
1804 for (n
= 0, d
= dynrules
; n
< ndyn
; n
++, d
++) {
1805 width
= snprintf(NULL
, 0, "%llu",
1806 align_uint64(&d
->pcnt
));
1807 if (width
> pcwidth
)
1810 width
= snprintf(NULL
, 0, "%llu",
1811 align_uint64(&d
->bcnt
));
1812 if (width
> bcwidth
)
1816 /* if no rule numbers were specified, list all rules */
1818 for (n
= 0, r
= data
; n
< nstat
; n
++, r
= NEXT(r
) )
1819 show_ipfw(r
, pcwidth
, bcwidth
);
1821 if (do_dynamic
&& ndyn
) {
1822 printf("## Dynamic rules (%d):\n", ndyn
);
1823 for (n
= 0, d
= dynrules
; n
< ndyn
; n
++, d
++)
1824 show_dyn_ipfw(d
, pcwidth
, bcwidth
);
1829 /* display specific rules requested on command line */
1831 for (lac
= ac
, lav
= av
; lac
!= 0; lac
--) {
1832 /* convert command line rule # */
1833 last
= rnum
= strtoul(*lav
++, &endptr
, 10);
1835 last
= strtoul(endptr
+1, &endptr
, 10);
1838 warnx("invalid rule number: %s", *(lav
- 1));
1841 for (n
= seen
= 0, r
= data
; n
< nstat
; n
++, r
= NEXT(r
) ) {
1842 if (r
->rulenum
> last
)
1844 if (r
->rulenum
>= rnum
&& r
->rulenum
<= last
) {
1845 show_ipfw(r
, pcwidth
, bcwidth
);
1850 /* give precedence to other error(s) */
1851 if (exitval
== EX_OK
)
1852 exitval
= EX_UNAVAILABLE
;
1853 warnx("rule %lu does not exist", rnum
);
1857 if (do_dynamic
&& ndyn
) {
1858 printf("## Dynamic rules:\n");
1859 for (lac
= ac
, lav
= av
; lac
!= 0; lac
--) {
1860 rnum
= strtoul(*lav
++, &endptr
, 10);
1862 last
= strtoul(endptr
+1, &endptr
, 10);
1864 /* already warned */
1866 for (n
= 0, d
= dynrules
; n
< ndyn
; n
++, d
++) {
1869 bcopy(&d
->rule
, &rulenum
, sizeof(rulenum
));
1872 if (r
->rulenum
>= rnum
&& r
->rulenum
<= last
)
1873 show_dyn_ipfw(d
, pcwidth
, bcwidth
);
1883 if (exitval
!= EX_OK
)
1891 fprintf(stderr
, "usage: ipfw [options]\n"
1892 "do \"ipfw -h\" or see ipfw manpage for details\n"
1901 "ipfw syntax summary (but please do read the ipfw(8) manpage):\n"
1902 "ipfw [-acdeftTnNpqS] <command> where <command> is one of:\n"
1903 "add [num] [set N] [prob x] RULE-BODY\n"
1904 "{pipe|queue} N config PIPE-BODY\n"
1905 "[pipe|queue] {zero|delete|show} [N{,N}]\n"
1906 "set [disable N... enable N...] | move [rule] X to Y | swap X Y | show\n"
1908 "RULE-BODY: check-state [LOG] | ACTION [LOG] ADDR [OPTION_LIST]\n"
1909 "ACTION: check-state | allow | count | deny | reject | skipto N |\n"
1910 " {divert|tee} PORT | forward ADDR | pipe N | queue N\n"
1911 "ADDR: [ MAC dst src ether_type ] \n"
1912 " [ from IPADDR [ PORT ] to IPADDR [ PORTLIST ] ]\n"
1913 "IPADDR: [not] { any | me | ip/bits{x,y,z} | IPLIST }\n"
1914 "IPLIST: { ip | ip/bits | ip:mask }[,IPLIST]\n"
1915 "OPTION_LIST: OPTION [OPTION_LIST]\n"
1916 "OPTION: bridged | {dst-ip|src-ip} ADDR | {dst-port|src-port} LIST |\n"
1917 " estab | frag | {gid|uid} N | icmptypes LIST | in | out | ipid LIST |\n"
1918 " iplen LIST | ipoptions SPEC | ipprecedence | ipsec | iptos SPEC |\n"
1919 " ipttl LIST | ipversion VER | keep-state | layer2 | limit ... |\n"
1920 " mac ... | mac-type LIST | proto LIST | {recv|xmit|via} {IF|IPADDR} |\n"
1921 " setup | {tcpack|tcpseq|tcpwin} NN | tcpflags SPEC | tcpoptions SPEC |\n"
1929 lookup_host (char *host
, struct in_addr
*ipaddr
)
1933 if (!inet_aton(host
, ipaddr
)) {
1934 if ((he
= gethostbyname(host
)) == NULL
)
1936 *ipaddr
= *(struct in_addr
*)he
->h_addr_list
[0];
1942 * fills the addr and mask fields in the instruction as appropriate from av.
1943 * Update length as appropriate.
1944 * The following formats are allowed:
1945 * any matches any IP. Actually returns an empty instruction.
1946 * me returns O_IP_*_ME
1947 * 1.2.3.4 single IP address
1948 * 1.2.3.4:5.6.7.8 address:mask
1949 * 1.2.3.4/24 address/mask
1950 * 1.2.3.4/26{1,6,5,4,23} set of addresses in a subnet
1951 * We can have multiple comma-separated address/mask entries.
1954 fill_ip(ipfw_insn_ip
*cmd
, char *av
)
1957 uint32_t *d
= ((ipfw_insn_u32
*)cmd
)->d
;
1959 cmd
->o
.len
&= ~F_LEN_MASK
; /* zero len */
1961 if (!strncmp(av
, "any", strlen(av
)))
1964 if (!strncmp(av
, "me", strlen(av
))) {
1965 cmd
->o
.len
|= F_INSN_SIZE(ipfw_insn
);
1971 * After the address we can have '/' or ':' indicating a mask,
1972 * ',' indicating another address follows, '{' indicating a
1973 * set of addresses of unspecified size.
1975 char *p
= strpbrk(av
, "/:,{");
1985 if (lookup_host(av
, (struct in_addr
*)&d
[0]) != 0)
1986 errx(EX_NOHOST
, "hostname ``%s'' unknown", av
);
1989 if (!inet_aton(p
, (struct in_addr
*)&d
[1]))
1990 errx(EX_DATAERR
, "bad netmask ``%s''", p
);
1995 d
[1] = htonl(0); /* mask */
1996 else if (masklen
> 32)
1997 errx(EX_DATAERR
, "bad width ``%s''", p
);
1999 d
[1] = htonl(~0 << (32 - masklen
));
2001 case '{': /* no mask, assume /24 and put back the '{' */
2002 d
[1] = htonl(~0 << (32 - 24));
2006 case ',': /* single address plus continuation */
2009 case 0: /* initialization value */
2011 d
[1] = htonl(~0); /* force /32 */
2014 d
[0] &= d
[1]; /* mask base address with mask */
2015 /* find next separator */
2017 p
= strpbrk(p
, ",{");
2018 if (p
&& *p
== '{') {
2020 * We have a set of addresses. They are stored as follows:
2021 * arg1 is the set size (powers of 2, 2..256)
2022 * addr is the base address IN HOST FORMAT
2023 * mask.. is an array of arg1 bits (rounded up to
2024 * the next multiple of 32) with bits set
2025 * for each host in the map.
2027 uint32_t *map
= (uint32_t *)&cmd
->mask
;
2029 int i
= contigmask((uint8_t *)&(d
[1]), 32);
2032 errx(EX_DATAERR
, "address set cannot be in a list");
2033 if (i
< 24 || i
> 31)
2034 errx(EX_DATAERR
, "invalid set with mask %d\n", i
);
2035 cmd
->o
.arg1
= 1<<(32-i
); /* map length */
2036 d
[0] = ntohl(d
[0]); /* base addr in host format */
2037 cmd
->o
.opcode
= O_IP_DST_SET
; /* default */
2038 cmd
->o
.len
|= F_INSN_SIZE(ipfw_insn_u32
) + (cmd
->o
.arg1
+31)/32;
2039 for (i
= 0; i
< (cmd
->o
.arg1
+31)/32 ; i
++)
2040 map
[i
] = 0; /* clear map */
2044 high
= low
+ cmd
->o
.arg1
- 1;
2046 * Here, i stores the previous value when we specify a range
2047 * of addresses within a mask, e.g. 45-63. i = -1 means we
2048 * have no previous value.
2050 i
= -1; /* previous value in a range */
2051 while (isdigit(*av
)) {
2053 int a
= strtol(av
, &s
, 0);
2055 if (s
== av
) { /* no parameter */
2057 errx(EX_DATAERR
, "set not closed\n");
2059 errx(EX_DATAERR
, "incomplete range %d-", i
);
2062 if (a
< low
|| a
> high
)
2063 errx(EX_DATAERR
, "addr %d out of range [%d-%d]\n",
2066 if (i
== -1) /* no previous in range */
2068 else { /* check that range is valid */
2070 errx(EX_DATAERR
, "invalid range %d-%d",
2073 errx(EX_DATAERR
, "double '-' in range");
2076 map
[i
/32] |= 1<<(i
& 31);
2087 if (av
) /* then *av must be a ',' */
2090 /* Check this entry */
2091 if (d
[1] == 0) { /* "any", specified as x.x.x.x/0 */
2093 * 'any' turns the entire list into a NOP.
2094 * 'not any' never matches, so it is removed from the
2095 * list unless it is the only item, in which case we
2098 if (cmd
->o
.len
& F_NOT
) { /* "not any" never matches */
2099 if (av
== NULL
&& len
== 0) /* only this entry */
2100 errx(EX_DATAERR
, "not any never matches");
2102 /* else do nothing and return */
2105 /* A single IP can be stored in an optimized format */
2106 if (d
[1] == IP_MASK_ALL
&& av
== NULL
&& len
== 0) {
2107 cmd
->o
.len
|= F_INSN_SIZE(ipfw_insn_u32
);
2110 len
+= 2; /* two words... */
2113 cmd
->o
.len
|= len
+1;
2118 * helper function to process a set of flags and set bits in the
2119 * appropriate masks.
2122 fill_flags(ipfw_insn
*cmd
, enum ipfw_opcodes opcode
,
2123 struct _s_x
*flags
, char *p
)
2125 uint8_t set
=0, clear
=0;
2128 char *q
; /* points to the separator */
2130 uint8_t *which
; /* mask we are working on */
2140 val
= match_token(flags
, p
);
2142 errx(EX_DATAERR
, "invalid flag %s", p
);
2143 *which
|= (uint8_t)val
;
2146 cmd
->opcode
= opcode
;
2147 cmd
->len
= (cmd
->len
& (F_NOT
| F_OR
)) | 1;
2148 cmd
->arg1
= (set
& 0xff) | ( (clear
& 0xff) << 8);
2153 delete(int ac
, char *av
[])
2158 int exitval
= EX_OK
;
2161 memset(&p
, 0, sizeof p
);
2164 if (ac
> 0 && !strncmp(*av
, "set", strlen(*av
))) {
2165 do_set
= 1; /* delete set */
2170 while (ac
&& isdigit(**av
)) {
2171 i
= atoi(*av
); av
++; ac
--;
2177 i
= do_cmd(IP_DUMMYNET_DEL
, &p
, sizeof p
);
2180 warn("rule %u: setsockopt(IP_DUMMYNET_DEL)",
2181 do_pipe
== 1 ? p
.pipe_nr
: p
.fs
.fs_nr
);
2184 bzero(&rule
, sizeof(rule
));
2185 rule
.rulenum
= (i
& 0xffff) | (do_set
<< 24);
2186 i
= do_cmd(IP_FW_DEL
, &rule
, sizeof(rule
));
2188 exitval
= EX_UNAVAILABLE
;
2189 warn("rule %u: setsockopt(IP_FW_DEL)",
2194 if (exitval
!= EX_OK
)
2200 * fill the interface structure. We do not check the name as we can
2201 * create interfaces dynamically, so checking them at insert time
2202 * makes relatively little sense.
2203 * A '*' following the name means any unit.
2206 fill_iface(ipfw_insn_if
*cmd
, char *arg
)
2208 cmd
->name
[0] = '\0';
2209 cmd
->o
.len
|= F_INSN_SIZE(ipfw_insn_if
);
2211 /* Parse the interface or address */
2212 if (!strcmp(arg
, "any"))
2213 cmd
->o
.len
= 0; /* effectively ignore this command */
2214 else if (!isdigit(*arg
)) {
2217 strncpy(cmd
->name
, arg
, sizeof(cmd
->name
));
2218 cmd
->name
[sizeof(cmd
->name
) - 1] = '\0';
2219 /* find first digit or wildcard */
2220 for (q
= cmd
->name
; *q
&& !isdigit(*q
) && *q
!= '*'; q
++)
2222 cmd
->p
.unit
= (*q
== '*') ? -1 : atoi(q
);
2224 } else if (!inet_aton(arg
, &cmd
->p
.ip
))
2225 errx(EX_DATAERR
, "bad ip address ``%s''", arg
);
2229 * the following macro returns an error message if we run out of
2232 #define NEED1(msg) {if (!ac) errx(EX_USAGE, msg);}
2235 config_pipe(int ac
, char **av
)
2243 memset(&p
, 0, sizeof p
);
2247 if (ac
&& isdigit(**av
)) {
2248 i
= atoi(*av
); av
++; ac
--;
2256 int tok
= match_token(dummynet_params
, *av
);
2261 p
.fs
.flags_fs
|= DN_NOERROR
;
2265 NEED1("plr needs argument 0..1\n");
2266 d
= strtod(av
[0], NULL
);
2271 p
.fs
.plr
= (int)(d
*0x7fffffff);
2276 NEED1("queue needs queue size\n");
2278 p
.fs
.qsize
= strtoul(av
[0], &end
, 0);
2279 if (*end
== 'K' || *end
== 'k') {
2280 p
.fs
.flags_fs
|= DN_QSIZE_IS_BYTES
;
2282 } else if (*end
== 'B' || !strncmp(end
, "by", 2)) {
2283 p
.fs
.flags_fs
|= DN_QSIZE_IS_BYTES
;
2289 NEED1("buckets needs argument\n");
2290 p
.fs
.rq_size
= strtoul(av
[0], NULL
, 0);
2295 NEED1("mask needs mask specifier\n");
2297 * per-flow queue, mask is dst_ip, dst_port,
2298 * src_ip, src_port, proto measured in bits
2302 p
.fs
.flow_mask
.dst_ip
= 0;
2303 p
.fs
.flow_mask
.src_ip
= 0;
2304 p
.fs
.flow_mask
.dst_port
= 0;
2305 p
.fs
.flow_mask
.src_port
= 0;
2306 p
.fs
.flow_mask
.proto
= 0;
2310 uint32_t *p32
= NULL
;
2311 uint16_t *p16
= NULL
;
2313 tok
= match_token(dummynet_params
, *av
);
2318 * special case, all bits significant
2320 p
.fs
.flow_mask
.dst_ip
= ~0;
2321 p
.fs
.flow_mask
.src_ip
= ~0;
2322 p
.fs
.flow_mask
.dst_port
= ~0;
2323 p
.fs
.flow_mask
.src_port
= ~0;
2324 p
.fs
.flow_mask
.proto
= ~0;
2325 p
.fs
.flags_fs
|= DN_HAVE_FLOW_MASK
;
2329 p32
= &p
.fs
.flow_mask
.dst_ip
;
2333 p32
= &p
.fs
.flow_mask
.src_ip
;
2337 p16
= &p
.fs
.flow_mask
.dst_port
;
2341 p16
= &p
.fs
.flow_mask
.src_port
;
2348 ac
++; av
--; /* backtrack */
2352 errx(EX_USAGE
, "mask: value missing");
2353 if (*av
[0] == '/') {
2354 a
= strtoul(av
[0]+1, &end
, 0);
2355 a
= (a
== 32) ? ~0 : (1 << a
) - 1;
2357 a
= strtoul(av
[0], &end
, 0);
2360 else if (p16
!= NULL
) {
2363 "mask: must be 16 bit");
2368 "mask: must be 8 bit");
2369 p
.fs
.flow_mask
.proto
= (uint8_t)a
;
2372 p
.fs
.flags_fs
|= DN_HAVE_FLOW_MASK
;
2374 } /* end while, config masks */
2380 NEED1("red/gred needs w_q/min_th/max_th/max_p\n");
2381 p
.fs
.flags_fs
|= DN_IS_RED
;
2382 if (tok
== TOK_GRED
)
2383 p
.fs
.flags_fs
|= DN_IS_GENTLE_RED
;
2385 * the format for parameters is w_q/min_th/max_th/max_p
2387 if ((end
= strsep(&av
[0], "/"))) {
2388 double w_q
= strtod(end
, NULL
);
2389 if (w_q
> 1 || w_q
<= 0)
2390 errx(EX_DATAERR
, "0 < w_q <= 1");
2391 p
.fs
.w_q
= (int) (w_q
* (1 << SCALE_RED
));
2393 if ((end
= strsep(&av
[0], "/"))) {
2394 p
.fs
.min_th
= strtoul(end
, &end
, 0);
2395 if (*end
== 'K' || *end
== 'k')
2396 p
.fs
.min_th
*= 1024;
2398 if ((end
= strsep(&av
[0], "/"))) {
2399 p
.fs
.max_th
= strtoul(end
, &end
, 0);
2400 if (*end
== 'K' || *end
== 'k')
2401 p
.fs
.max_th
*= 1024;
2403 if ((end
= strsep(&av
[0], "/"))) {
2404 double max_p
= strtod(end
, NULL
);
2405 if (max_p
> 1 || max_p
<= 0)
2406 errx(EX_DATAERR
, "0 < max_p <= 1");
2407 p
.fs
.max_p
= (int)(max_p
* (1 << SCALE_RED
));
2413 p
.fs
.flags_fs
&= ~(DN_IS_RED
|DN_IS_GENTLE_RED
);
2417 NEED1("bw needs bandwidth or interface\n");
2419 errx(EX_DATAERR
, "bandwidth only valid for pipes");
2421 * set clocking interface or bandwidth value
2423 if (av
[0][0] >= 'a' && av
[0][0] <= 'z') {
2424 int l
= sizeof(p
.if_name
)-1;
2425 /* interface name */
2426 strncpy(p
.if_name
, av
[0], l
);
2427 p
.if_name
[l
] = '\0';
2430 p
.if_name
[0] = '\0';
2431 p
.bandwidth
= strtoul(av
[0], &end
, 0);
2432 if (*end
== 'K' || *end
== 'k') {
2434 p
.bandwidth
*= 1000;
2435 } else if (*end
== 'M') {
2437 p
.bandwidth
*= 1000000;
2439 if (*end
== 'B' || !strncmp(end
, "by", 2))
2441 if (p
.bandwidth
< 0)
2442 errx(EX_DATAERR
, "bandwidth too large");
2449 errx(EX_DATAERR
, "delay only valid for pipes");
2450 NEED1("delay needs argument 0..10000ms\n");
2451 p
.delay
= strtoul(av
[0], NULL
, 0);
2457 errx(EX_DATAERR
,"weight only valid for queues");
2458 NEED1("weight needs argument 0..100\n");
2459 p
.fs
.weight
= strtoul(av
[0], &end
, 0);
2465 errx(EX_DATAERR
,"pipe only valid for queues");
2466 NEED1("pipe needs pipe_number\n");
2467 p
.fs
.parent_nr
= strtoul(av
[0], &end
, 0);
2472 errx(EX_DATAERR
, "unrecognised option ``%s''", *av
);
2477 errx(EX_DATAERR
, "pipe_nr must be > 0");
2478 if (p
.delay
> 10000)
2479 errx(EX_DATAERR
, "delay must be < 10000");
2480 } else { /* do_pipe == 2, queue */
2481 if (p
.fs
.parent_nr
== 0)
2482 errx(EX_DATAERR
, "pipe must be > 0");
2483 if (p
.fs
.weight
>100)
2484 errx(EX_DATAERR
, "weight must be <= 100");
2486 if (p
.fs
.flags_fs
& DN_QSIZE_IS_BYTES
) {
2487 if (p
.fs
.qsize
> 1024*1024)
2488 errx(EX_DATAERR
, "queue size must be < 1MB");
2490 if (p
.fs
.qsize
> 100)
2491 errx(EX_DATAERR
, "2 <= queue size <= 100");
2493 if (p
.fs
.flags_fs
& DN_IS_RED
) {
2495 int lookup_depth
, avg_pkt_size
;
2496 double s
, idle
, weight
, w_q
;
2497 struct clockinfo ck
;
2500 if (p
.fs
.min_th
>= p
.fs
.max_th
)
2501 errx(EX_DATAERR
, "min_th %d must be < than max_th %d",
2502 p
.fs
.min_th
, p
.fs
.max_th
);
2503 if (p
.fs
.max_th
== 0)
2504 errx(EX_DATAERR
, "max_th must be > 0");
2507 if (sysctlbyname("net.inet.ip.dummynet.red_lookup_depth",
2508 &lookup_depth
, &len
, NULL
, 0) == -1)
2510 errx(1, "sysctlbyname(\"%s\")",
2511 "net.inet.ip.dummynet.red_lookup_depth");
2512 if (lookup_depth
== 0)
2513 errx(EX_DATAERR
, "net.inet.ip.dummynet.red_lookup_depth"
2514 " must be greater than zero");
2517 if (sysctlbyname("net.inet.ip.dummynet.red_avg_pkt_size",
2518 &avg_pkt_size
, &len
, NULL
, 0) == -1)
2520 errx(1, "sysctlbyname(\"%s\")",
2521 "net.inet.ip.dummynet.red_avg_pkt_size");
2522 if (avg_pkt_size
== 0)
2524 "net.inet.ip.dummynet.red_avg_pkt_size must"
2525 " be greater than zero");
2527 len
= sizeof(struct clockinfo
);
2528 if (sysctlbyname("kern.clockrate", &ck
, &len
, NULL
, 0) == -1)
2529 errx(1, "sysctlbyname(\"%s\")", "kern.clockrate");
2532 * Ticks needed for sending a medium-sized packet.
2533 * Unfortunately, when we are configuring a WF2Q+ queue, we
2534 * do not have bandwidth information, because that is stored
2535 * in the parent pipe, and also we have multiple queues
2536 * competing for it. So we set s=0, which is not very
2537 * correct. But on the other hand, why do we want RED with
2540 if (p
.bandwidth
==0) /* this is a WF2Q+ queue */
2543 s
= ck
.hz
* avg_pkt_size
* 8 / p
.bandwidth
;
2546 * max idle time (in ticks) before avg queue size becomes 0.
2547 * NOTA: (3/w_q) is approx the value x so that
2548 * (1-w_q)^x < 10^-3.
2550 w_q
= ((double)p
.fs
.w_q
) / (1 << SCALE_RED
);
2551 idle
= s
* 3. / w_q
;
2552 p
.fs
.lookup_step
= (int)idle
/ lookup_depth
;
2553 if (!p
.fs
.lookup_step
)
2554 p
.fs
.lookup_step
= 1;
2556 for (t
= p
.fs
.lookup_step
; t
> 0; --t
)
2558 p
.fs
.lookup_weight
= (int)(weight
* (1 << SCALE_RED
));
2560 i
= do_cmd(IP_DUMMYNET_CONFIGURE
, &p
, sizeof p
);
2562 err(1, "setsockopt(%s)", "IP_DUMMYNET_CONFIGURE");
2566 get_mac_addr_mask(char *p
, uint8_t *addr
, uint8_t *mask
)
2571 addr
[i
] = mask
[i
] = 0;
2572 if (!strcmp(p
, "any"))
2575 for (i
=0; *p
&& i
<6;i
++, p
++) {
2576 addr
[i
] = strtol(p
, &p
, 16);
2577 if (*p
!= ':') /* we start with the mask */
2580 if (*p
== '/') { /* mask len */
2581 l
= strtol(p
+1, &p
, 0);
2582 for (i
=0; l
>0; l
-=8, i
++)
2583 mask
[i
] = (l
>=8) ? 0xff : (~0) << (8-l
);
2584 } else if (*p
== '&') { /* mask */
2585 for (i
=0, p
++; *p
&& i
<6;i
++, p
++) {
2586 mask
[i
] = strtol(p
, &p
, 16);
2590 } else if (*p
== '\0') {
2599 * helper function, updates the pointer to cmd with the length
2600 * of the current command, and also cleans up the first word of
2601 * the new command in case it has been clobbered before.
2604 next_cmd(ipfw_insn
*cmd
)
2607 bzero(cmd
, sizeof(*cmd
));
2612 * Takes arguments and copies them into a comment
2615 fill_comment(ipfw_insn
*cmd
, int ac
, char **av
)
2618 char *p
= (char *)(cmd
+ 1);
2620 cmd
->opcode
= O_NOP
;
2621 cmd
->len
= (cmd
->len
& (F_NOT
| F_OR
));
2623 /* Compute length of comment string. */
2624 for (i
= 0, l
= 0; i
< ac
; i
++)
2625 l
+= strlen(av
[i
]) + 1;
2630 "comment too long (max 80 chars)");
2632 cmd
->len
= (cmd
->len
& (F_NOT
| F_OR
)) | l
;
2633 for (i
= 0; i
< ac
; i
++) {
2642 * A function to fill simple commands of size 1.
2643 * Existing flags are preserved.
2646 fill_cmd(ipfw_insn
*cmd
, enum ipfw_opcodes opcode
, int flags
, uint16_t arg
)
2648 cmd
->opcode
= opcode
;
2649 cmd
->len
= ((cmd
->len
| flags
) & (F_NOT
| F_OR
)) | 1;
2654 * Fetch and add the MAC address and type, with masks. This generates one or
2655 * two microinstructions, and returns the pointer to the last one.
2658 add_mac(ipfw_insn
*cmd
, int ac
, char *av
[])
2663 errx(EX_DATAERR
, "MAC dst src");
2665 cmd
->opcode
= O_MACADDR2
;
2666 cmd
->len
= (cmd
->len
& (F_NOT
| F_OR
)) | F_INSN_SIZE(ipfw_insn_mac
);
2668 mac
= (ipfw_insn_mac
*)cmd
;
2669 get_mac_addr_mask(av
[0], mac
->addr
, mac
->mask
); /* dst */
2670 get_mac_addr_mask(av
[1], &(mac
->addr
[6]), &(mac
->mask
[6])); /* src */
2675 add_mactype(ipfw_insn
*cmd
, int ac
, char *av
)
2678 errx(EX_DATAERR
, "missing MAC type");
2679 if (strcmp(av
, "any") != 0) { /* we have a non-null type */
2680 fill_newports((ipfw_insn_u16
*)cmd
, av
, IPPROTO_ETHERTYPE
);
2681 cmd
->opcode
= O_MAC_TYPE
;
2688 add_proto(ipfw_insn
*cmd
, char *av
)
2690 struct protoent
*pe
;
2693 if (!strncmp(av
, "all", strlen(av
)))
2694 ; /* same as "ip" */
2695 else if ((proto
= atoi(av
)) > 0)
2697 else if ((pe
= getprotobyname(av
)) != NULL
)
2698 proto
= pe
->p_proto
;
2701 if (proto
!= IPPROTO_IP
)
2702 fill_cmd(cmd
, O_PROTO
, 0, proto
);
2707 add_srcip(ipfw_insn
*cmd
, char *av
)
2709 fill_ip((ipfw_insn_ip
*)cmd
, av
);
2710 if (cmd
->opcode
== O_IP_DST_SET
) /* set */
2711 cmd
->opcode
= O_IP_SRC_SET
;
2712 else if (F_LEN(cmd
) == F_INSN_SIZE(ipfw_insn
)) /* me */
2713 cmd
->opcode
= O_IP_SRC_ME
;
2714 else if (F_LEN(cmd
) == F_INSN_SIZE(ipfw_insn_u32
)) /* one IP */
2715 cmd
->opcode
= O_IP_SRC
;
2716 else /* addr/mask */
2717 cmd
->opcode
= O_IP_SRC_MASK
;
2722 add_dstip(ipfw_insn
*cmd
, char *av
)
2724 fill_ip((ipfw_insn_ip
*)cmd
, av
);
2725 if (cmd
->opcode
== O_IP_DST_SET
) /* set */
2727 else if (F_LEN(cmd
) == F_INSN_SIZE(ipfw_insn
)) /* me */
2728 cmd
->opcode
= O_IP_DST_ME
;
2729 else if (F_LEN(cmd
) == F_INSN_SIZE(ipfw_insn_u32
)) /* one IP */
2730 cmd
->opcode
= O_IP_DST
;
2731 else /* addr/mask */
2732 cmd
->opcode
= O_IP_DST_MASK
;
2737 add_ports(ipfw_insn
*cmd
, char *av
, u_char proto
, int opcode
)
2739 if (!strncmp(av
, "any", strlen(av
))) {
2741 } else if (fill_newports((ipfw_insn_u16
*)cmd
, av
, proto
)) {
2742 /* XXX todo: check that we have a protocol with ports */
2743 cmd
->opcode
= opcode
;
2750 * Parse arguments and assemble the microinstructions which make up a rule.
2751 * Rules are added into the 'rulebuf' and then copied in the correct order
2752 * into the actual rule.
2754 * The syntax for a rule starts with the action, followed by an
2755 * optional log action, and the various match patterns.
2756 * In the assembled microcode, the first opcode must be an O_PROBE_STATE
2757 * (generated if the rule includes a keep-state option), then the
2758 * various match patterns, the "log" action, and the actual action.
2762 add(int ac
, char *av
[])
2765 * rules are added into the 'rulebuf' and then copied in
2766 * the correct order into the actual rule.
2767 * Some things that need to go out of order (prob, action etc.)
2770 static uint32_t rulebuf
[255], actbuf
[255], cmdbuf
[255];
2772 ipfw_insn
*src
, *dst
, *cmd
, *action
, *prev
=NULL
;
2773 ipfw_insn
*first_cmd
; /* first match pattern */
2778 * various flags used to record that we entered some fields.
2780 ipfw_insn
*have_state
= NULL
; /* check-state or keep-state */
2784 int open_par
= 0; /* open parenthesis ( */
2786 /* proto is here because it is used to fetch ports */
2787 u_char proto
= IPPROTO_IP
; /* default protocol */
2789 double match_prob
= 1; /* match probability, default is always match */
2791 bzero(actbuf
, sizeof(actbuf
)); /* actions go here */
2792 bzero(cmdbuf
, sizeof(cmdbuf
));
2793 bzero(rulebuf
, sizeof(rulebuf
));
2795 rule
= (struct ip_fw
*)rulebuf
;
2796 cmd
= (ipfw_insn
*)cmdbuf
;
2797 action
= (ipfw_insn
*)actbuf
;
2801 /* [rule N] -- Rule number optional */
2802 if (ac
&& isdigit(**av
)) {
2803 rule
->rulenum
= atoi(*av
);
2808 /* [set N] -- set number (0..RESVD_SET), optional */
2809 if (ac
> 1 && !strncmp(*av
, "set", strlen(*av
))) {
2810 int set
= strtoul(av
[1], NULL
, 10);
2811 if (set
< 0 || set
> RESVD_SET
)
2812 errx(EX_DATAERR
, "illegal set %s", av
[1]);
2817 /* [prob D] -- match probability, optional */
2818 if (ac
> 1 && !strncmp(*av
, "prob", strlen(*av
))) {
2819 match_prob
= strtod(av
[1], NULL
);
2821 if (match_prob
<= 0 || match_prob
> 1)
2822 errx(EX_DATAERR
, "illegal match prob. %s", av
[1]);
2826 /* action -- mandatory */
2827 NEED1("missing action");
2828 i
= match_token(rule_actions
, *av
);
2830 action
->len
= 1; /* default */
2832 case TOK_CHECKSTATE
:
2833 have_state
= action
;
2834 action
->opcode
= O_CHECK_STATE
;
2838 action
->opcode
= O_ACCEPT
;
2842 action
->opcode
= O_DENY
;
2847 action
->opcode
= O_REJECT
;
2848 action
->arg1
= ICMP_UNREACH_HOST
;
2852 action
->opcode
= O_REJECT
;
2853 action
->arg1
= ICMP_REJECT_RST
;
2857 action
->opcode
= O_REJECT
;
2858 NEED1("missing reject code");
2859 fill_reject_code(&action
->arg1
, *av
);
2864 action
->opcode
= O_COUNT
;
2869 action
->len
= F_INSN_SIZE(ipfw_insn_pipe
);
2872 action
->opcode
= O_QUEUE
;
2873 else if (i
== TOK_PIPE
)
2874 action
->opcode
= O_PIPE
;
2875 else if (i
== TOK_SKIPTO
)
2876 action
->opcode
= O_SKIPTO
;
2877 NEED1("missing skipto/pipe/queue number");
2878 action
->arg1
= strtoul(*av
, NULL
, 10);
2884 action
->opcode
= (i
== TOK_DIVERT
) ? O_DIVERT
: O_TEE
;
2885 NEED1("missing divert/tee port");
2886 action
->arg1
= strtoul(*av
, NULL
, 0);
2887 if (action
->arg1
== 0) {
2890 s
= getservbyname(av
[0], "divert");
2892 action
->arg1
= ntohs(s
->s_port
);
2894 errx(EX_DATAERR
, "illegal divert/tee port");
2900 ipfw_insn_sa
*p
= (ipfw_insn_sa
*)action
;
2903 NEED1("missing forward address[:port]");
2905 action
->opcode
= O_FORWARD_IP
;
2906 action
->len
= F_INSN_SIZE(ipfw_insn_sa
);
2908 p
->sa
.sin_len
= sizeof(struct sockaddr_in
);
2909 p
->sa
.sin_family
= AF_INET
;
2912 * locate the address-port separator (':' or ',')
2914 s
= strchr(*av
, ':');
2916 s
= strchr(*av
, ',');
2919 i
= strtoport(s
, &end
, 0 /* base */, 0 /* proto */);
2922 "illegal forwarding port ``%s''", s
);
2923 p
->sa
.sin_port
= (u_short
)i
;
2925 lookup_host(*av
, &(p
->sa
.sin_addr
));
2931 /* pretend it is a 'count' rule followed by the comment */
2932 action
->opcode
= O_COUNT
;
2933 ac
++; av
--; /* go back... */
2937 errx(EX_DATAERR
, "invalid action %s\n", av
[-1]);
2939 action
= next_cmd(action
);
2942 * [log [logamount N]] -- log, optional
2944 * If exists, it goes first in the cmdbuf, but then it is
2945 * skipped in the copy section to the end of the buffer.
2947 if (ac
&& !strncmp(*av
, "log", strlen(*av
))) {
2948 ipfw_insn_log
*c
= (ipfw_insn_log
*)cmd
;
2951 cmd
->len
= F_INSN_SIZE(ipfw_insn_log
);
2952 cmd
->opcode
= O_LOG
;
2954 if (ac
&& !strncmp(*av
, "logamount", strlen(*av
))) {
2956 NEED1("logamount requires argument");
2959 errx(EX_DATAERR
, "logamount must be positive");
2963 cmd
= next_cmd(cmd
);
2966 if (have_state
) /* must be a check-state, we are done */
2969 #define OR_START(target) \
2970 if (ac && (*av[0] == '(' || *av[0] == '{')) { \
2972 errx(EX_USAGE, "nested \"(\" not allowed\n"); \
2975 if ( (av[0])[1] == '\0') { \
2986 !strncmp(*av, ")", strlen(*av)) || \
2987 !strncmp(*av, "}", strlen(*av)) )) { \
2992 errx(EX_USAGE, "missing \")\"\n"); \
2996 if (ac && !strncmp(*av, "not", strlen(*av))) { \
2997 if (cmd->len & F_NOT) \
2998 errx(EX_USAGE, "double \"not\" not allowed\n"); \
2999 cmd->len |= F_NOT; \
3003 #define OR_BLOCK(target) \
3004 if (ac && !strncmp(*av, "or", strlen(*av))) { \
3005 if (prev == NULL || open_par == 0) \
3006 errx(EX_DATAERR, "invalid OR block"); \
3007 prev->len |= F_OR; \
3017 * MAC addresses, optional.
3018 * If we have this, we skip the part "proto from src to dst"
3019 * and jump straight to the option parsing.
3022 NEED1("missing protocol");
3023 if (!strncmp(*av
, "MAC", strlen(*av
)) ||
3024 !strncmp(*av
, "mac", strlen(*av
))) {
3025 ac
--; av
++; /* the "MAC" keyword */
3026 add_mac(cmd
, ac
, av
); /* exits in case of errors */
3027 cmd
= next_cmd(cmd
);
3028 ac
-= 2; av
+= 2; /* dst-mac and src-mac */
3030 NEED1("missing mac type");
3031 if (add_mactype(cmd
, ac
, av
[0]))
3032 cmd
= next_cmd(cmd
);
3033 ac
--; av
++; /* any or mac-type */
3039 * protocol, mandatory
3041 OR_START(get_proto
);
3043 NEED1("missing protocol");
3044 if (add_proto(cmd
, *av
)) {
3046 if (F_LEN(cmd
) == 0) /* plain IP */
3051 cmd
= next_cmd(cmd
);
3053 } else if (first_cmd
!= cmd
) {
3054 errx(EX_DATAERR
, "invalid protocol ``%s''", *av
);
3057 OR_BLOCK(get_proto
);
3062 if (!ac
|| strncmp(*av
, "from", strlen(*av
)))
3063 errx(EX_USAGE
, "missing ``from''");
3067 * source IP, mandatory
3069 OR_START(source_ip
);
3070 NOT_BLOCK
; /* optional "not" */
3071 NEED1("missing source address");
3072 if (add_srcip(cmd
, *av
)) {
3074 if (F_LEN(cmd
) != 0) { /* ! any */
3076 cmd
= next_cmd(cmd
);
3079 OR_BLOCK(source_ip
);
3082 * source ports, optional
3084 NOT_BLOCK
; /* optional "not" */
3086 if (!strncmp(*av
, "any", strlen(*av
)) ||
3087 add_ports(cmd
, *av
, proto
, O_IP_SRCPORT
)) {
3089 if (F_LEN(cmd
) != 0)
3090 cmd
= next_cmd(cmd
);
3097 if (!ac
|| strncmp(*av
, "to", strlen(*av
)))
3098 errx(EX_USAGE
, "missing ``to''");
3102 * destination, mandatory
3105 NOT_BLOCK
; /* optional "not" */
3106 NEED1("missing dst address");
3107 if (add_dstip(cmd
, *av
)) {
3109 if (F_LEN(cmd
) != 0) { /* ! any */
3111 cmd
= next_cmd(cmd
);
3117 * dest. ports, optional
3119 NOT_BLOCK
; /* optional "not" */
3121 if (!strncmp(*av
, "any", strlen(*av
)) ||
3122 add_ports(cmd
, *av
, proto
, O_IP_DSTPORT
)) {
3124 if (F_LEN(cmd
) != 0)
3125 cmd
= next_cmd(cmd
);
3130 if (ac
&& first_cmd
== cmd
) {
3132 * nothing specified so far, store in the rule to ease
3140 ipfw_insn_u32
*cmd32
; /* alias for cmd */
3143 cmd32
= (ipfw_insn_u32
*)cmd
;
3145 if (*s
== '!') { /* alternate syntax for NOT */
3146 if (cmd
->len
& F_NOT
)
3147 errx(EX_USAGE
, "double \"not\" not allowed\n");
3151 i
= match_token(rule_options
, s
);
3155 if (cmd
->len
& F_NOT
)
3156 errx(EX_USAGE
, "double \"not\" not allowed\n");
3161 if (open_par
== 0 || prev
== NULL
)
3162 errx(EX_USAGE
, "invalid \"or\" block\n");
3166 case TOK_STARTBRACE
:
3168 errx(EX_USAGE
, "+nested \"(\" not allowed\n");
3174 errx(EX_USAGE
, "+missing \")\"\n");
3180 fill_cmd(cmd
, O_IN
, 0, 0);
3184 cmd
->len
^= F_NOT
; /* toggle F_NOT */
3185 fill_cmd(cmd
, O_IN
, 0, 0);
3189 fill_cmd(cmd
, O_FRAG
, 0, 0);
3193 fill_cmd(cmd
, O_LAYER2
, 0, 0);
3199 NEED1("recv, xmit, via require interface name"
3201 fill_iface((ipfw_insn_if
*)cmd
, av
[0]);
3203 if (F_LEN(cmd
) == 0) /* not a valid address */
3206 cmd
->opcode
= O_XMIT
;
3207 else if (i
== TOK_RECV
)
3208 cmd
->opcode
= O_RECV
;
3209 else if (i
== TOK_VIA
)
3210 cmd
->opcode
= O_VIA
;
3214 NEED1("icmptypes requires list of types");
3215 fill_icmptypes((ipfw_insn_u32
*)cmd
, *av
);
3220 NEED1("ipttl requires TTL");
3221 if (strpbrk(*av
, "-,")) {
3222 if (!add_ports(cmd
, *av
, 0, O_IPTTL
))
3223 errx(EX_DATAERR
, "invalid ipttl %s", *av
);
3225 fill_cmd(cmd
, O_IPTTL
, 0, strtoul(*av
, NULL
, 0));
3230 NEED1("ipid requires id");
3231 if (strpbrk(*av
, "-,")) {
3232 if (!add_ports(cmd
, *av
, 0, O_IPID
))
3233 errx(EX_DATAERR
, "invalid ipid %s", *av
);
3235 fill_cmd(cmd
, O_IPID
, 0, strtoul(*av
, NULL
, 0));
3240 NEED1("iplen requires length");
3241 if (strpbrk(*av
, "-,")) {
3242 if (!add_ports(cmd
, *av
, 0, O_IPLEN
))
3243 errx(EX_DATAERR
, "invalid ip len %s", *av
);
3245 fill_cmd(cmd
, O_IPLEN
, 0, strtoul(*av
, NULL
, 0));
3250 NEED1("ipver requires version");
3251 fill_cmd(cmd
, O_IPVER
, 0, strtoul(*av
, NULL
, 0));
3255 case TOK_IPPRECEDENCE
:
3256 NEED1("ipprecedence requires value");
3257 fill_cmd(cmd
, O_IPPRECEDENCE
, 0,
3258 (strtoul(*av
, NULL
, 0) & 7) << 5);
3263 NEED1("missing argument for ipoptions");
3264 fill_flags(cmd
, O_IPOPT
, f_ipopts
, *av
);
3269 NEED1("missing argument for iptos");
3270 fill_flags(cmd
, O_IPTOS
, f_iptos
, *av
);
3275 NEED1("uid requires argument");
3281 cmd
->opcode
= O_UID
;
3282 uid
= strtoul(*av
, &end
, 0);
3283 pwd
= (*end
== '\0') ? getpwuid(uid
) : getpwnam(*av
);
3285 errx(EX_DATAERR
, "uid \"%s\" nonexistent", *av
);
3286 cmd32
->d
[0] = pwd
->pw_uid
;
3287 cmd
->len
= F_INSN_SIZE(ipfw_insn_u32
);
3293 NEED1("gid requires argument");
3299 cmd
->opcode
= O_GID
;
3300 gid
= strtoul(*av
, &end
, 0);
3301 grp
= (*end
== '\0') ? getgrgid(gid
) : getgrnam(*av
);
3303 errx(EX_DATAERR
, "gid \"%s\" nonexistent", *av
);
3304 cmd32
->d
[0] = grp
->gr_gid
;
3305 cmd
->len
= F_INSN_SIZE(ipfw_insn_u32
);
3311 fill_cmd(cmd
, O_ESTAB
, 0, 0);
3315 fill_cmd(cmd
, O_TCPFLAGS
, 0,
3316 (TH_SYN
) | ( (TH_ACK
) & 0xff) <<8 );
3320 NEED1("missing argument for tcpoptions");
3321 fill_flags(cmd
, O_TCPOPTS
, f_tcpopts
, *av
);
3327 NEED1("tcpseq/tcpack requires argument");
3328 cmd
->len
= F_INSN_SIZE(ipfw_insn_u32
);
3329 cmd
->opcode
= (i
== TOK_TCPSEQ
) ? O_TCPSEQ
: O_TCPACK
;
3330 cmd32
->d
[0] = htonl(strtoul(*av
, NULL
, 0));
3335 NEED1("tcpwin requires length");
3336 fill_cmd(cmd
, O_TCPWIN
, 0,
3337 htons(strtoul(*av
, NULL
, 0)));
3342 NEED1("missing argument for tcpflags");
3343 cmd
->opcode
= O_TCPFLAGS
;
3344 fill_flags(cmd
, O_TCPFLAGS
, f_tcpflags
, *av
);
3350 errx(EX_USAGE
, "keep-state cannot be part "
3353 errx(EX_USAGE
, "only one of keep-state "
3354 "and limit is allowed");
3356 fill_cmd(cmd
, O_KEEP_STATE
, 0, 0);
3361 errx(EX_USAGE
, "limit cannot be part "
3364 errx(EX_USAGE
, "only one of keep-state "
3365 "and limit is allowed");
3366 NEED1("limit needs mask and # of connections");
3369 ipfw_insn_limit
*c
= (ipfw_insn_limit
*)cmd
;
3371 cmd
->len
= F_INSN_SIZE(ipfw_insn_limit
);
3372 cmd
->opcode
= O_LIMIT
;
3378 val
= match_token(limit_masks
, *av
);
3381 c
->limit_mask
|= val
;
3384 c
->conn_limit
= atoi(*av
);
3385 if (c
->conn_limit
== 0)
3386 errx(EX_USAGE
, "limit: limit must be >0");
3387 if (c
->limit_mask
== 0)
3388 errx(EX_USAGE
, "missing limit mask");
3394 NEED1("missing protocol");
3395 if (add_proto(cmd
, *av
)) {
3399 errx(EX_DATAERR
, "invalid protocol ``%s''",
3404 NEED1("missing source IP");
3405 if (add_srcip(cmd
, *av
)) {
3411 NEED1("missing destination IP");
3412 if (add_dstip(cmd
, *av
)) {
3418 NEED1("missing source port");
3419 if (!strncmp(*av
, "any", strlen(*av
)) ||
3420 add_ports(cmd
, *av
, proto
, O_IP_SRCPORT
)) {
3423 errx(EX_DATAERR
, "invalid source port %s", *av
);
3427 NEED1("missing destination port");
3428 if (!strncmp(*av
, "any", strlen(*av
)) ||
3429 add_ports(cmd
, *av
, proto
, O_IP_DSTPORT
)) {
3432 errx(EX_DATAERR
, "invalid destination port %s",
3438 errx(EX_USAGE
, "MAC dst-mac src-mac");
3439 if (add_mac(cmd
, ac
, av
)) {
3445 NEED1("missing mac type");
3446 if (!add_mactype(cmd
, ac
, *av
))
3447 errx(EX_DATAERR
, "invalid mac type %s", *av
);
3451 case TOK_VERREVPATH
:
3452 fill_cmd(cmd
, O_VERREVPATH
, 0, 0);
3456 fill_cmd(cmd
, O_IPSEC
, 0, 0);
3460 fill_comment(cmd
, ac
, av
);
3466 errx(EX_USAGE
, "unrecognised option [%d] %s\n", i
, s
);
3468 if (F_LEN(cmd
) > 0) { /* prepare to advance */
3470 cmd
= next_cmd(cmd
);
3476 * Now copy stuff into the rule.
3477 * If we have a keep-state option, the first instruction
3478 * must be a PROBE_STATE (which is generated here).
3479 * If we have a LOG option, it was stored as the first command,
3480 * and now must be moved to the top of the action part.
3482 dst
= (ipfw_insn
*)rule
->cmd
;
3485 * First thing to write into the command stream is the match probability.
3487 if (match_prob
!= 1) { /* 1 means always match */
3488 dst
->opcode
= O_PROB
;
3490 *((int32_t *)(dst
+1)) = (int32_t)(match_prob
* 0x7fffffff);
3495 * generate O_PROBE_STATE if necessary
3497 if (have_state
&& have_state
->opcode
!= O_CHECK_STATE
) {
3498 fill_cmd(dst
, O_PROBE_STATE
, 0, 0);
3499 dst
= next_cmd(dst
);
3502 * copy all commands but O_LOG, O_KEEP_STATE, O_LIMIT
3504 for (src
= (ipfw_insn
*)cmdbuf
; src
!= cmd
; src
+= i
) {
3507 switch (src
->opcode
) {
3513 bcopy(src
, dst
, i
* sizeof(uint32_t));
3519 * put back the have_state command as last opcode
3521 if (have_state
&& have_state
->opcode
!= O_CHECK_STATE
) {
3522 i
= F_LEN(have_state
);
3523 bcopy(have_state
, dst
, i
* sizeof(uint32_t));
3527 * start action section
3529 rule
->act_ofs
= dst
- rule
->cmd
;
3532 * put back O_LOG if necessary
3534 src
= (ipfw_insn
*)cmdbuf
;
3535 if (src
->opcode
== O_LOG
) {
3537 bcopy(src
, dst
, i
* sizeof(uint32_t));
3541 * copy all other actions
3543 for (src
= (ipfw_insn
*)actbuf
; src
!= action
; src
+= i
) {
3545 bcopy(src
, dst
, i
* sizeof(uint32_t));
3549 rule
->cmd_len
= (uint32_t *)dst
- (uint32_t *)(rule
->cmd
);
3550 i
= (char *)dst
- (char *)rule
;
3552 if (do_cmd(IP_FW_ADD
, rule
, (uintptr_t)&i
) == -1)
3553 err(EX_UNAVAILABLE
, "getsockopt(%s)", "IP_FW_ADD");
3555 show_ipfw(rule
, 0, 0);
3559 zero(int ac
, char *av
[], int optname
/* IP_FW_ZERO or IP_FW_RESETLOG */)
3564 char const *name
= optname
== IP_FW_ZERO
? "ZERO" : "RESETLOG";
3567 bzero(&rule
, sizeof(rule
));
3570 /* clear all entries - send empty rule */
3571 if (do_cmd(optname
, &rule
, sizeof(rule
)) < 0)
3572 err(EX_UNAVAILABLE
, "setsockopt(IP_FW_%s)", name
);
3574 printf("%s.\n", optname
== IP_FW_ZERO
?
3575 "Accounting cleared":"Logging counts reset");
3582 if (isdigit(**av
)) {
3583 rulenum
= atoi(*av
);
3586 rule
.rulenum
= rulenum
;
3587 if (do_cmd(optname
, &rule
, sizeof(rule
))) {
3588 warn("rule %u: setsockopt(IP_FW_%s)",
3590 failed
= EX_UNAVAILABLE
;
3591 } else if (!do_quiet
)
3592 printf("Entry %d %s.\n", rulenum
,
3593 optname
== IP_FW_ZERO
?
3594 "cleared" : "logging count reset");
3596 errx(EX_USAGE
, "invalid rule number ``%s''", *av
);
3599 if (failed
!= EX_OK
)
3606 int cmd
= do_pipe
? IP_DUMMYNET_FLUSH
: IP_FW_FLUSH
;
3609 if (!force
&& !do_quiet
) { /* need to ask user */
3612 printf("Are you sure? [yn] ");
3615 c
= toupper(getc(stdin
));
3616 while (c
!= '\n' && getc(stdin
) != '\n')
3618 return; /* and do not flush */
3619 } while (c
!= 'Y' && c
!= 'N');
3621 if (c
== 'N') /* user said no */
3625 if (cmd
== IP_FW_FLUSH
) {
3626 /* send empty rule */
3627 bzero(&rule
, sizeof(rule
));
3628 if (do_cmd(cmd
, &rule
, sizeof(rule
)) < 0)
3629 err(EX_UNAVAILABLE
, "setsockopt(IP_FW_FLUSH)");
3632 if (do_cmd(cmd
, NULL
, 0) < 0)
3633 err(EX_UNAVAILABLE
, "setsockopt(IP_DUMMYNET_FLUSH)");
3636 printf("Flushed all %s.\n", do_pipe
? "pipes" : "rules");
3640 * Free a the (locally allocated) copy of command line arguments.
3643 free_args(int ac
, char **av
)
3647 for (i
=0; i
< ac
; i
++)
3653 * Called with the arguments (excluding program name).
3654 * Returns 0 if successful, 1 if empty command, errx() in case of errors.
3657 ipfw_main(int oldac
, char **oldav
)
3659 int ch
, ac
, save_ac
;
3660 char **av
, **save_av
;
3661 int do_acct
= 0; /* Show packet/byte count */
3662 int do_force
= 0; /* Don't ask for confirmation */
3664 #define WHITESP " \t\f\v\n\r"
3667 else if (oldac
== 1) {
3669 * If we are called with a single string, try to split it into
3670 * arguments for subsequent parsing.
3671 * But first, remove spaces after a ',', by copying the string
3674 char *arg
= oldav
[0]; /* The string... */
3675 int l
= strlen(arg
);
3676 int copy
= 0; /* 1 if we need to copy, 0 otherwise */
3678 for (i
= j
= 0; i
< l
; i
++) {
3679 if (arg
[i
] == '#') /* comment marker */
3683 copy
= !index("," WHITESP
, arg
[i
]);
3685 copy
= !index(WHITESP
, arg
[i
]);
3690 if (!copy
&& j
> 0) /* last char was a 'blank', remove it */
3692 l
= j
; /* the new argument length */
3694 if (l
== 0) /* empty string! */
3698 * First, count number of arguments. Because of the previous
3699 * processing, this is just the number of blanks plus 1.
3701 for (i
= 0, ac
= 1; i
< l
; i
++)
3702 if (index(WHITESP
, arg
[i
]) != NULL
)
3705 av
= calloc(ac
, sizeof(char *));
3708 * Second, copy arguments from cmd[] to av[]. For each one,
3709 * j is the initial character, i is the one past the end.
3711 for (ac
= 0, i
= j
= 0; i
< l
; i
++)
3712 if (index(WHITESP
, arg
[i
]) != NULL
|| i
== l
-1) {
3715 av
[ac
] = calloc(i
-j
+1, 1);
3716 bcopy(arg
+j
, av
[ac
], i
-j
);
3722 * If an argument ends with ',' join with the next one.
3726 av
= calloc(oldac
, sizeof(char *));
3727 for (first
= i
= ac
= 0, l
= 0; i
< oldac
; i
++) {
3728 char *arg
= oldav
[i
];
3729 int k
= strlen(arg
);
3732 if (arg
[k
-1] != ',' || i
== oldac
-1) {
3734 av
[ac
] = calloc(l
+1, 1);
3735 for (l
=0; first
<= i
; first
++) {
3736 strcat(av
[ac
]+l
, oldav
[first
]);
3737 l
+= strlen(oldav
[first
]);
3746 /* Set the force flag for non-interactive processes */
3747 do_force
= !isatty(STDIN_FILENO
);
3749 /* Save arguments for final freeing of memory. */
3753 optind
= optreset
= 0;
3754 while ((ch
= getopt(ac
, av
, "acdefhnNqs:STtv")) != -1)
3776 case 'h': /* help */
3777 free_args(save_ac
, save_av
);
3779 break; /* NOTREACHED */
3793 case 's': /* sort */
3794 do_sort
= atoi(optarg
);
3806 do_time
= 2; /* numeric timestamp */
3809 case 'v': /* verbose */
3814 free_args(save_ac
, save_av
);
3820 NEED1("bad arguments, for usage summary ``ipfw''");
3823 * An undocumented behaviour of ipfw1 was to allow rule numbers first,
3824 * e.g. "100 add allow ..." instead of "add 100 allow ...".
3825 * In case, swap first and second argument to get the normal form.
3827 if (ac
> 1 && isdigit(*av
[0])) {
3835 * optional: pipe or queue
3838 if (!strncmp(*av
, "pipe", strlen(*av
)))
3840 else if (!strncmp(*av
, "queue", strlen(*av
)))
3846 NEED1("missing command");
3849 * For pipes and queues we normally say 'pipe NN config'
3850 * but the code is easier to parse as 'pipe config NN'
3851 * so we swap the two arguments.
3853 if (do_pipe
> 0 && ac
> 1 && isdigit(*av
[0])) {
3860 if (!strncmp(*av
, "add", strlen(*av
)))
3862 else if (do_pipe
&& !strncmp(*av
, "config", strlen(*av
)))
3863 config_pipe(ac
, av
);
3864 else if (!strncmp(*av
, "delete", strlen(*av
)))
3866 else if (!strncmp(*av
, "flush", strlen(*av
)))
3868 else if (!strncmp(*av
, "zero", strlen(*av
)))
3869 zero(ac
, av
, IP_FW_ZERO
);
3870 else if (!strncmp(*av
, "resetlog", strlen(*av
)))
3871 zero(ac
, av
, IP_FW_RESETLOG
);
3872 else if (!strncmp(*av
, "print", strlen(*av
)) ||
3873 !strncmp(*av
, "list", strlen(*av
)))
3874 list(ac
, av
, do_acct
);
3875 else if (!strncmp(*av
, "set", strlen(*av
)))
3876 sets_handler(ac
, av
);
3877 else if (!strncmp(*av
, "enable", strlen(*av
)))
3878 sysctl_handler(ac
, av
, 1);
3879 else if (!strncmp(*av
, "disable", strlen(*av
)))
3880 sysctl_handler(ac
, av
, 0);
3881 else if (!strncmp(*av
, "show", strlen(*av
)))
3882 list(ac
, av
, 1 /* show counters */);
3884 errx(EX_USAGE
, "bad command `%s'", *av
);
3886 /* Free memory allocated in the argument parsing. */
3887 free_args(save_ac
, save_av
);
3893 ipfw_readfile(int ac
, char *av
[])
3897 char *cmd
= NULL
, *filename
= av
[ac
-1];
3902 filename
= av
[ac
-1];
3904 while ((c
= getopt(ac
, av
, "cNnp:qS")) != -1) {
3921 * Skip previous args and delete last one, so we
3922 * pass all but the last argument to the preprocessor
3928 fprintf(stderr
, "command is %s\n", av
[0]);
3940 errx(EX_USAGE
, "bad arguments, for usage"
3941 " summary ``ipfw''");
3948 if (cmd
== NULL
&& ac
!= optind
+ 1) {
3949 fprintf(stderr
, "ac %d, optind %d\n", ac
, optind
);
3950 errx(EX_USAGE
, "extraneous filename arguments");
3953 if ((f
= fopen(filename
, "r")) == NULL
)
3954 err(EX_UNAVAILABLE
, "fopen: %s", filename
);
3956 if (cmd
!= NULL
) { /* pipe through preprocessor */
3959 if (pipe(pipedes
) == -1)
3960 err(EX_OSERR
, "cannot create pipe");
3964 err(EX_OSERR
, "cannot fork");
3968 * Child, will run the preprocessor with the
3969 * file on stdin and the pipe on stdout.
3971 if (dup2(fileno(f
), 0) == -1
3972 || dup2(pipedes
[1], 1) == -1)
3973 err(EX_OSERR
, "dup2()");
3978 err(EX_OSERR
, "execvp(%s) failed", cmd
);
3979 } else { /* parent, will reopen f as the pipe */
3982 if ((f
= fdopen(pipedes
[0], "r")) == NULL
) {
3983 int savederrno
= errno
;
3985 (void)kill(preproc
, SIGTERM
);
3987 err(EX_OSERR
, "fdopen()");
3992 while (fgets(buf
, BUFSIZ
, f
)) { /* read commands */
3997 sprintf(linename
, "Line %d", lineno
);
3998 setprogname(linename
); /* XXX */
4006 if (waitpid(preproc
, &status
, 0) == -1)
4007 errx(EX_OSERR
, "waitpid()");
4008 if (WIFEXITED(status
) && WEXITSTATUS(status
) != EX_OK
)
4009 errx(EX_UNAVAILABLE
,
4010 "preprocessor exited with status %d",
4011 WEXITSTATUS(status
));
4012 else if (WIFSIGNALED(status
))
4013 errx(EX_UNAVAILABLE
,
4014 "preprocessor exited with signal %d",
4020 main(int ac
, char *av
[])
4023 * If the last argument is an absolute pathname, interpret it
4024 * as a file to be preprocessed.
4027 if (ac
> 1 && av
[ac
- 1][0] == '/' && access(av
[ac
- 1], R_OK
) == 0)
4028 ipfw_readfile(ac
, av
);
4030 if (ipfw_main(ac
-1, av
+1))