2 * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 * Copyright (c) 2002-2003 Luigi Rizzo
25 * Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp
26 * Copyright (c) 1994 Ugen J.S.Antsilevich
28 * Idea and grammar partially left from:
29 * Copyright (c) 1993 Daniel Boulet
31 * Redistribution and use in source forms, with and without modification,
32 * are permitted provided that this entire comment appears intact.
34 * Redistribution in binary form may occur without any restrictions.
35 * Obviously, it would be nice if you gave credit where credit is due
36 * but requiring it would be too onerous.
38 * This software is provided ``AS IS'' without any warranties of any kind.
40 * NEW command line interface for IP firewall facility
42 * $FreeBSD: /repoman/r/ncvs/src/sbin/ipfw/ipfw2.c,v 1.4.2.18 2003/09/15 10:27:03 luigi Exp $
45 #include <sys/param.h>
47 #include <sys/socket.h>
48 #include <sys/sockio.h>
49 #include <sys/sysctl.h>
69 #include <netinet/in.h>
70 #include <netinet/in_systm.h>
71 #include <netinet/ip.h>
72 #include <netinet/ip_icmp.h>
74 #include <netinet/ip_fw.h>
76 #include <net/route.h> /* def. of struct route */
77 #include <netinet/ip_dummynet.h>
78 #include <netinet/tcp.h>
79 #include <arpa/inet.h>
82 do_resolv
, /* Would try to resolve all */
83 do_time
, /* Show time stamps */
84 do_quiet
, /* Be quiet in add and flush */
85 do_pipe
, /* this cmd refers to a pipe */
86 do_sort
, /* field to sort results (0 = no) */
87 do_dynamic
, /* display dynamic rules */
88 do_expired
, /* display expired dynamic rules */
89 do_compact
, /* show rules in compact mode */
90 show_sets
, /* display rule sets */
91 test_only
, /* only check syntax */
94 #define IP_MASK_ALL 0xffffffff
97 * _s_x is a structure that stores a string <-> token pairs, used in
98 * various places in the parser. Entries are stored in arrays,
99 * with an entry with s=NULL as terminator.
100 * The search routines are match_token() and match_value().
101 * Often, an element with x=0 contains an error string.
109 static struct _s_x f_tcpflags
[] = {
120 static struct _s_x f_tcpopts
[] = {
121 { "mss", IP_FW_TCPOPT_MSS
},
122 { "maxseg", IP_FW_TCPOPT_MSS
},
123 { "window", IP_FW_TCPOPT_WINDOW
},
124 { "sack", IP_FW_TCPOPT_SACK
},
125 { "ts", IP_FW_TCPOPT_TS
},
126 { "timestamp", IP_FW_TCPOPT_TS
},
127 { "cc", IP_FW_TCPOPT_CC
},
133 * IP options span the range 0 to 255 so we need to remap them
134 * (though in fact only the low 5 bits are significant).
136 static struct _s_x f_ipopts
[] = {
137 { "ssrr", IP_FW_IPOPT_SSRR
},
138 { "lsrr", IP_FW_IPOPT_LSRR
},
139 { "rr", IP_FW_IPOPT_RR
},
140 { "ts", IP_FW_IPOPT_TS
},
145 static struct _s_x f_iptos
[] = {
146 { "lowdelay", IPTOS_LOWDELAY
},
147 { "throughput", IPTOS_THROUGHPUT
},
148 { "reliability", IPTOS_RELIABILITY
},
149 { "mincost", IPTOS_MINCOST
},
150 { "congestion", IPTOS_CE
},
151 { "ecntransport", IPTOS_ECT
},
152 { "ip tos option", 0},
156 static struct _s_x limit_masks
[] = {
157 {"all", DYN_SRC_ADDR
|DYN_SRC_PORT
|DYN_DST_ADDR
|DYN_DST_PORT
},
158 {"src-addr", DYN_SRC_ADDR
},
159 {"src-port", DYN_SRC_PORT
},
160 {"dst-addr", DYN_DST_ADDR
},
161 {"dst-port", DYN_DST_PORT
},
166 * we use IPPROTO_ETHERTYPE as a fake protocol id to call the print routines
167 * This is only used in this code.
169 #define IPPROTO_ETHERTYPE 0x1000
170 static struct _s_x ether_types
[] = {
172 * Note, we cannot use "-:&/" in the names because they are field
173 * separators in the type specifications. Also, we use s = NULL as
174 * end-delimiter, because a type of 0 can be legal.
187 { "pppoe_disc", 0x8863 },
188 { "pppoe_sess", 0x8864 },
189 { "ipx_8022", 0x00E0 },
190 { "ipx_8023", 0x0000 },
191 { "ipx_ii", 0x8137 },
192 { "ipx_snap", 0x8137 },
198 static struct _s_x exception_types
[] = {
210 static void show_usage(void);
284 struct _s_x dummynet_params
[] = {
286 { "noerror", TOK_NOERROR
},
287 { "buckets", TOK_BUCKETS
},
288 { "dst-ip", TOK_DSTIP
},
289 { "src-ip", TOK_SRCIP
},
290 { "dst-port", TOK_DSTPORT
},
291 { "src-port", TOK_SRCPORT
},
292 { "proto", TOK_PROTO
},
293 { "weight", TOK_WEIGHT
},
295 { "mask", TOK_MASK
},
296 { "droptail", TOK_DROPTAIL
},
298 { "gred", TOK_GRED
},
300 { "bandwidth", TOK_BW
},
301 { "delay", TOK_DELAY
},
302 { "pipe", TOK_PIPE
},
303 { "queue", TOK_QUEUE
},
304 { "dummynet-params", TOK_NULL
},
305 { NULL
, 0 } /* terminator */
308 struct _s_x rule_actions
[] = {
309 { "accept", TOK_ACCEPT
},
310 { "pass", TOK_ACCEPT
},
311 { "allow", TOK_ACCEPT
},
312 { "permit", TOK_ACCEPT
},
313 { "count", TOK_COUNT
},
314 { "pipe", TOK_PIPE
},
315 { "queue", TOK_QUEUE
},
316 { "divert", TOK_DIVERT
},
318 { "fwd", TOK_FORWARD
},
319 { "forward", TOK_FORWARD
},
320 { "skipto", TOK_SKIPTO
},
321 { "deny", TOK_DENY
},
322 { "drop", TOK_DENY
},
323 { "reject", TOK_REJECT
},
324 { "reset", TOK_RESET
},
325 { "unreach", TOK_UNREACH
},
326 { "check-state", TOK_CHECKSTATE
},
327 { "//", TOK_COMMENT
},
328 { NULL
, 0 } /* terminator */
331 struct _s_x rule_options
[] = {
335 { "limit", TOK_LIMIT
},
336 { "keep-state", TOK_KEEPSTATE
},
337 { "bridged", TOK_LAYER2
},
338 { "layer2", TOK_LAYER2
},
340 { "xmit", TOK_XMIT
},
341 { "recv", TOK_RECV
},
343 { "fragment", TOK_FRAG
},
344 { "frag", TOK_FRAG
},
345 { "ipoptions", TOK_IPOPTS
},
346 { "ipopts", TOK_IPOPTS
},
347 { "iplen", TOK_IPLEN
},
348 { "ipid", TOK_IPID
},
349 { "ipprecedence", TOK_IPPRECEDENCE
},
350 { "iptos", TOK_IPTOS
},
351 { "ipttl", TOK_IPTTL
},
352 { "ipversion", TOK_IPVER
},
353 { "ipver", TOK_IPVER
},
354 { "estab", TOK_ESTAB
},
355 { "established", TOK_ESTAB
},
356 { "setup", TOK_SETUP
},
357 { "tcpflags", TOK_TCPFLAGS
},
358 { "tcpflgs", TOK_TCPFLAGS
},
359 { "tcpoptions", TOK_TCPOPTS
},
360 { "tcpopts", TOK_TCPOPTS
},
361 { "tcpseq", TOK_TCPSEQ
},
362 { "tcpack", TOK_TCPACK
},
363 { "tcpwin", TOK_TCPWIN
},
364 { "icmptype", TOK_ICMPTYPES
},
365 { "icmptypes", TOK_ICMPTYPES
},
366 { "dst-ip", TOK_DSTIP
},
367 { "src-ip", TOK_SRCIP
},
368 { "dst-port", TOK_DSTPORT
},
369 { "src-port", TOK_SRCPORT
},
370 { "proto", TOK_PROTO
},
373 { "mac-type", TOK_MACTYPE
},
374 { "verrevpath", TOK_VERREVPATH
},
375 { "ipsec", TOK_IPSEC
},
376 { "//", TOK_COMMENT
},
378 { "not", TOK_NOT
}, /* pseudo option */
379 { "!", /* escape ? */ TOK_NOT
}, /* pseudo option */
380 { "or", TOK_OR
}, /* pseudo option */
381 { "|", /* escape */ TOK_OR
}, /* pseudo option */
382 { "{", TOK_STARTBRACE
}, /* pseudo option */
383 { "(", TOK_STARTBRACE
}, /* pseudo option */
384 { "}", TOK_ENDBRACE
}, /* pseudo option */
385 { ")", TOK_ENDBRACE
}, /* pseudo option */
386 { NULL
, 0 } /* terminator */
389 static __inline
uint64_t
390 align_uint64(uint64_t *pll
) {
393 bcopy (pll
, &ret
, sizeof(ret
));
398 * conditionally runs the command.
401 do_cmd(int optname
, void *optval
, uintptr_t optlen
)
403 static int s
= -1; /* the socket */
410 s
= socket(AF_INET
, SOCK_RAW
, IPPROTO_RAW
);
412 err(EX_UNAVAILABLE
, "socket");
421 ((struct ip_fw
*)optval
)->version
= IP_FW_CURRENT_API_VERSION
;
426 if (optname
== IP_FW_GET
|| optname
== IP_DUMMYNET_GET
||
427 optname
== IP_FW_ADD
)
428 i
= getsockopt(s
, IPPROTO_IP
, optname
, optval
,
429 (socklen_t
*)optlen
);
431 i
= setsockopt(s
, IPPROTO_IP
, optname
, optval
, optlen
);
436 * match_token takes a table and a string, returns the value associated
437 * with the string (-1 in case of failure).
440 match_token(struct _s_x
*table
, char *string
)
443 uint i
= strlen(string
);
445 for (pt
= table
; i
&& pt
->s
!= NULL
; pt
++)
446 if (strlen(pt
->s
) == i
&& !bcmp(string
, pt
->s
, i
))
452 * match_value takes a table and a value, returns the string associated
453 * with the value (NULL in case of failure).
456 match_value(struct _s_x
*p
, int value
)
458 for (; p
->s
!= NULL
; p
++)
465 * prints one port, symbolic or numeric
468 print_port(int proto
, uint16_t port
)
471 if (proto
== IPPROTO_ETHERTYPE
) {
474 if (do_resolv
&& (s
= match_value(ether_types
, port
)) )
477 printf("0x%04x", port
);
479 struct servent
*se
= NULL
;
481 struct protoent
*pe
= getprotobynumber(proto
);
483 se
= getservbyport(htons(port
), pe
? pe
->p_name
: NULL
);
486 printf("%s", se
->s_name
);
492 struct _s_x _port_name
[] = {
493 {"dst-port", O_IP_DSTPORT
},
494 {"src-port", O_IP_SRCPORT
},
498 {"mac-type", O_MAC_TYPE
},
503 * Print the values in a list 16-bit items of the types above.
504 * XXX todo: add support for mask.
507 print_newports(ipfw_insn_u16
*cmd
, int proto
, int opcode
)
509 uint16_t *p
= cmd
->ports
;
513 if (cmd
->o
.len
& F_NOT
)
516 sep
= match_value(_port_name
, opcode
);
522 for (i
= F_LEN((ipfw_insn
*)cmd
) - 1; i
> 0; i
--, p
+= 2) {
524 print_port(proto
, p
[0]);
527 print_port(proto
, p
[1]);
534 * Like strtol, but also translates service names into port numbers
535 * for some protocols.
537 * proto == -1 disables the protocol check;
538 * proto == IPPROTO_ETHERTYPE looks up an internal table
539 * proto == <some value in /etc/protocols> matches the values there.
540 * Returns *end == s in case the parameter is not found.
543 strtoport(char *s
, char **end
, int base
, int proto
)
549 *end
= s
; /* default - not found */
551 return 0; /* not found */
554 return strtol(s
, end
, base
);
557 * find separator. '\\' escapes the next char.
559 for (s1
= s
; *s1
&& (isalnum(*s1
) || *s1
== '\\') ; s1
++)
560 if (*s1
== '\\' && s1
[1] != '\0')
563 buf
= malloc(s1
- s
+ 1);
568 * copy into a buffer skipping backslashes
570 for (p
= s
, i
= 0; p
!= s1
; p
++)
575 if ( match_token( exception_types
, buf
) != -1 ){
580 if (proto
== IPPROTO_ETHERTYPE
) {
581 i
= match_token(ether_types
, buf
);
583 if (i
!= -1) { /* found */
588 struct protoent
*pe
= NULL
;
592 pe
= getprotobynumber(proto
);
594 se
= getservbyname(buf
, pe
? pe
->p_name
: NULL
);
598 return ntohs(se
->s_port
);
601 return 0; /* not found */
605 * Fill the body of the command with the list of port ranges.
608 fill_newports(ipfw_insn_u16
*cmd
, char *av
, int proto
)
610 uint16_t a
, b
, *p
= cmd
->ports
;
615 a
= strtoport(av
, &s
, 0, proto
);
616 if (s
== av
) /* no parameter */
618 if (*s
== '-') { /* a range */
620 b
= strtoport(av
, &s
, 0, proto
);
621 if (s
== av
) /* no parameter */
625 } else if (*s
== ',' || *s
== '\0' )
627 else /* invalid separator */
628 errx(EX_DATAERR
, "invalid separator <%c> in <%s>\n",
635 if (i
+1 > F_LEN_MASK
)
636 errx(EX_DATAERR
, "too many ports/ranges\n");
637 cmd
->o
.len
|= i
+1; /* leave F_NOT and F_OR untouched */
642 static struct _s_x icmpcodes
[] = {
643 { "net", ICMP_UNREACH_NET
},
644 { "host", ICMP_UNREACH_HOST
},
645 { "protocol", ICMP_UNREACH_PROTOCOL
},
646 { "port", ICMP_UNREACH_PORT
},
647 { "needfrag", ICMP_UNREACH_NEEDFRAG
},
648 { "srcfail", ICMP_UNREACH_SRCFAIL
},
649 { "net-unknown", ICMP_UNREACH_NET_UNKNOWN
},
650 { "host-unknown", ICMP_UNREACH_HOST_UNKNOWN
},
651 { "isolated", ICMP_UNREACH_ISOLATED
},
652 { "net-prohib", ICMP_UNREACH_NET_PROHIB
},
653 { "host-prohib", ICMP_UNREACH_HOST_PROHIB
},
654 { "tosnet", ICMP_UNREACH_TOSNET
},
655 { "toshost", ICMP_UNREACH_TOSHOST
},
656 { "filter-prohib", ICMP_UNREACH_FILTER_PROHIB
},
657 { "host-precedence", ICMP_UNREACH_HOST_PRECEDENCE
},
658 { "precedence-cutoff", ICMP_UNREACH_PRECEDENCE_CUTOFF
},
663 fill_reject_code(u_short
*codep
, char *str
)
668 val
= strtoul(str
, &s
, 0);
669 if (s
== str
|| *s
!= '\0' || val
>= 0x100)
670 val
= match_token(icmpcodes
, str
);
672 errx(EX_DATAERR
, "unknown ICMP unreachable code ``%s''", str
);
678 print_reject_code(uint16_t code
)
680 char const *s
= match_value(icmpcodes
, code
);
683 printf("unreach %s", s
);
685 printf("unreach %u", code
);
689 * Returns the number of bits set (from left) in a contiguous bitmask,
690 * or -1 if the mask is not contiguous.
691 * XXX this needs a proper fix.
692 * This effectively works on masks in big-endian (network) format.
693 * when compiled on little endian architectures.
695 * First bit is bit 7 of the first byte -- note, for MAC addresses,
696 * the first bit on the wire is bit 0 of the first byte.
697 * len is the max length in bits.
700 contigmask(uint8_t *p
, int len
)
704 for (i
=0; i
<len
; i
++)
705 if ( (p
[i
/8] & (1 << (7 - (i%8
)))) == 0) /* first bit unset */
707 for (n
=i
+1; n
< len
; n
++)
708 if ( (p
[n
/8] & (1 << (7 - (n%8
)))) != 0)
709 return -1; /* mask not contiguous */
714 * print flags set/clear in the two bitmasks passed as parameters.
715 * There is a specialized check for f_tcpflags.
718 print_flags(char const *name
, ipfw_insn
*cmd
, struct _s_x
*list
)
720 char const *comma
= "";
722 uint8_t set
= cmd
->arg1
& 0xff;
723 uint8_t clear
= (cmd
->arg1
>> 8) & 0xff;
725 if (list
== f_tcpflags
&& set
== TH_SYN
&& clear
== TH_ACK
) {
730 printf(" %s ", name
);
731 for (i
=0; list
[i
].x
!= 0; i
++) {
732 if (set
& list
[i
].x
) {
734 printf("%s%s", comma
, list
[i
].s
);
737 if (clear
& list
[i
].x
) {
739 printf("%s!%s", comma
, list
[i
].s
);
746 * Print the ip address contained in a command.
749 print_ip(ipfw_insn_ip
*cmd
, char const *s
)
751 struct hostent
*he
= NULL
;
752 int len
= F_LEN((ipfw_insn
*)cmd
);
753 uint32_t *a
= ((ipfw_insn_u32
*)cmd
)->d
;
755 printf("%s%s ", cmd
->o
.len
& F_NOT
? " not": "", s
);
757 if (cmd
->o
.opcode
== O_IP_SRC_ME
|| cmd
->o
.opcode
== O_IP_DST_ME
) {
761 if (cmd
->o
.opcode
== O_IP_SRC_SET
|| cmd
->o
.opcode
== O_IP_DST_SET
) {
762 uint32_t x
, *map
= (uint32_t *)&(cmd
->mask
);
768 cmd
->addr
.s_addr
= htonl(cmd
->addr
.s_addr
);
769 printf("%s/%d", inet_ntoa(cmd
->addr
),
770 contigmask((uint8_t *)&x
, 32));
771 x
= cmd
->addr
.s_addr
= htonl(cmd
->addr
.s_addr
);
772 x
&= 0xff; /* base */
774 * Print bits and ranges.
775 * Locate first bit set (i), then locate first bit unset (j).
776 * If we have 3+ consecutive bits set, then print them as a
777 * range, otherwise only print the initial bit and rescan.
779 for (i
=0; i
< cmd
->o
.arg1
; i
++)
780 if (map
[i
/32] & (1<<(i
& 31))) {
781 for (j
=i
+1; j
< cmd
->o
.arg1
; j
++)
782 if (!(map
[ j
/32] & (1<<(j
& 31))))
784 printf("%c%d", comma
, i
+x
);
785 if (j
>i
+2) { /* range has at least 3 elements */
786 printf("-%d", j
-1+x
);
795 * len == 2 indicates a single IP, whereas lists of 1 or more
796 * addr/mask pairs have len = (2n+1). We convert len to n so we
797 * use that to count the number of entries.
799 for (len
= len
/ 2; len
> 0; len
--, a
+= 2) {
800 int mb
= /* mask length */
801 (cmd
->o
.opcode
== O_IP_SRC
|| cmd
->o
.opcode
== O_IP_DST
) ?
802 32 : contigmask((uint8_t *)&(a
[1]), 32);
803 if (mb
== 32 && do_resolv
)
804 he
= gethostbyaddr((char *)&(a
[0]), sizeof(u_long
), AF_INET
);
805 if (he
!= NULL
) /* resolved to name */
806 printf("%s", he
->h_name
);
807 else if (mb
== 0) /* any */
809 else { /* numeric IP followed by some kind of mask */
810 printf("%s", inet_ntoa( *((struct in_addr
*)&a
[0]) ) );
812 printf(":%s", inet_ntoa( *((struct in_addr
*)&a
[1]) ) );
822 * prints a MAC address/mask pair
825 print_mac(uint8_t *addr
, uint8_t *mask
)
827 int l
= contigmask(mask
, 48);
832 printf(" %02x:%02x:%02x:%02x:%02x:%02x",
833 addr
[0], addr
[1], addr
[2], addr
[3], addr
[4], addr
[5]);
835 printf("&%02x:%02x:%02x:%02x:%02x:%02x",
836 mask
[0], mask
[1], mask
[2],
837 mask
[3], mask
[4], mask
[5]);
844 fill_icmptypes(ipfw_insn_u32
*cmd
, char *av
)
853 type
= strtoul(av
, &av
, 0);
855 if (*av
!= ',' && *av
!= '\0')
856 errx(EX_DATAERR
, "invalid ICMP type");
859 errx(EX_DATAERR
, "ICMP type out of range");
861 cmd
->d
[0] |= 1 << type
;
863 cmd
->o
.opcode
= O_ICMPTYPE
;
864 cmd
->o
.len
|= F_INSN_SIZE(ipfw_insn_u32
);
868 print_icmptypes(ipfw_insn_u32
*cmd
)
873 printf(" icmptypes");
874 for (i
= 0; i
< 32; i
++) {
875 if ( (cmd
->d
[0] & (1 << (i
))) == 0)
877 printf("%c%d", sep
, i
);
883 * show_ipfw() prints the body of an ipfw rule.
884 * Because the standard rule has at least proto src_ip dst_ip, we use
885 * a helper function to produce these entries if not provided explicitly.
886 * The first argument is the list of fields we have, the second is
887 * the list of fields we want to be printed.
889 * Special cases if we have provided a MAC header:
890 * + if the rule does not contain IP addresses/ports, do not print them;
891 * + if the rule does not contain an IP proto, print "all" instead of "ip";
893 * Once we have 'have_options', IP header fields are printed as options.
895 #define HAVE_PROTO 0x0001
896 #define HAVE_SRCIP 0x0002
897 #define HAVE_DSTIP 0x0004
898 #define HAVE_MAC 0x0008
899 #define HAVE_MACTYPE 0x0010
900 #define HAVE_OPTIONS 0x8000
902 #define HAVE_IP (HAVE_PROTO | HAVE_SRCIP | HAVE_DSTIP)
904 show_prerequisites(int *flags
, int want
, int cmd
)
906 if ( (*flags
& HAVE_IP
) == HAVE_IP
)
907 *flags
|= HAVE_OPTIONS
;
909 if ( (*flags
& (HAVE_MAC
|HAVE_MACTYPE
|HAVE_OPTIONS
)) == HAVE_MAC
&&
912 * mac-type was optimized out by the compiler,
916 *flags
|= HAVE_MACTYPE
| HAVE_OPTIONS
;
919 if ( !(*flags
& HAVE_OPTIONS
)) {
920 if ( !(*flags
& HAVE_PROTO
) && (want
& HAVE_PROTO
))
922 if ( !(*flags
& HAVE_SRCIP
) && (want
& HAVE_SRCIP
))
924 if ( !(*flags
& HAVE_DSTIP
) && (want
& HAVE_DSTIP
))
931 show_ipfw(struct ip_fw
*rule
, int pcwidth
, int bcwidth
)
933 static int twidth
= 0;
936 char *comment
= NULL
; /* ptr to comment if we have one */
937 int proto
= 0; /* default */
938 int flags
= 0; /* prerequisites */
939 ipfw_insn_log
*logptr
= NULL
; /* set if we find an O_LOG */
940 int or_block
= 0; /* we are in an or block */
941 uint32_t set_disable
;
943 bcopy(&rule
->next_rule
, &set_disable
, sizeof(set_disable
));
945 if (set_disable
& (1 << rule
->set
)) { /* disabled */
949 printf("# DISABLED ");
951 printf("%05u ", rule
->rulenum
);
953 if (pcwidth
>0 || bcwidth
>0)
954 printf("%*llu %*llu ", pcwidth
, align_uint64(&rule
->pcnt
),
955 bcwidth
, align_uint64(&rule
->bcnt
));
958 printf("%10u ", rule
->timestamp
);
959 else if (do_time
== 1) {
961 time_t t
= (time_t)0;
964 strcpy(timestr
, ctime(&t
));
965 *strchr(timestr
, '\n') = '\0';
966 twidth
= strlen(timestr
);
968 if (rule
->timestamp
) {
969 #if _FreeBSD_version < 500000 /* XXX check */
970 #define _long_to_time(x) (time_t)(x)
972 t
= _long_to_time(rule
->timestamp
);
974 strcpy(timestr
, ctime(&t
));
975 *strchr(timestr
, '\n') = '\0';
976 printf("%s ", timestr
);
978 printf("%*s", twidth
, " ");
983 printf("set %d ", rule
->set
);
986 * print the optional "match probability"
988 if (rule
->cmd_len
> 0) {
990 if (cmd
->opcode
== O_PROB
) {
991 ipfw_insn_u32
*p
= (ipfw_insn_u32
*)cmd
;
992 double d
= 1.0 * p
->d
[0];
994 d
= (d
/ 0x7fffffff);
995 printf("prob %f ", d
);
1000 * first print actions
1002 for (l
= rule
->cmd_len
- rule
->act_ofs
, cmd
= ACTION_PTR(rule
);
1003 l
> 0 ; l
-= F_LEN(cmd
), cmd
+= F_LEN(cmd
)) {
1004 switch(cmd
->opcode
) {
1006 printf("check-state");
1007 flags
= HAVE_IP
; /* avoid printing anything else */
1023 if (cmd
->arg1
== ICMP_REJECT_RST
)
1025 else if (cmd
->arg1
== ICMP_UNREACH_HOST
)
1028 print_reject_code(cmd
->arg1
);
1032 printf("skipto %u", cmd
->arg1
);
1036 printf("pipe %u", cmd
->arg1
);
1040 printf("queue %u", cmd
->arg1
);
1044 printf("divert %u", cmd
->arg1
);
1048 printf("tee %u", cmd
->arg1
);
1053 ipfw_insn_sa
*s
= (ipfw_insn_sa
*)cmd
;
1055 printf("fwd %s", inet_ntoa(s
->sa
.sin_addr
));
1057 printf(",%d", s
->sa
.sin_port
);
1061 case O_LOG
: /* O_LOG is printed last */
1062 logptr
= (ipfw_insn_log
*)cmd
;
1066 printf("** unrecognized action %d len %d",
1067 cmd
->opcode
, cmd
->len
);
1071 if (logptr
->max_log
> 0)
1072 printf(" log logamount %d", logptr
->max_log
);
1078 * then print the body.
1080 if (rule
->_pad
& 1) { /* empty rules before options */
1082 printf(" ip from any to any");
1083 flags
|= HAVE_IP
| HAVE_OPTIONS
;
1086 for (l
= rule
->act_ofs
, cmd
= rule
->cmd
;
1087 l
> 0 ; l
-= F_LEN(cmd
) , cmd
+= F_LEN(cmd
)) {
1089 ipfw_insn_u32
*cmd32
= (ipfw_insn_u32
*)cmd
;
1091 show_prerequisites(&flags
, 0, cmd
->opcode
);
1093 switch(cmd
->opcode
) {
1095 break; /* done already */
1098 break; /* no need to print anything here */
1101 ipfw_insn_mac
*m
= (ipfw_insn_mac
*)cmd
;
1103 if ((cmd
->len
& F_OR
) && !or_block
)
1105 if (cmd
->len
& F_NOT
)
1109 print_mac(m
->addr
, m
->mask
);
1110 print_mac(m
->addr
+ 6, m
->mask
+ 6);
1115 if ((cmd
->len
& F_OR
) && !or_block
)
1117 print_newports((ipfw_insn_u16
*)cmd
, IPPROTO_ETHERTYPE
,
1118 (flags
& HAVE_OPTIONS
) ? cmd
->opcode
: 0);
1119 flags
|= HAVE_MAC
| HAVE_MACTYPE
| HAVE_OPTIONS
;
1126 show_prerequisites(&flags
, HAVE_PROTO
, 0);
1127 if (!(flags
& HAVE_SRCIP
))
1129 if ((cmd
->len
& F_OR
) && !or_block
)
1131 print_ip((ipfw_insn_ip
*)cmd
,
1132 (flags
& HAVE_OPTIONS
) ? " src-ip" : "");
1133 flags
|= HAVE_SRCIP
;
1140 show_prerequisites(&flags
, HAVE_PROTO
|HAVE_SRCIP
, 0);
1141 if (!(flags
& HAVE_DSTIP
))
1143 if ((cmd
->len
& F_OR
) && !or_block
)
1145 print_ip((ipfw_insn_ip
*)cmd
,
1146 (flags
& HAVE_OPTIONS
) ? " dst-ip" : "");
1147 flags
|= HAVE_DSTIP
;
1151 show_prerequisites(&flags
, HAVE_IP
, 0);
1153 show_prerequisites(&flags
, HAVE_PROTO
|HAVE_SRCIP
, 0);
1154 if ((cmd
->len
& F_OR
) && !or_block
)
1156 print_newports((ipfw_insn_u16
*)cmd
, proto
,
1157 (flags
& HAVE_OPTIONS
) ? cmd
->opcode
: 0);
1161 struct protoent
*pe
;
1163 if ((cmd
->len
& F_OR
) && !or_block
)
1165 if (cmd
->len
& F_NOT
)
1168 pe
= getprotobynumber(cmd
->arg1
);
1169 if (flags
& HAVE_OPTIONS
)
1172 printf(" %s", pe
->p_name
);
1174 printf(" %u", cmd
->arg1
);
1176 flags
|= HAVE_PROTO
;
1179 default: /*options ... */
1180 show_prerequisites(&flags
, HAVE_IP
| HAVE_OPTIONS
, 0);
1181 if ((cmd
->len
& F_OR
) && !or_block
)
1183 if (cmd
->len
& F_NOT
&& cmd
->opcode
!= O_IN
)
1185 switch(cmd
->opcode
) {
1191 printf(cmd
->len
& F_NOT
? " out" : " in");
1201 ipfw_insn_if
*cmdif
= (ipfw_insn_if
*)cmd
;
1203 if (cmd
->opcode
== O_XMIT
)
1205 else if (cmd
->opcode
== O_RECV
)
1207 else /* if (cmd->opcode == O_VIA) */
1209 if (cmdif
->name
[0] == '\0')
1211 inet_ntoa(cmdif
->p
.ip
));
1212 else if (cmdif
->p
.unit
== -1)
1213 printf(" %s %s*", s
, cmdif
->name
);
1215 printf(" %s %s%d", s
, cmdif
->name
,
1221 if (F_LEN(cmd
) == 1)
1222 printf(" ipid %u", cmd
->arg1
);
1224 print_newports((ipfw_insn_u16
*)cmd
, 0,
1229 if (F_LEN(cmd
) == 1)
1230 printf(" ipttl %u", cmd
->arg1
);
1232 print_newports((ipfw_insn_u16
*)cmd
, 0,
1237 printf(" ipver %u", cmd
->arg1
);
1240 case O_IPPRECEDENCE
:
1241 printf(" ipprecedence %u", (cmd
->arg1
) >> 5 );
1245 if (F_LEN(cmd
) == 1)
1246 printf(" iplen %u", cmd
->arg1
);
1248 print_newports((ipfw_insn_u16
*)cmd
, 0,
1253 print_flags("ipoptions", cmd
, f_ipopts
);
1257 print_flags("iptos", cmd
, f_iptos
);
1261 print_icmptypes((ipfw_insn_u32
*)cmd
);
1265 printf(" established");
1269 print_flags("tcpflags", cmd
, f_tcpflags
);
1273 print_flags("tcpoptions", cmd
, f_tcpopts
);
1277 printf(" tcpwin %d", ntohs(cmd
->arg1
));
1281 printf(" tcpack %ld", ntohl(cmd32
->d
[0]));
1285 printf(" tcpseq %ld", ntohl(cmd32
->d
[0]));
1290 struct passwd
*pwd
= getpwuid(cmd32
->d
[0]);
1293 printf(" uid %s", pwd
->pw_name
);
1295 printf(" uid %u", cmd32
->d
[0]);
1301 struct group
*grp
= getgrgid(cmd32
->d
[0]);
1304 printf(" gid %s", grp
->gr_name
);
1306 printf(" gid %u", cmd32
->d
[0]);
1311 printf(" verrevpath");
1319 comment
= (char *)(cmd
+ 1);
1323 printf(" keep-state");
1328 struct _s_x
*p
= limit_masks
;
1329 ipfw_insn_limit
*c
= (ipfw_insn_limit
*)cmd
;
1330 uint8_t x
= c
->limit_mask
;
1331 char const *comma
= " ";
1334 for (; p
->x
!= 0 ; p
++)
1335 if ((x
& p
->x
) == p
->x
) {
1337 printf("%s%s", comma
, p
->s
);
1340 printf(" %d", c
->conn_limit
);
1345 printf(" [opcode %d len %d]",
1346 cmd
->opcode
, cmd
->len
);
1349 if (cmd
->len
& F_OR
) {
1352 } else if (or_block
) {
1357 show_prerequisites(&flags
, HAVE_IP
, 0);
1359 printf(" // %s", comment
);
1364 show_dyn_ipfw(ipfw_dyn_rule
*d
, int pcwidth
, int bcwidth
)
1366 struct protoent
*pe
;
1371 if (!d
->expire
&& !(d
->dyn_type
== O_LIMIT_PARENT
))
1374 bcopy(&d
->rule
, &rulenum
, sizeof(rulenum
));
1375 printf("%05d", rulenum
);
1376 if (pcwidth
>0 || bcwidth
>0)
1377 printf(" %*llu %*llu (%ds)", pcwidth
,
1378 align_uint64(&d
->pcnt
), bcwidth
,
1379 align_uint64(&d
->bcnt
), d
->expire
);
1380 switch (d
->dyn_type
) {
1381 case O_LIMIT_PARENT
:
1382 printf(" PARENT %d", d
->count
);
1387 case O_KEEP_STATE
: /* bidir, no mask */
1392 if ((pe
= getprotobynumber(d
->id
.proto
)) != NULL
)
1393 printf(" %s", pe
->p_name
);
1395 printf(" proto %u", d
->id
.proto
);
1397 a
.s_addr
= htonl(d
->id
.src_ip
);
1398 printf(" %s %d", inet_ntoa(a
), d
->id
.src_port
);
1400 a
.s_addr
= htonl(d
->id
.dst_ip
);
1401 printf(" <-> %s %d", inet_ntoa(a
), d
->id
.dst_port
);
1406 sort_q(const void *pa
, const void *pb
)
1408 int rev
= (do_sort
< 0);
1409 int field
= rev
? -do_sort
: do_sort
;
1411 const struct dn_flow_queue
*a
= pa
;
1412 const struct dn_flow_queue
*b
= pb
;
1416 res
= a
->len
- b
->len
;
1419 res
= a
->len_bytes
- b
->len_bytes
;
1422 case 3: /* tot pkts */
1423 res
= a
->tot_pkts
- b
->tot_pkts
;
1426 case 4: /* tot bytes */
1427 res
= a
->tot_bytes
- b
->tot_bytes
;
1434 return (int)(rev
? res
: -res
);
1438 list_queues(struct dn_flow_set
*fs
, struct dn_flow_queue
*q
)
1442 printf(" mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n",
1443 fs
->flow_mask
.proto
,
1444 fs
->flow_mask
.src_ip
, fs
->flow_mask
.src_port
,
1445 fs
->flow_mask
.dst_ip
, fs
->flow_mask
.dst_port
);
1446 if (fs
->rq_elements
== 0)
1449 printf("BKT Prot ___Source IP/port____ "
1450 "____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp\n");
1452 heapsort(q
, fs
->rq_elements
, sizeof *q
, sort_q
);
1453 for (l
= 0; l
< fs
->rq_elements
; l
++) {
1455 struct protoent
*pe
;
1457 ina
.s_addr
= htonl(q
[l
].id
.src_ip
);
1458 printf("%3d ", q
[l
].hash_slot
);
1459 pe
= getprotobynumber(q
[l
].id
.proto
);
1461 printf("%-4s ", pe
->p_name
);
1463 printf("%4u ", q
[l
].id
.proto
);
1464 printf("%15s/%-5d ",
1465 inet_ntoa(ina
), q
[l
].id
.src_port
);
1466 ina
.s_addr
= htonl(q
[l
].id
.dst_ip
);
1467 printf("%15s/%-5d ",
1468 inet_ntoa(ina
), q
[l
].id
.dst_port
);
1469 printf("%4qu %8qu %2u %4u %3u\n",
1470 q
[l
].tot_pkts
, q
[l
].tot_bytes
,
1471 q
[l
].len
, q
[l
].len_bytes
, q
[l
].drops
);
1473 printf(" S %20qd F %20qd\n",
1479 print_flowset_parms(struct dn_flow_set
*fs
, char *prefix
)
1484 char red
[90]; /* Display RED parameters */
1487 if (fs
->flags_fs
& DN_QSIZE_IS_BYTES
) {
1489 sprintf(qs
, "%d KB", l
/ 1024);
1491 sprintf(qs
, "%d B", l
);
1493 sprintf(qs
, "%3d sl.", l
);
1495 sprintf(plr
, "plr %f", 1.0 * fs
->plr
/ (double)(0x7fffffff));
1498 if (fs
->flags_fs
& DN_IS_RED
) /* RED parameters */
1500 "\n\t %cRED w_q %f min_th %d max_th %d max_p %f",
1501 (fs
->flags_fs
& DN_IS_GENTLE_RED
) ? 'G' : ' ',
1502 1.0 * fs
->w_q
/ (double)(1 << SCALE_RED
),
1503 SCALE_VAL(fs
->min_th
),
1504 SCALE_VAL(fs
->max_th
),
1505 1.0 * fs
->max_p
/ (double)(1 << SCALE_RED
));
1507 sprintf(red
, "droptail");
1509 printf("%s %s%s %d queues (%d buckets) %s\n",
1510 prefix
, qs
, plr
, fs
->rq_elements
, fs
->rq_size
, red
);
1514 list_pipes(void *data
, uint nbytes
, int ac
, char *av
[])
1518 struct dn_pipe
*p
= (struct dn_pipe
*) data
;
1519 struct dn_flow_set
*fs
;
1520 struct dn_flow_queue
*q
;
1524 rulenum
= strtoul(*av
++, NULL
, 10);
1527 for (; nbytes
>= sizeof *p
; p
= (struct dn_pipe
*)next
) {
1528 double b
= p
->bandwidth
;
1532 if (p
->next
!= (struct dn_pipe
*)DN_IS_PIPE
)
1533 break; /* done with pipes, now queues */
1536 * compute length, as pipe have variable size
1538 l
= sizeof(*p
) + p
->fs
.rq_elements
* sizeof(*q
);
1539 next
= (char *)p
+ l
;
1542 if (rulenum
!= 0 && rulenum
!= p
->pipe_nr
)
1546 * Print rate (or clocking interface)
1548 if (p
->if_name
[0] != '\0')
1549 sprintf(buf
, "%s", p
->if_name
);
1551 sprintf(buf
, "unlimited");
1552 else if (b
>= 1000000)
1553 sprintf(buf
, "%7.3f Mbit/s", b
/1000000);
1555 sprintf(buf
, "%7.3f Kbit/s", b
/1000);
1557 sprintf(buf
, "%7.3f bit/s ", b
);
1559 sprintf(prefix
, "%05d: %s %4d ms ",
1560 p
->pipe_nr
, buf
, p
->delay
);
1561 print_flowset_parms(&(p
->fs
), prefix
);
1563 printf(" V %20qd\n", p
->V
>> MY_M
);
1565 q
= (struct dn_flow_queue
*)(p
+1);
1566 list_queues(&(p
->fs
), q
);
1568 for (fs
= next
; nbytes
>= sizeof *fs
; fs
= next
) {
1571 if (fs
->next
!= (struct dn_flow_set
*)DN_IS_QUEUE
)
1573 l
= sizeof(*fs
) + fs
->rq_elements
* sizeof(*q
);
1574 next
= (char *)fs
+ l
;
1576 q
= (struct dn_flow_queue
*)(fs
+1);
1577 sprintf(prefix
, "q%05d: weight %d pipe %d ",
1578 fs
->fs_nr
, fs
->weight
, fs
->parent_nr
);
1579 print_flowset_parms(fs
, prefix
);
1585 * This one handles all set-related commands
1586 * ipfw set { show | enable | disable }
1588 * ipfw set move X to Y
1589 * ipfw set move rule X to Y
1592 sets_handler(int ac
, char *av
[])
1594 uint32_t set_disable
, masks
[2];
1597 uint8_t cmd
, new_set
;
1603 errx(EX_USAGE
, "set needs command");
1604 if (!strncmp(*av
, "show", strlen(*av
)) ) {
1608 nbytes
= sizeof(struct ip_fw
);
1609 if ((data
= calloc(1, nbytes
)) == NULL
)
1610 err(EX_OSERR
, "calloc");
1612 if (do_cmd(IP_FW_GET
, data
, (uintptr_t)&nbytes
) < 0)
1613 err(EX_OSERR
, "getsockopt(IP_FW_GET)");
1614 bcopy(&((struct ip_fw
*)data
)->next_rule
,
1615 &set_disable
, sizeof(set_disable
));
1617 for (i
= 0, msg
= "disable" ; i
< RESVD_SET
; i
++)
1618 if ((set_disable
& (1<<i
))) {
1619 printf("%s %d", msg
, i
);
1622 msg
= (set_disable
) ? " enable" : "enable";
1623 for (i
= 0; i
< RESVD_SET
; i
++)
1624 if (!(set_disable
& (1<<i
))) {
1625 printf("%s %d", msg
, i
);
1629 } else if (!strncmp(*av
, "swap", strlen(*av
))) {
1633 errx(EX_USAGE
, "set swap needs 2 set numbers\n");
1634 rulenum
= atoi(av
[0]);
1635 new_set
= atoi(av
[1]);
1636 if (!isdigit(*(av
[0])) || rulenum
> RESVD_SET
)
1637 errx(EX_DATAERR
, "invalid set number %s\n", av
[0]);
1638 if (!isdigit(*(av
[1])) || new_set
> RESVD_SET
)
1639 errx(EX_DATAERR
, "invalid set number %s\n", av
[1]);
1640 masks
[0] = (4 << 24) | (new_set
<< 16) | (rulenum
);
1642 bzero(&rule
, sizeof(rule
));
1643 rule
.set_masks
[0] = masks
[0];
1645 i
= do_cmd(IP_FW_DEL
, &rule
, sizeof(rule
));
1646 } else if (!strncmp(*av
, "move", strlen(*av
))) {
1649 if (ac
&& !strncmp(*av
, "rule", strlen(*av
))) {
1654 if (ac
!= 3 || strncmp(av
[1], "to", strlen(*av
)))
1655 errx(EX_USAGE
, "syntax: set move [rule] X to Y\n");
1656 rulenum
= atoi(av
[0]);
1657 new_set
= atoi(av
[2]);
1658 if (!isdigit(*(av
[0])) || (cmd
== 3 && rulenum
> RESVD_SET
) ||
1659 (cmd
== 2 && rulenum
== 65535) )
1660 errx(EX_DATAERR
, "invalid source number %s\n", av
[0]);
1661 if (!isdigit(*(av
[2])) || new_set
> RESVD_SET
)
1662 errx(EX_DATAERR
, "invalid dest. set %s\n", av
[1]);
1663 masks
[0] = (cmd
<< 24) | (new_set
<< 16) | (rulenum
);
1665 bzero(&rule
, sizeof(rule
));
1666 rule
.set_masks
[0] = masks
[0];
1668 i
= do_cmd(IP_FW_DEL
, &rule
, sizeof(rule
));
1669 } else if (!strncmp(*av
, "disable", strlen(*av
)) ||
1670 !strncmp(*av
, "enable", strlen(*av
)) ) {
1671 int which
= !strncmp(*av
, "enable", strlen(*av
)) ? 1 : 0;
1675 masks
[0] = masks
[1] = 0;
1678 if (isdigit(**av
)) {
1680 if (i
< 0 || i
> RESVD_SET
)
1682 "invalid set number %d\n", i
);
1683 masks
[which
] |= (1<<i
);
1684 } else if (!strncmp(*av
, "disable", strlen(*av
)))
1686 else if (!strncmp(*av
, "enable", strlen(*av
)))
1690 "invalid set command %s\n", *av
);
1693 if ( (masks
[0] & masks
[1]) != 0 )
1695 "cannot enable and disable the same set\n");
1697 bzero(&rule
, sizeof(rule
));
1698 rule
.set_masks
[0] = masks
[0];
1699 rule
.set_masks
[1] = masks
[1];
1701 i
= do_cmd(IP_FW_DEL
, &rule
, sizeof(rule
));
1703 warn("set enable/disable: setsockopt(IP_FW_DEL)");
1705 errx(EX_USAGE
, "invalid set command %s\n", *av
);
1709 sysctl_handler(int ac
, char *av
[], int which
)
1715 warnx("missing keyword to enable/disable\n");
1716 } else if (strncmp(*av
, "firewall", strlen(*av
)) == 0) {
1717 sysctlbyname("net.inet.ip.fw.enable", NULL
, 0,
1718 &which
, sizeof(which
));
1719 } else if (strncmp(*av
, "one_pass", strlen(*av
)) == 0) {
1720 sysctlbyname("net.inet.ip.fw.one_pass", NULL
, 0,
1721 &which
, sizeof(which
));
1722 } else if (strncmp(*av
, "debug", strlen(*av
)) == 0) {
1723 sysctlbyname("net.inet.ip.fw.debug", NULL
, 0,
1724 &which
, sizeof(which
));
1725 } else if (strncmp(*av
, "verbose", strlen(*av
)) == 0) {
1726 sysctlbyname("net.inet.ip.fw.verbose", NULL
, 0,
1727 &which
, sizeof(which
));
1728 } else if (strncmp(*av
, "dyn_keepalive", strlen(*av
)) == 0) {
1729 sysctlbyname("net.inet.ip.fw.dyn_keepalive", NULL
, 0,
1730 &which
, sizeof(which
));
1732 warnx("unrecognize enable/disable keyword: %s\n", *av
);
1737 list(int ac
, char *av
[], int show_counters
)
1740 ipfw_dyn_rule
*dynrules
, *d
;
1742 #define NEXT(r) ((struct ip_fw *)((char *)r + RULESIZE(r)))
1745 int bcwidth
, n
, nbytes
, nstat
, ndyn
, pcwidth
, width
;
1746 int exitval
= EX_OK
;
1753 const int ocmd
= do_pipe
? IP_DUMMYNET_GET
: IP_FW_GET
;
1754 int nalloc
= 1024; /* start somewhere... */
1757 fprintf(stderr
, "Testing only, list disabled\n");
1764 /* get rules or pipes from kernel, resizing array as necessary */
1767 while (nbytes
>= nalloc
) {
1768 nalloc
= nalloc
* 2 + 200;
1770 if ((data
= realloc(data
, nbytes
)) == NULL
)
1771 err(EX_OSERR
, "realloc");
1773 if (do_cmd(ocmd
, data
, (uintptr_t)&nbytes
) < 0)
1774 err(EX_OSERR
, "getsockopt(IP_%s_GET)",
1775 do_pipe
? "DUMMYNET" : "FW");
1779 list_pipes(data
, nbytes
, ac
, av
);
1784 * Count static rules. They have variable size so we
1785 * need to scan the list to count them.
1787 for (nstat
= 1, r
= data
, lim
= (char *)data
+ nbytes
;
1788 r
->rulenum
< 65535 && (char *)r
< lim
;
1789 ++nstat
, r
= NEXT(r
) )
1793 * Count dynamic rules. This is easier as they have
1797 dynrules
= (ipfw_dyn_rule
*)r
;
1798 n
= (char *)r
- (char *)data
;
1799 ndyn
= (nbytes
- n
) / sizeof *dynrules
;
1801 /* if showing stats, figure out column widths ahead of time */
1802 bcwidth
= pcwidth
= 0;
1803 if (show_counters
) {
1804 for (n
= 0, r
= data
; n
< nstat
; n
++, r
= NEXT(r
)) {
1805 /* packet counter */
1806 width
= snprintf(NULL
, 0, "%llu",
1807 align_uint64(&r
->pcnt
));
1808 if (width
> pcwidth
)
1812 width
= snprintf(NULL
, 0, "%llu",
1813 align_uint64(&r
->bcnt
));
1814 if (width
> bcwidth
)
1818 if (do_dynamic
&& ndyn
) {
1819 for (n
= 0, d
= dynrules
; n
< ndyn
; n
++, d
++) {
1820 width
= snprintf(NULL
, 0, "%llu",
1821 align_uint64(&d
->pcnt
));
1822 if (width
> pcwidth
)
1825 width
= snprintf(NULL
, 0, "%llu",
1826 align_uint64(&d
->bcnt
));
1827 if (width
> bcwidth
)
1831 /* if no rule numbers were specified, list all rules */
1833 for (n
= 0, r
= data
; n
< nstat
; n
++, r
= NEXT(r
) )
1834 show_ipfw(r
, pcwidth
, bcwidth
);
1836 if (do_dynamic
&& ndyn
) {
1837 printf("## Dynamic rules (%d):\n", ndyn
);
1838 for (n
= 0, d
= dynrules
; n
< ndyn
; n
++, d
++)
1839 show_dyn_ipfw(d
, pcwidth
, bcwidth
);
1844 /* display specific rules requested on command line */
1846 for (lac
= ac
, lav
= av
; lac
!= 0; lac
--) {
1847 /* convert command line rule # */
1848 last
= rnum
= strtoul(*lav
++, &endptr
, 10);
1850 last
= strtoul(endptr
+1, &endptr
, 10);
1853 warnx("invalid rule number: %s", *(lav
- 1));
1856 for (n
= seen
= 0, r
= data
; n
< nstat
; n
++, r
= NEXT(r
) ) {
1857 if (r
->rulenum
> last
)
1859 if (r
->rulenum
>= rnum
&& r
->rulenum
<= last
) {
1860 show_ipfw(r
, pcwidth
, bcwidth
);
1865 /* give precedence to other error(s) */
1866 if (exitval
== EX_OK
)
1867 exitval
= EX_UNAVAILABLE
;
1868 warnx("rule %lu does not exist", rnum
);
1872 if (do_dynamic
&& ndyn
) {
1873 printf("## Dynamic rules:\n");
1874 for (lac
= ac
, lav
= av
; lac
!= 0; lac
--) {
1875 rnum
= strtoul(*lav
++, &endptr
, 10);
1877 last
= strtoul(endptr
+1, &endptr
, 10);
1879 /* already warned */
1881 for (n
= 0, d
= dynrules
; n
< ndyn
; n
++, d
++) {
1884 bcopy(&d
->rule
, &rulenum
, sizeof(rulenum
));
1887 if (r
->rulenum
>= rnum
&& r
->rulenum
<= last
)
1888 show_dyn_ipfw(d
, pcwidth
, bcwidth
);
1898 if (exitval
!= EX_OK
)
1906 fprintf(stderr
, "usage: ipfw [options]\n"
1907 "do \"ipfw -h\" or see ipfw manpage for details\n"
1916 "ipfw syntax summary (but please do read the ipfw(8) manpage):\n"
1917 "ipfw [-acdeftTnNpqS] <command> where <command> is one of:\n"
1918 "add [num] [set N] [prob x] RULE-BODY\n"
1919 "{pipe|queue} N config PIPE-BODY\n"
1920 "[pipe|queue] {zero|delete|show} [N{,N}]\n"
1921 "set [disable N... enable N...] | move [rule] X to Y | swap X Y | show\n"
1923 "RULE-BODY: check-state [LOG] | ACTION [LOG] ADDR [OPTION_LIST]\n"
1924 "ACTION: check-state | allow | count | deny | reject | skipto N |\n"
1925 " {divert|tee} PORT | forward ADDR | pipe N | queue N\n"
1926 "ADDR: [ MAC dst src ether_type ] \n"
1927 " [ from IPADDR [ PORT ] to IPADDR [ PORTLIST ] ]\n"
1928 "IPADDR: [not] { any | me | ip/bits{x,y,z} | IPLIST }\n"
1929 "IPLIST: { ip | ip/bits | ip:mask }[,IPLIST]\n"
1930 "OPTION_LIST: OPTION [OPTION_LIST]\n"
1931 "OPTION: bridged | {dst-ip|src-ip} ADDR | {dst-port|src-port} LIST |\n"
1932 " estab | frag | {gid|uid} N | icmptypes LIST | in | out | ipid LIST |\n"
1933 " iplen LIST | ipoptions SPEC | ipprecedence | ipsec | iptos SPEC |\n"
1934 " ipttl LIST | ipversion VER | keep-state | layer2 | limit ... |\n"
1935 " mac ... | mac-type LIST | proto LIST | {recv|xmit|via} {IF|IPADDR} |\n"
1936 " setup | {tcpack|tcpseq|tcpwin} NN | tcpflags SPEC | tcpoptions SPEC |\n"
1944 lookup_host (char *host
, struct in_addr
*ipaddr
)
1948 if (!inet_aton(host
, ipaddr
)) {
1949 if ((he
= gethostbyname(host
)) == NULL
)
1951 *ipaddr
= *(struct in_addr
*)he
->h_addr_list
[0];
1957 * fills the addr and mask fields in the instruction as appropriate from av.
1958 * Update length as appropriate.
1959 * The following formats are allowed:
1960 * any matches any IP. Actually returns an empty instruction.
1961 * me returns O_IP_*_ME
1962 * 1.2.3.4 single IP address
1963 * 1.2.3.4:5.6.7.8 address:mask
1964 * 1.2.3.4/24 address/mask
1965 * 1.2.3.4/26{1,6,5,4,23} set of addresses in a subnet
1966 * We can have multiple comma-separated address/mask entries.
1969 fill_ip(ipfw_insn_ip
*cmd
, char *av
)
1972 uint32_t *d
= ((ipfw_insn_u32
*)cmd
)->d
;
1974 cmd
->o
.len
&= ~F_LEN_MASK
; /* zero len */
1976 if (!strncmp(av
, "any", strlen(av
)))
1979 if (!strncmp(av
, "me", strlen(av
))) {
1980 cmd
->o
.len
|= F_INSN_SIZE(ipfw_insn
);
1986 * After the address we can have '/' or ':' indicating a mask,
1987 * ',' indicating another address follows, '{' indicating a
1988 * set of addresses of unspecified size.
1990 char *p
= strpbrk(av
, "/:,{");
2000 if (lookup_host(av
, (struct in_addr
*)&d
[0]) != 0)
2001 errx(EX_NOHOST
, "hostname ``%s'' unknown", av
);
2004 if (!inet_aton(p
, (struct in_addr
*)&d
[1]))
2005 errx(EX_DATAERR
, "bad netmask ``%s''", p
);
2010 d
[1] = htonl(0); /* mask */
2011 else if (masklen
> 32)
2012 errx(EX_DATAERR
, "bad width ``%s''", p
);
2014 d
[1] = htonl(~0 << (32 - masklen
));
2016 case '{': /* no mask, assume /24 and put back the '{' */
2017 d
[1] = htonl(~0 << (32 - 24));
2021 case ',': /* single address plus continuation */
2024 case 0: /* initialization value */
2026 d
[1] = htonl(~0); /* force /32 */
2029 d
[0] &= d
[1]; /* mask base address with mask */
2030 /* find next separator */
2032 p
= strpbrk(p
, ",{");
2033 if (p
&& *p
== '{') {
2035 * We have a set of addresses. They are stored as follows:
2036 * arg1 is the set size (powers of 2, 2..256)
2037 * addr is the base address IN HOST FORMAT
2038 * mask.. is an array of arg1 bits (rounded up to
2039 * the next multiple of 32) with bits set
2040 * for each host in the map.
2042 uint32_t *map
= (uint32_t *)&cmd
->mask
;
2044 int i
= contigmask((uint8_t *)&(d
[1]), 32);
2047 errx(EX_DATAERR
, "address set cannot be in a list");
2048 if (i
< 24 || i
> 31)
2049 errx(EX_DATAERR
, "invalid set with mask %d\n", i
);
2050 cmd
->o
.arg1
= 1<<(32-i
); /* map length */
2051 d
[0] = ntohl(d
[0]); /* base addr in host format */
2052 cmd
->o
.opcode
= O_IP_DST_SET
; /* default */
2053 cmd
->o
.len
|= F_INSN_SIZE(ipfw_insn_u32
) + (cmd
->o
.arg1
+31)/32;
2054 for (i
= 0; i
< (cmd
->o
.arg1
+31)/32 ; i
++)
2055 map
[i
] = 0; /* clear map */
2059 high
= low
+ cmd
->o
.arg1
- 1;
2061 * Here, i stores the previous value when we specify a range
2062 * of addresses within a mask, e.g. 45-63. i = -1 means we
2063 * have no previous value.
2065 i
= -1; /* previous value in a range */
2066 while (isdigit(*av
)) {
2068 int a
= strtol(av
, &s
, 0);
2070 if (s
== av
) { /* no parameter */
2072 errx(EX_DATAERR
, "set not closed\n");
2074 errx(EX_DATAERR
, "incomplete range %d-", i
);
2077 if (a
< low
|| a
> high
)
2078 errx(EX_DATAERR
, "addr %d out of range [%d-%d]\n",
2081 if (i
== -1) /* no previous in range */
2083 else { /* check that range is valid */
2085 errx(EX_DATAERR
, "invalid range %d-%d",
2088 errx(EX_DATAERR
, "double '-' in range");
2091 map
[i
/32] |= 1<<(i
& 31);
2102 if (av
) /* then *av must be a ',' */
2105 /* Check this entry */
2106 if (d
[1] == 0) { /* "any", specified as x.x.x.x/0 */
2108 * 'any' turns the entire list into a NOP.
2109 * 'not any' never matches, so it is removed from the
2110 * list unless it is the only item, in which case we
2113 if (cmd
->o
.len
& F_NOT
) { /* "not any" never matches */
2114 if (av
== NULL
&& len
== 0) /* only this entry */
2115 errx(EX_DATAERR
, "not any never matches");
2117 /* else do nothing and return */
2120 /* A single IP can be stored in an optimized format */
2121 if (d
[1] == IP_MASK_ALL
&& av
== NULL
&& len
== 0) {
2122 cmd
->o
.len
|= F_INSN_SIZE(ipfw_insn_u32
);
2125 len
+= 2; /* two words... */
2128 cmd
->o
.len
|= len
+1;
2133 * helper function to process a set of flags and set bits in the
2134 * appropriate masks.
2137 fill_flags(ipfw_insn
*cmd
, enum ipfw_opcodes opcode
,
2138 struct _s_x
*flags
, char *p
)
2140 uint8_t set
=0, clear
=0;
2143 char *q
; /* points to the separator */
2145 uint8_t *which
; /* mask we are working on */
2155 val
= match_token(flags
, p
);
2157 errx(EX_DATAERR
, "invalid flag %s", p
);
2158 *which
|= (uint8_t)val
;
2161 cmd
->opcode
= opcode
;
2162 cmd
->len
= (cmd
->len
& (F_NOT
| F_OR
)) | 1;
2163 cmd
->arg1
= (set
& 0xff) | ( (clear
& 0xff) << 8);
2168 delete(int ac
, char *av
[])
2173 int exitval
= EX_OK
;
2176 memset(&p
, 0, sizeof p
);
2179 if (ac
> 0 && !strncmp(*av
, "set", strlen(*av
))) {
2180 do_set
= 1; /* delete set */
2185 while (ac
&& isdigit(**av
)) {
2186 i
= atoi(*av
); av
++; ac
--;
2192 i
= do_cmd(IP_DUMMYNET_DEL
, &p
, sizeof p
);
2195 warn("rule %u: setsockopt(IP_DUMMYNET_DEL)",
2196 do_pipe
== 1 ? p
.pipe_nr
: p
.fs
.fs_nr
);
2199 bzero(&rule
, sizeof(rule
));
2201 rule
.set_masks
[0] = (i
& 0xffff) | (do_set
<< 24);
2206 i
= do_cmd(IP_FW_DEL
, &rule
, sizeof(rule
));
2208 exitval
= EX_UNAVAILABLE
;
2209 warn("rule %u: setsockopt(IP_FW_DEL)",
2214 if (exitval
!= EX_OK
)
2220 * fill the interface structure. We do not check the name as we can
2221 * create interfaces dynamically, so checking them at insert time
2222 * makes relatively little sense.
2223 * A '*' following the name means any unit.
2226 fill_iface(ipfw_insn_if
*cmd
, char *arg
)
2228 cmd
->name
[0] = '\0';
2229 cmd
->o
.len
|= F_INSN_SIZE(ipfw_insn_if
);
2231 /* Parse the interface or address */
2232 if (!strcmp(arg
, "any"))
2233 cmd
->o
.len
= 0; /* effectively ignore this command */
2234 else if (!isdigit(*arg
)) {
2237 strncpy(cmd
->name
, arg
, sizeof(cmd
->name
));
2238 cmd
->name
[sizeof(cmd
->name
) - 1] = '\0';
2239 /* find first digit or wildcard */
2240 for (q
= cmd
->name
; *q
&& !isdigit(*q
) && *q
!= '*'; q
++)
2242 cmd
->p
.unit
= (*q
== '*') ? -1 : atoi(q
);
2244 } else if (!inet_aton(arg
, &cmd
->p
.ip
))
2245 errx(EX_DATAERR
, "bad ip address ``%s''", arg
);
2249 * the following macro returns an error message if we run out of
2252 #define NEED1(msg) {if (!ac) errx(EX_USAGE, msg);}
2255 config_pipe(int ac
, char **av
)
2263 memset(&p
, 0, sizeof p
);
2267 if (ac
&& isdigit(**av
)) {
2268 i
= atoi(*av
); av
++; ac
--;
2276 int tok
= match_token(dummynet_params
, *av
);
2281 p
.fs
.flags_fs
|= DN_NOERROR
;
2285 NEED1("plr needs argument 0..1\n");
2286 d
= strtod(av
[0], NULL
);
2291 p
.fs
.plr
= (int)(d
*0x7fffffff);
2296 NEED1("queue needs queue size\n");
2298 p
.fs
.qsize
= strtoul(av
[0], &end
, 0);
2299 if (*end
== 'K' || *end
== 'k') {
2300 p
.fs
.flags_fs
|= DN_QSIZE_IS_BYTES
;
2302 } else if (*end
== 'B' || !strncmp(end
, "by", 2)) {
2303 p
.fs
.flags_fs
|= DN_QSIZE_IS_BYTES
;
2309 NEED1("buckets needs argument\n");
2310 p
.fs
.rq_size
= strtoul(av
[0], NULL
, 0);
2315 NEED1("mask needs mask specifier\n");
2317 * per-flow queue, mask is dst_ip, dst_port,
2318 * src_ip, src_port, proto measured in bits
2322 p
.fs
.flow_mask
.dst_ip
= 0;
2323 p
.fs
.flow_mask
.src_ip
= 0;
2324 p
.fs
.flow_mask
.dst_port
= 0;
2325 p
.fs
.flow_mask
.src_port
= 0;
2326 p
.fs
.flow_mask
.proto
= 0;
2330 uint32_t *p32
= NULL
;
2331 uint16_t *p16
= NULL
;
2333 tok
= match_token(dummynet_params
, *av
);
2338 * special case, all bits significant
2340 p
.fs
.flow_mask
.dst_ip
= ~0;
2341 p
.fs
.flow_mask
.src_ip
= ~0;
2342 p
.fs
.flow_mask
.dst_port
= ~0;
2343 p
.fs
.flow_mask
.src_port
= ~0;
2344 p
.fs
.flow_mask
.proto
= ~0;
2345 p
.fs
.flags_fs
|= DN_HAVE_FLOW_MASK
;
2349 p32
= &p
.fs
.flow_mask
.dst_ip
;
2353 p32
= &p
.fs
.flow_mask
.src_ip
;
2357 p16
= &p
.fs
.flow_mask
.dst_port
;
2361 p16
= &p
.fs
.flow_mask
.src_port
;
2368 ac
++; av
--; /* backtrack */
2372 errx(EX_USAGE
, "mask: value missing");
2373 if (*av
[0] == '/') {
2374 a
= strtoul(av
[0]+1, &end
, 0);
2375 a
= (a
== 32) ? ~0 : (1 << a
) - 1;
2377 a
= strtoul(av
[0], &end
, 0);
2380 else if (p16
!= NULL
) {
2383 "mask: must be 16 bit");
2388 "mask: must be 8 bit");
2389 p
.fs
.flow_mask
.proto
= (uint8_t)a
;
2392 p
.fs
.flags_fs
|= DN_HAVE_FLOW_MASK
;
2394 } /* end while, config masks */
2400 NEED1("red/gred needs w_q/min_th/max_th/max_p\n");
2401 p
.fs
.flags_fs
|= DN_IS_RED
;
2402 if (tok
== TOK_GRED
)
2403 p
.fs
.flags_fs
|= DN_IS_GENTLE_RED
;
2405 * the format for parameters is w_q/min_th/max_th/max_p
2407 if ((end
= strsep(&av
[0], "/"))) {
2408 double w_q
= strtod(end
, NULL
);
2409 if (w_q
> 1 || w_q
<= 0)
2410 errx(EX_DATAERR
, "0 < w_q <= 1");
2411 p
.fs
.w_q
= (int) (w_q
* (1 << SCALE_RED
));
2413 if ((end
= strsep(&av
[0], "/"))) {
2414 p
.fs
.min_th
= strtoul(end
, &end
, 0);
2415 if (*end
== 'K' || *end
== 'k')
2416 p
.fs
.min_th
*= 1024;
2418 if ((end
= strsep(&av
[0], "/"))) {
2419 p
.fs
.max_th
= strtoul(end
, &end
, 0);
2420 if (*end
== 'K' || *end
== 'k')
2421 p
.fs
.max_th
*= 1024;
2423 if ((end
= strsep(&av
[0], "/"))) {
2424 double max_p
= strtod(end
, NULL
);
2425 if (max_p
> 1 || max_p
<= 0)
2426 errx(EX_DATAERR
, "0 < max_p <= 1");
2427 p
.fs
.max_p
= (int)(max_p
* (1 << SCALE_RED
));
2433 p
.fs
.flags_fs
&= ~(DN_IS_RED
|DN_IS_GENTLE_RED
);
2437 NEED1("bw needs bandwidth or interface\n");
2439 errx(EX_DATAERR
, "bandwidth only valid for pipes");
2441 * set clocking interface or bandwidth value
2443 if (av
[0][0] >= 'a' && av
[0][0] <= 'z') {
2444 int l
= sizeof(p
.if_name
)-1;
2445 /* interface name */
2446 strncpy(p
.if_name
, av
[0], l
);
2447 p
.if_name
[l
] = '\0';
2450 p
.if_name
[0] = '\0';
2451 p
.bandwidth
= strtoul(av
[0], &end
, 0);
2452 if (*end
== 'K' || *end
== 'k') {
2454 p
.bandwidth
*= 1000;
2455 } else if (*end
== 'M') {
2457 p
.bandwidth
*= 1000000;
2459 if (*end
== 'B' || !strncmp(end
, "by", 2))
2461 if (p
.bandwidth
< 0)
2462 errx(EX_DATAERR
, "bandwidth too large");
2469 errx(EX_DATAERR
, "delay only valid for pipes");
2470 NEED1("delay needs argument 0..10000ms\n");
2471 p
.delay
= strtoul(av
[0], NULL
, 0);
2477 errx(EX_DATAERR
,"weight only valid for queues");
2478 NEED1("weight needs argument 0..100\n");
2479 p
.fs
.weight
= strtoul(av
[0], &end
, 0);
2485 errx(EX_DATAERR
,"pipe only valid for queues");
2486 NEED1("pipe needs pipe_number\n");
2487 p
.fs
.parent_nr
= strtoul(av
[0], &end
, 0);
2492 errx(EX_DATAERR
, "unrecognised option ``%s''", *av
);
2497 errx(EX_DATAERR
, "pipe_nr must be > 0");
2498 if (p
.delay
> 10000)
2499 errx(EX_DATAERR
, "delay must be < 10000");
2500 } else { /* do_pipe == 2, queue */
2501 if (p
.fs
.parent_nr
== 0)
2502 errx(EX_DATAERR
, "pipe must be > 0");
2503 if (p
.fs
.weight
>100)
2504 errx(EX_DATAERR
, "weight must be <= 100");
2506 if (p
.fs
.flags_fs
& DN_QSIZE_IS_BYTES
) {
2507 if (p
.fs
.qsize
> 1024*1024)
2508 errx(EX_DATAERR
, "queue size must be < 1MB");
2510 if (p
.fs
.qsize
> 100)
2511 errx(EX_DATAERR
, "2 <= queue size <= 100");
2513 if (p
.fs
.flags_fs
& DN_IS_RED
) {
2515 int lookup_depth
, avg_pkt_size
;
2516 double s
, idle
, weight
, w_q
;
2517 struct clockinfo ck
;
2520 if (p
.fs
.min_th
>= p
.fs
.max_th
)
2521 errx(EX_DATAERR
, "min_th %d must be < than max_th %d",
2522 p
.fs
.min_th
, p
.fs
.max_th
);
2523 if (p
.fs
.max_th
== 0)
2524 errx(EX_DATAERR
, "max_th must be > 0");
2527 if (sysctlbyname("net.inet.ip.dummynet.red_lookup_depth",
2528 &lookup_depth
, &len
, NULL
, 0) == -1)
2530 errx(1, "sysctlbyname(\"%s\")",
2531 "net.inet.ip.dummynet.red_lookup_depth");
2532 if (lookup_depth
== 0)
2533 errx(EX_DATAERR
, "net.inet.ip.dummynet.red_lookup_depth"
2534 " must be greater than zero");
2537 if (sysctlbyname("net.inet.ip.dummynet.red_avg_pkt_size",
2538 &avg_pkt_size
, &len
, NULL
, 0) == -1)
2540 errx(1, "sysctlbyname(\"%s\")",
2541 "net.inet.ip.dummynet.red_avg_pkt_size");
2542 if (avg_pkt_size
== 0)
2544 "net.inet.ip.dummynet.red_avg_pkt_size must"
2545 " be greater than zero");
2547 len
= sizeof(struct clockinfo
);
2548 if (sysctlbyname("kern.clockrate", &ck
, &len
, NULL
, 0) == -1)
2549 errx(1, "sysctlbyname(\"%s\")", "kern.clockrate");
2552 * Ticks needed for sending a medium-sized packet.
2553 * Unfortunately, when we are configuring a WF2Q+ queue, we
2554 * do not have bandwidth information, because that is stored
2555 * in the parent pipe, and also we have multiple queues
2556 * competing for it. So we set s=0, which is not very
2557 * correct. But on the other hand, why do we want RED with
2560 if (p
.bandwidth
==0) /* this is a WF2Q+ queue */
2563 s
= ck
.hz
* avg_pkt_size
* 8 / p
.bandwidth
;
2566 * max idle time (in ticks) before avg queue size becomes 0.
2567 * NOTA: (3/w_q) is approx the value x so that
2568 * (1-w_q)^x < 10^-3.
2570 w_q
= ((double)p
.fs
.w_q
) / (1 << SCALE_RED
);
2571 idle
= s
* 3. / w_q
;
2572 p
.fs
.lookup_step
= (int)idle
/ lookup_depth
;
2573 if (!p
.fs
.lookup_step
)
2574 p
.fs
.lookup_step
= 1;
2576 for (t
= p
.fs
.lookup_step
; t
> 0; --t
)
2578 p
.fs
.lookup_weight
= (int)(weight
* (1 << SCALE_RED
));
2580 i
= do_cmd(IP_DUMMYNET_CONFIGURE
, &p
, sizeof p
);
2582 err(1, "setsockopt(%s)", "IP_DUMMYNET_CONFIGURE");
2586 get_mac_addr_mask(char *p
, uint8_t *addr
, uint8_t *mask
)
2591 addr
[i
] = mask
[i
] = 0;
2592 if (!strcmp(p
, "any"))
2595 for (i
=0; *p
&& i
<6;i
++, p
++) {
2596 addr
[i
] = strtol(p
, &p
, 16);
2597 if (*p
!= ':') /* we start with the mask */
2600 if (*p
== '/') { /* mask len */
2601 l
= strtol(p
+1, &p
, 0);
2602 for (i
=0; l
>0; l
-=8, i
++)
2603 mask
[i
] = (l
>=8) ? 0xff : (~0) << (8-l
);
2604 } else if (*p
== '&') { /* mask */
2605 for (i
=0, p
++; *p
&& i
<6;i
++, p
++) {
2606 mask
[i
] = strtol(p
, &p
, 16);
2610 } else if (*p
== '\0') {
2619 * helper function, updates the pointer to cmd with the length
2620 * of the current command, and also cleans up the first word of
2621 * the new command in case it has been clobbered before.
2624 next_cmd(ipfw_insn
*cmd
)
2627 bzero(cmd
, sizeof(*cmd
));
2632 * Takes arguments and copies them into a comment
2635 fill_comment(ipfw_insn
*cmd
, int ac
, char **av
)
2638 char *p
= (char *)(cmd
+ 1);
2640 cmd
->opcode
= O_NOP
;
2641 cmd
->len
= (cmd
->len
& (F_NOT
| F_OR
));
2643 /* Compute length of comment string. */
2644 for (i
= 0, l
= 0; i
< ac
; i
++)
2645 l
+= strlen(av
[i
]) + 1;
2650 "comment too long (max 80 chars)");
2652 cmd
->len
= (cmd
->len
& (F_NOT
| F_OR
)) | l
;
2653 for (i
= 0; i
< ac
; i
++) {
2662 * A function to fill simple commands of size 1.
2663 * Existing flags are preserved.
2666 fill_cmd(ipfw_insn
*cmd
, enum ipfw_opcodes opcode
, int flags
, uint16_t arg
)
2668 cmd
->opcode
= opcode
;
2669 cmd
->len
= ((cmd
->len
| flags
) & (F_NOT
| F_OR
)) | 1;
2674 * Fetch and add the MAC address and type, with masks. This generates one or
2675 * two microinstructions, and returns the pointer to the last one.
2678 add_mac(ipfw_insn
*cmd
, int ac
, char *av
[])
2683 errx(EX_DATAERR
, "MAC dst src");
2685 cmd
->opcode
= O_MACADDR2
;
2686 cmd
->len
= (cmd
->len
& (F_NOT
| F_OR
)) | F_INSN_SIZE(ipfw_insn_mac
);
2688 mac
= (ipfw_insn_mac
*)cmd
;
2689 get_mac_addr_mask(av
[0], mac
->addr
, mac
->mask
); /* dst */
2690 get_mac_addr_mask(av
[1], &(mac
->addr
[6]), &(mac
->mask
[6])); /* src */
2695 add_mactype(ipfw_insn
*cmd
, int ac
, char *av
)
2698 errx(EX_DATAERR
, "missing MAC type");
2699 if (strcmp(av
, "any") != 0) { /* we have a non-null type */
2700 fill_newports((ipfw_insn_u16
*)cmd
, av
, IPPROTO_ETHERTYPE
);
2701 cmd
->opcode
= O_MAC_TYPE
;
2708 add_proto(ipfw_insn
*cmd
, char *av
)
2710 struct protoent
*pe
;
2713 if (!strncmp(av
, "all", strlen(av
)))
2714 ; /* same as "ip" */
2715 else if ((proto
= atoi(av
)) > 0)
2717 else if ((pe
= getprotobyname(av
)) != NULL
)
2718 proto
= pe
->p_proto
;
2721 if (proto
!= IPPROTO_IP
)
2722 fill_cmd(cmd
, O_PROTO
, 0, proto
);
2727 add_srcip(ipfw_insn
*cmd
, char *av
)
2729 fill_ip((ipfw_insn_ip
*)cmd
, av
);
2730 if (cmd
->opcode
== O_IP_DST_SET
) /* set */
2731 cmd
->opcode
= O_IP_SRC_SET
;
2732 else if (F_LEN(cmd
) == F_INSN_SIZE(ipfw_insn
)) /* me */
2733 cmd
->opcode
= O_IP_SRC_ME
;
2734 else if (F_LEN(cmd
) == F_INSN_SIZE(ipfw_insn_u32
)) /* one IP */
2735 cmd
->opcode
= O_IP_SRC
;
2736 else /* addr/mask */
2737 cmd
->opcode
= O_IP_SRC_MASK
;
2742 add_dstip(ipfw_insn
*cmd
, char *av
)
2744 fill_ip((ipfw_insn_ip
*)cmd
, av
);
2745 if (cmd
->opcode
== O_IP_DST_SET
) /* set */
2747 else if (F_LEN(cmd
) == F_INSN_SIZE(ipfw_insn
)) /* me */
2748 cmd
->opcode
= O_IP_DST_ME
;
2749 else if (F_LEN(cmd
) == F_INSN_SIZE(ipfw_insn_u32
)) /* one IP */
2750 cmd
->opcode
= O_IP_DST
;
2751 else /* addr/mask */
2752 cmd
->opcode
= O_IP_DST_MASK
;
2757 add_ports(ipfw_insn
*cmd
, char *av
, u_char proto
, int opcode
)
2759 if (!strncmp(av
, "any", strlen(av
))) {
2761 } else if (fill_newports((ipfw_insn_u16
*)cmd
, av
, proto
)) {
2762 /* XXX todo: check that we have a protocol with ports */
2763 cmd
->opcode
= opcode
;
2770 * Parse arguments and assemble the microinstructions which make up a rule.
2771 * Rules are added into the 'rulebuf' and then copied in the correct order
2772 * into the actual rule.
2774 * The syntax for a rule starts with the action, followed by an
2775 * optional log action, and the various match patterns.
2776 * In the assembled microcode, the first opcode must be an O_PROBE_STATE
2777 * (generated if the rule includes a keep-state option), then the
2778 * various match patterns, the "log" action, and the actual action.
2782 add(int ac
, char *av
[])
2785 * rules are added into the 'rulebuf' and then copied in
2786 * the correct order into the actual rule.
2787 * Some things that need to go out of order (prob, action etc.)
2790 static uint32_t rulebuf
[255], actbuf
[255], cmdbuf
[255];
2792 ipfw_insn
*src
, *dst
, *cmd
, *action
, *prev
=NULL
;
2793 ipfw_insn
*first_cmd
; /* first match pattern */
2798 * various flags used to record that we entered some fields.
2800 ipfw_insn
*have_state
= NULL
; /* check-state or keep-state */
2804 int open_par
= 0; /* open parenthesis ( */
2806 /* proto is here because it is used to fetch ports */
2807 u_char proto
= IPPROTO_IP
; /* default protocol */
2809 double match_prob
= 1; /* match probability, default is always match */
2811 bzero(actbuf
, sizeof(actbuf
)); /* actions go here */
2812 bzero(cmdbuf
, sizeof(cmdbuf
));
2813 bzero(rulebuf
, sizeof(rulebuf
));
2815 rule
= (struct ip_fw
*)rulebuf
;
2816 cmd
= (ipfw_insn
*)cmdbuf
;
2817 action
= (ipfw_insn
*)actbuf
;
2821 /* [rule N] -- Rule number optional */
2822 if (ac
&& isdigit(**av
)) {
2823 rule
->rulenum
= atoi(*av
);
2828 /* [set N] -- set number (0..RESVD_SET), optional */
2829 if (ac
> 1 && !strncmp(*av
, "set", strlen(*av
))) {
2830 int set
= strtoul(av
[1], NULL
, 10);
2831 if (set
< 0 || set
> RESVD_SET
)
2832 errx(EX_DATAERR
, "illegal set %s", av
[1]);
2837 /* [prob D] -- match probability, optional */
2838 if (ac
> 1 && !strncmp(*av
, "prob", strlen(*av
))) {
2839 match_prob
= strtod(av
[1], NULL
);
2841 if (match_prob
<= 0 || match_prob
> 1)
2842 errx(EX_DATAERR
, "illegal match prob. %s", av
[1]);
2846 /* action -- mandatory */
2847 NEED1("missing action");
2848 i
= match_token(rule_actions
, *av
);
2850 action
->len
= 1; /* default */
2852 case TOK_CHECKSTATE
:
2853 have_state
= action
;
2854 action
->opcode
= O_CHECK_STATE
;
2858 action
->opcode
= O_ACCEPT
;
2862 action
->opcode
= O_DENY
;
2867 action
->opcode
= O_REJECT
;
2868 action
->arg1
= ICMP_UNREACH_HOST
;
2872 action
->opcode
= O_REJECT
;
2873 action
->arg1
= ICMP_REJECT_RST
;
2877 action
->opcode
= O_REJECT
;
2878 NEED1("missing reject code");
2879 fill_reject_code(&action
->arg1
, *av
);
2884 action
->opcode
= O_COUNT
;
2889 action
->len
= F_INSN_SIZE(ipfw_insn_pipe
);
2892 action
->opcode
= O_QUEUE
;
2893 else if (i
== TOK_PIPE
)
2894 action
->opcode
= O_PIPE
;
2895 else if (i
== TOK_SKIPTO
)
2896 action
->opcode
= O_SKIPTO
;
2897 NEED1("missing skipto/pipe/queue number");
2898 action
->arg1
= strtoul(*av
, NULL
, 10);
2904 action
->opcode
= (i
== TOK_DIVERT
) ? O_DIVERT
: O_TEE
;
2905 NEED1("missing divert/tee port");
2906 action
->arg1
= strtoul(*av
, NULL
, 0);
2907 if (action
->arg1
== 0) {
2910 s
= getservbyname(av
[0], "divert");
2912 action
->arg1
= ntohs(s
->s_port
);
2914 errx(EX_DATAERR
, "illegal divert/tee port");
2920 ipfw_insn_sa
*p
= (ipfw_insn_sa
*)action
;
2923 NEED1("missing forward address[:port]");
2925 action
->opcode
= O_FORWARD_IP
;
2926 action
->len
= F_INSN_SIZE(ipfw_insn_sa
);
2928 p
->sa
.sin_len
= sizeof(struct sockaddr_in
);
2929 p
->sa
.sin_family
= AF_INET
;
2932 * locate the address-port separator (':' or ',')
2934 s
= strchr(*av
, ':');
2936 s
= strchr(*av
, ',');
2939 i
= strtoport(s
, &end
, 0 /* base */, 0 /* proto */);
2942 "illegal forwarding port ``%s''", s
);
2943 p
->sa
.sin_port
= (u_short
)i
;
2945 lookup_host(*av
, &(p
->sa
.sin_addr
));
2951 /* pretend it is a 'count' rule followed by the comment */
2952 action
->opcode
= O_COUNT
;
2953 ac
++; av
--; /* go back... */
2957 errx(EX_DATAERR
, "invalid action %s\n", av
[-1]);
2959 action
= next_cmd(action
);
2962 * [log [logamount N]] -- log, optional
2964 * If exists, it goes first in the cmdbuf, but then it is
2965 * skipped in the copy section to the end of the buffer.
2967 if (ac
&& !strncmp(*av
, "log", strlen(*av
))) {
2968 ipfw_insn_log
*c
= (ipfw_insn_log
*)cmd
;
2971 cmd
->len
= F_INSN_SIZE(ipfw_insn_log
);
2972 cmd
->opcode
= O_LOG
;
2974 if (ac
&& !strncmp(*av
, "logamount", strlen(*av
))) {
2976 NEED1("logamount requires argument");
2979 errx(EX_DATAERR
, "logamount must be positive");
2983 cmd
= next_cmd(cmd
);
2986 if (have_state
) /* must be a check-state, we are done */
2989 #define OR_START(target) \
2990 if (ac && (*av[0] == '(' || *av[0] == '{')) { \
2992 errx(EX_USAGE, "nested \"(\" not allowed\n"); \
2995 if ( (av[0])[1] == '\0') { \
3006 !strncmp(*av, ")", strlen(*av)) || \
3007 !strncmp(*av, "}", strlen(*av)) )) { \
3012 errx(EX_USAGE, "missing \")\"\n"); \
3016 if (ac && !strncmp(*av, "not", strlen(*av))) { \
3017 if (cmd->len & F_NOT) \
3018 errx(EX_USAGE, "double \"not\" not allowed\n"); \
3019 cmd->len |= F_NOT; \
3023 #define OR_BLOCK(target) \
3024 if (ac && !strncmp(*av, "or", strlen(*av))) { \
3025 if (prev == NULL || open_par == 0) \
3026 errx(EX_DATAERR, "invalid OR block"); \
3027 prev->len |= F_OR; \
3037 * MAC addresses, optional.
3038 * If we have this, we skip the part "proto from src to dst"
3039 * and jump straight to the option parsing.
3042 NEED1("missing protocol");
3043 if (!strncmp(*av
, "MAC", strlen(*av
)) ||
3044 !strncmp(*av
, "mac", strlen(*av
))) {
3045 ac
--; av
++; /* the "MAC" keyword */
3046 add_mac(cmd
, ac
, av
); /* exits in case of errors */
3047 cmd
= next_cmd(cmd
);
3048 ac
-= 2; av
+= 2; /* dst-mac and src-mac */
3050 NEED1("missing mac type");
3051 if (add_mactype(cmd
, ac
, av
[0]))
3052 cmd
= next_cmd(cmd
);
3053 ac
--; av
++; /* any or mac-type */
3059 * protocol, mandatory
3061 OR_START(get_proto
);
3063 NEED1("missing protocol");
3064 if (add_proto(cmd
, *av
)) {
3066 if (F_LEN(cmd
) == 0) /* plain IP */
3071 cmd
= next_cmd(cmd
);
3073 } else if (first_cmd
!= cmd
) {
3074 errx(EX_DATAERR
, "invalid protocol ``%s''", *av
);
3077 OR_BLOCK(get_proto
);
3082 if (!ac
|| strncmp(*av
, "from", strlen(*av
)))
3083 errx(EX_USAGE
, "missing ``from''");
3087 * source IP, mandatory
3089 OR_START(source_ip
);
3090 NOT_BLOCK
; /* optional "not" */
3091 NEED1("missing source address");
3092 if (add_srcip(cmd
, *av
)) {
3094 if (F_LEN(cmd
) != 0) { /* ! any */
3096 cmd
= next_cmd(cmd
);
3099 OR_BLOCK(source_ip
);
3102 * source ports, optional
3104 NOT_BLOCK
; /* optional "not" */
3106 if (!strncmp(*av
, "any", strlen(*av
)) ||
3107 add_ports(cmd
, *av
, proto
, O_IP_SRCPORT
)) {
3109 if (F_LEN(cmd
) != 0)
3110 cmd
= next_cmd(cmd
);
3117 if (!ac
|| strncmp(*av
, "to", strlen(*av
)))
3118 errx(EX_USAGE
, "missing ``to''");
3122 * destination, mandatory
3125 NOT_BLOCK
; /* optional "not" */
3126 NEED1("missing dst address");
3127 if (add_dstip(cmd
, *av
)) {
3129 if (F_LEN(cmd
) != 0) { /* ! any */
3131 cmd
= next_cmd(cmd
);
3137 * dest. ports, optional
3139 NOT_BLOCK
; /* optional "not" */
3141 if (!strncmp(*av
, "any", strlen(*av
)) ||
3142 add_ports(cmd
, *av
, proto
, O_IP_DSTPORT
)) {
3144 if (F_LEN(cmd
) != 0)
3145 cmd
= next_cmd(cmd
);
3150 if (ac
&& first_cmd
== cmd
) {
3152 * nothing specified so far, store in the rule to ease
3160 ipfw_insn_u32
*cmd32
; /* alias for cmd */
3163 cmd32
= (ipfw_insn_u32
*)cmd
;
3165 if (*s
== '!') { /* alternate syntax for NOT */
3166 if (cmd
->len
& F_NOT
)
3167 errx(EX_USAGE
, "double \"not\" not allowed\n");
3171 i
= match_token(rule_options
, s
);
3175 if (cmd
->len
& F_NOT
)
3176 errx(EX_USAGE
, "double \"not\" not allowed\n");
3181 if (open_par
== 0 || prev
== NULL
)
3182 errx(EX_USAGE
, "invalid \"or\" block\n");
3186 case TOK_STARTBRACE
:
3188 errx(EX_USAGE
, "+nested \"(\" not allowed\n");
3194 errx(EX_USAGE
, "+missing \")\"\n");
3200 fill_cmd(cmd
, O_IN
, 0, 0);
3204 cmd
->len
^= F_NOT
; /* toggle F_NOT */
3205 fill_cmd(cmd
, O_IN
, 0, 0);
3209 fill_cmd(cmd
, O_FRAG
, 0, 0);
3213 fill_cmd(cmd
, O_LAYER2
, 0, 0);
3219 NEED1("recv, xmit, via require interface name"
3221 fill_iface((ipfw_insn_if
*)cmd
, av
[0]);
3223 if (F_LEN(cmd
) == 0) /* not a valid address */
3226 cmd
->opcode
= O_XMIT
;
3227 else if (i
== TOK_RECV
)
3228 cmd
->opcode
= O_RECV
;
3229 else if (i
== TOK_VIA
)
3230 cmd
->opcode
= O_VIA
;
3234 NEED1("icmptypes requires list of types");
3235 fill_icmptypes((ipfw_insn_u32
*)cmd
, *av
);
3240 NEED1("ipttl requires TTL");
3241 if (strpbrk(*av
, "-,")) {
3242 if (!add_ports(cmd
, *av
, 0, O_IPTTL
))
3243 errx(EX_DATAERR
, "invalid ipttl %s", *av
);
3245 fill_cmd(cmd
, O_IPTTL
, 0, strtoul(*av
, NULL
, 0));
3250 NEED1("ipid requires id");
3251 if (strpbrk(*av
, "-,")) {
3252 if (!add_ports(cmd
, *av
, 0, O_IPID
))
3253 errx(EX_DATAERR
, "invalid ipid %s", *av
);
3255 fill_cmd(cmd
, O_IPID
, 0, strtoul(*av
, NULL
, 0));
3260 NEED1("iplen requires length");
3261 if (strpbrk(*av
, "-,")) {
3262 if (!add_ports(cmd
, *av
, 0, O_IPLEN
))
3263 errx(EX_DATAERR
, "invalid ip len %s", *av
);
3265 fill_cmd(cmd
, O_IPLEN
, 0, strtoul(*av
, NULL
, 0));
3270 NEED1("ipver requires version");
3271 fill_cmd(cmd
, O_IPVER
, 0, strtoul(*av
, NULL
, 0));
3275 case TOK_IPPRECEDENCE
:
3276 NEED1("ipprecedence requires value");
3277 fill_cmd(cmd
, O_IPPRECEDENCE
, 0,
3278 (strtoul(*av
, NULL
, 0) & 7) << 5);
3283 NEED1("missing argument for ipoptions");
3284 fill_flags(cmd
, O_IPOPT
, f_ipopts
, *av
);
3289 NEED1("missing argument for iptos");
3290 fill_flags(cmd
, O_IPTOS
, f_iptos
, *av
);
3295 NEED1("uid requires argument");
3301 cmd
->opcode
= O_UID
;
3302 uid
= strtoul(*av
, &end
, 0);
3303 pwd
= (*end
== '\0') ? getpwuid(uid
) : getpwnam(*av
);
3305 errx(EX_DATAERR
, "uid \"%s\" nonexistent", *av
);
3306 cmd32
->d
[0] = pwd
->pw_uid
;
3307 cmd
->len
= F_INSN_SIZE(ipfw_insn_u32
);
3313 NEED1("gid requires argument");
3319 cmd
->opcode
= O_GID
;
3320 gid
= strtoul(*av
, &end
, 0);
3321 grp
= (*end
== '\0') ? getgrgid(gid
) : getgrnam(*av
);
3323 errx(EX_DATAERR
, "gid \"%s\" nonexistent", *av
);
3324 cmd32
->d
[0] = grp
->gr_gid
;
3325 cmd
->len
= F_INSN_SIZE(ipfw_insn_u32
);
3331 fill_cmd(cmd
, O_ESTAB
, 0, 0);
3335 fill_cmd(cmd
, O_TCPFLAGS
, 0,
3336 (TH_SYN
) | ( (TH_ACK
) & 0xff) <<8 );
3340 NEED1("missing argument for tcpoptions");
3341 fill_flags(cmd
, O_TCPOPTS
, f_tcpopts
, *av
);
3347 NEED1("tcpseq/tcpack requires argument");
3348 cmd
->len
= F_INSN_SIZE(ipfw_insn_u32
);
3349 cmd
->opcode
= (i
== TOK_TCPSEQ
) ? O_TCPSEQ
: O_TCPACK
;
3350 cmd32
->d
[0] = htonl(strtoul(*av
, NULL
, 0));
3355 NEED1("tcpwin requires length");
3356 fill_cmd(cmd
, O_TCPWIN
, 0,
3357 htons(strtoul(*av
, NULL
, 0)));
3362 NEED1("missing argument for tcpflags");
3363 cmd
->opcode
= O_TCPFLAGS
;
3364 fill_flags(cmd
, O_TCPFLAGS
, f_tcpflags
, *av
);
3370 errx(EX_USAGE
, "keep-state cannot be part "
3373 errx(EX_USAGE
, "only one of keep-state "
3374 "and limit is allowed");
3376 fill_cmd(cmd
, O_KEEP_STATE
, 0, 0);
3381 errx(EX_USAGE
, "limit cannot be part "
3384 errx(EX_USAGE
, "only one of keep-state "
3385 "and limit is allowed");
3386 NEED1("limit needs mask and # of connections");
3389 ipfw_insn_limit
*c
= (ipfw_insn_limit
*)cmd
;
3391 cmd
->len
= F_INSN_SIZE(ipfw_insn_limit
);
3392 cmd
->opcode
= O_LIMIT
;
3398 val
= match_token(limit_masks
, *av
);
3401 c
->limit_mask
|= val
;
3404 c
->conn_limit
= atoi(*av
);
3405 if (c
->conn_limit
== 0)
3406 errx(EX_USAGE
, "limit: limit must be >0");
3407 if (c
->limit_mask
== 0)
3408 errx(EX_USAGE
, "missing limit mask");
3414 NEED1("missing protocol");
3415 if (add_proto(cmd
, *av
)) {
3419 errx(EX_DATAERR
, "invalid protocol ``%s''",
3424 NEED1("missing source IP");
3425 if (add_srcip(cmd
, *av
)) {
3431 NEED1("missing destination IP");
3432 if (add_dstip(cmd
, *av
)) {
3438 NEED1("missing source port");
3439 if (!strncmp(*av
, "any", strlen(*av
)) ||
3440 add_ports(cmd
, *av
, proto
, O_IP_SRCPORT
)) {
3443 errx(EX_DATAERR
, "invalid source port %s", *av
);
3447 NEED1("missing destination port");
3448 if (!strncmp(*av
, "any", strlen(*av
)) ||
3449 add_ports(cmd
, *av
, proto
, O_IP_DSTPORT
)) {
3452 errx(EX_DATAERR
, "invalid destination port %s",
3458 errx(EX_USAGE
, "MAC dst-mac src-mac");
3459 if (add_mac(cmd
, ac
, av
)) {
3465 NEED1("missing mac type");
3466 if (!add_mactype(cmd
, ac
, *av
))
3467 errx(EX_DATAERR
, "invalid mac type %s", *av
);
3471 case TOK_VERREVPATH
:
3472 fill_cmd(cmd
, O_VERREVPATH
, 0, 0);
3476 fill_cmd(cmd
, O_IPSEC
, 0, 0);
3480 fill_comment(cmd
, ac
, av
);
3486 errx(EX_USAGE
, "unrecognised option [%d] %s\n", i
, s
);
3488 if (F_LEN(cmd
) > 0) { /* prepare to advance */
3490 cmd
= next_cmd(cmd
);
3496 * Now copy stuff into the rule.
3497 * If we have a keep-state option, the first instruction
3498 * must be a PROBE_STATE (which is generated here).
3499 * If we have a LOG option, it was stored as the first command,
3500 * and now must be moved to the top of the action part.
3502 dst
= (ipfw_insn
*)rule
->cmd
;
3505 * First thing to write into the command stream is the match probability.
3507 if (match_prob
!= 1) { /* 1 means always match */
3508 dst
->opcode
= O_PROB
;
3510 *((int32_t *)(dst
+1)) = (int32_t)(match_prob
* 0x7fffffff);
3515 * generate O_PROBE_STATE if necessary
3517 if (have_state
&& have_state
->opcode
!= O_CHECK_STATE
) {
3518 fill_cmd(dst
, O_PROBE_STATE
, 0, 0);
3519 dst
= next_cmd(dst
);
3522 * copy all commands but O_LOG, O_KEEP_STATE, O_LIMIT
3524 for (src
= (ipfw_insn
*)cmdbuf
; src
!= cmd
; src
+= i
) {
3527 switch (src
->opcode
) {
3533 bcopy(src
, dst
, i
* sizeof(uint32_t));
3539 * put back the have_state command as last opcode
3541 if (have_state
&& have_state
->opcode
!= O_CHECK_STATE
) {
3542 i
= F_LEN(have_state
);
3543 bcopy(have_state
, dst
, i
* sizeof(uint32_t));
3547 * start action section
3549 rule
->act_ofs
= dst
- rule
->cmd
;
3552 * put back O_LOG if necessary
3554 src
= (ipfw_insn
*)cmdbuf
;
3555 if (src
->opcode
== O_LOG
) {
3557 bcopy(src
, dst
, i
* sizeof(uint32_t));
3561 * copy all other actions
3563 for (src
= (ipfw_insn
*)actbuf
; src
!= action
; src
+= i
) {
3565 bcopy(src
, dst
, i
* sizeof(uint32_t));
3569 rule
->cmd_len
= (uint32_t *)dst
- (uint32_t *)(rule
->cmd
);
3570 i
= (char *)dst
- (char *)rule
;
3572 if (do_cmd(IP_FW_ADD
, rule
, (uintptr_t)&i
) == -1)
3573 err(EX_UNAVAILABLE
, "getsockopt(%s)", "IP_FW_ADD");
3575 show_ipfw(rule
, 0, 0);
3579 zero(int ac
, char *av
[], int optname
/* IP_FW_ZERO or IP_FW_RESETLOG */)
3584 char const *name
= optname
== IP_FW_ZERO
? "ZERO" : "RESETLOG";
3587 bzero(&rule
, sizeof(rule
));
3590 /* clear all entries - send empty rule */
3591 if (do_cmd(optname
, &rule
, sizeof(rule
)) < 0)
3592 err(EX_UNAVAILABLE
, "setsockopt(IP_FW_%s)", name
);
3594 printf("%s.\n", optname
== IP_FW_ZERO
?
3595 "Accounting cleared":"Logging counts reset");
3602 if (isdigit(**av
)) {
3603 rulenum
= atoi(*av
);
3606 rule
.rulenum
= rulenum
;
3607 if (do_cmd(optname
, &rule
, sizeof(rule
))) {
3608 warn("rule %u: setsockopt(IP_FW_%s)",
3610 failed
= EX_UNAVAILABLE
;
3611 } else if (!do_quiet
)
3612 printf("Entry %d %s.\n", rulenum
,
3613 optname
== IP_FW_ZERO
?
3614 "cleared" : "logging count reset");
3616 errx(EX_USAGE
, "invalid rule number ``%s''", *av
);
3619 if (failed
!= EX_OK
)
3626 int cmd
= do_pipe
? IP_DUMMYNET_FLUSH
: IP_FW_FLUSH
;
3629 if (!force
&& !do_quiet
) { /* need to ask user */
3632 printf("Are you sure? [yn] ");
3635 c
= toupper(getc(stdin
));
3636 while (c
!= '\n' && getc(stdin
) != '\n')
3638 return; /* and do not flush */
3639 } while (c
!= 'Y' && c
!= 'N');
3641 if (c
== 'N') /* user said no */
3645 if (cmd
== IP_FW_FLUSH
) {
3646 /* send empty rule */
3647 bzero(&rule
, sizeof(rule
));
3648 if (do_cmd(cmd
, &rule
, sizeof(rule
)) < 0)
3649 err(EX_UNAVAILABLE
, "setsockopt(IP_FW_FLUSH)");
3652 if (do_cmd(cmd
, NULL
, 0) < 0)
3653 err(EX_UNAVAILABLE
, "setsockopt(IP_DUMMYNET_FLUSH)");
3656 printf("Flushed all %s.\n", do_pipe
? "pipes" : "rules");
3660 * Free a the (locally allocated) copy of command line arguments.
3663 free_args(int ac
, char **av
)
3667 for (i
=0; i
< ac
; i
++)
3673 * Called with the arguments (excluding program name).
3674 * Returns 0 if successful, 1 if empty command, errx() in case of errors.
3677 ipfw_main(int oldac
, char **oldav
)
3679 int ch
, ac
, save_ac
;
3680 char **av
, **save_av
;
3681 int do_acct
= 0; /* Show packet/byte count */
3682 int do_force
= 0; /* Don't ask for confirmation */
3684 #define WHITESP " \t\f\v\n\r"
3687 else if (oldac
== 1) {
3689 * If we are called with a single string, try to split it into
3690 * arguments for subsequent parsing.
3691 * But first, remove spaces after a ',', by copying the string
3694 char *arg
= oldav
[0]; /* The string... */
3695 int l
= strlen(arg
);
3696 int copy
= 0; /* 1 if we need to copy, 0 otherwise */
3698 for (i
= j
= 0; i
< l
; i
++) {
3699 if (arg
[i
] == '#') /* comment marker */
3703 copy
= !index("," WHITESP
, arg
[i
]);
3705 copy
= !index(WHITESP
, arg
[i
]);
3710 if (!copy
&& j
> 0) /* last char was a 'blank', remove it */
3712 l
= j
; /* the new argument length */
3714 if (l
== 0) /* empty string! */
3718 * First, count number of arguments. Because of the previous
3719 * processing, this is just the number of blanks plus 1.
3721 for (i
= 0, ac
= 1; i
< l
; i
++)
3722 if (index(WHITESP
, arg
[i
]) != NULL
)
3725 av
= calloc(ac
, sizeof(char *));
3728 * Second, copy arguments from cmd[] to av[]. For each one,
3729 * j is the initial character, i is the one past the end.
3731 for (ac
= 0, i
= j
= 0; i
< l
; i
++)
3732 if (index(WHITESP
, arg
[i
]) != NULL
|| i
== l
-1) {
3735 av
[ac
] = calloc(i
-j
+1, 1);
3736 bcopy(arg
+j
, av
[ac
], i
-j
);
3742 * If an argument ends with ',' join with the next one.
3746 av
= calloc(oldac
, sizeof(char *));
3747 for (first
= i
= ac
= 0, l
= 0; i
< oldac
; i
++) {
3748 char *arg
= oldav
[i
];
3749 int k
= strlen(arg
);
3752 if (arg
[k
-1] != ',' || i
== oldac
-1) {
3754 av
[ac
] = calloc(l
+1, 1);
3755 for (l
=0; first
<= i
; first
++) {
3756 strcat(av
[ac
]+l
, oldav
[first
]);
3757 l
+= strlen(oldav
[first
]);
3766 /* Set the force flag for non-interactive processes */
3767 do_force
= !isatty(STDIN_FILENO
);
3769 /* Save arguments for final freeing of memory. */
3773 optind
= optreset
= 0;
3774 while ((ch
= getopt(ac
, av
, "acdefhnNqs:STtv")) != -1)
3796 case 'h': /* help */
3797 free_args(save_ac
, save_av
);
3799 break; /* NOTREACHED */
3813 case 's': /* sort */
3814 do_sort
= atoi(optarg
);
3826 do_time
= 2; /* numeric timestamp */
3829 case 'v': /* verbose */
3834 free_args(save_ac
, save_av
);
3840 NEED1("bad arguments, for usage summary ``ipfw''");
3843 * An undocumented behaviour of ipfw1 was to allow rule numbers first,
3844 * e.g. "100 add allow ..." instead of "add 100 allow ...".
3845 * In case, swap first and second argument to get the normal form.
3847 if (ac
> 1 && isdigit(*av
[0])) {
3855 * optional: pipe or queue
3858 if (!strncmp(*av
, "pipe", strlen(*av
)))
3860 else if (!strncmp(*av
, "queue", strlen(*av
)))
3866 NEED1("missing command");
3869 * For pipes and queues we normally say 'pipe NN config'
3870 * but the code is easier to parse as 'pipe config NN'
3871 * so we swap the two arguments.
3873 if (do_pipe
> 0 && ac
> 1 && isdigit(*av
[0])) {
3880 if (!strncmp(*av
, "add", strlen(*av
)))
3882 else if (do_pipe
&& !strncmp(*av
, "config", strlen(*av
)))
3883 config_pipe(ac
, av
);
3884 else if (!strncmp(*av
, "delete", strlen(*av
)))
3886 else if (!strncmp(*av
, "flush", strlen(*av
)))
3888 else if (!strncmp(*av
, "zero", strlen(*av
)))
3889 zero(ac
, av
, IP_FW_ZERO
);
3890 else if (!strncmp(*av
, "resetlog", strlen(*av
)))
3891 zero(ac
, av
, IP_FW_RESETLOG
);
3892 else if (!strncmp(*av
, "print", strlen(*av
)) ||
3893 !strncmp(*av
, "list", strlen(*av
)))
3894 list(ac
, av
, do_acct
);
3895 else if (!strncmp(*av
, "set", strlen(*av
)))
3896 sets_handler(ac
, av
);
3897 else if (!strncmp(*av
, "enable", strlen(*av
)))
3898 sysctl_handler(ac
, av
, 1);
3899 else if (!strncmp(*av
, "disable", strlen(*av
)))
3900 sysctl_handler(ac
, av
, 0);
3901 else if (!strncmp(*av
, "show", strlen(*av
)))
3902 list(ac
, av
, 1 /* show counters */);
3904 errx(EX_USAGE
, "bad command `%s'", *av
);
3906 /* Free memory allocated in the argument parsing. */
3907 free_args(save_ac
, save_av
);
3913 ipfw_readfile(int ac
, char *av
[])
3917 char *cmd
= NULL
, *filename
= av
[ac
-1];
3922 filename
= av
[ac
-1];
3924 while ((c
= getopt(ac
, av
, "cNnp:qS")) != -1) {
3941 * Skip previous args and delete last one, so we
3942 * pass all but the last argument to the preprocessor
3948 fprintf(stderr
, "command is %s\n", av
[0]);
3960 errx(EX_USAGE
, "bad arguments, for usage"
3961 " summary ``ipfw''");
3968 if (cmd
== NULL
&& ac
!= optind
+ 1) {
3969 fprintf(stderr
, "ac %d, optind %d\n", ac
, optind
);
3970 errx(EX_USAGE
, "extraneous filename arguments");
3973 if ((f
= fopen(filename
, "r")) == NULL
)
3974 err(EX_UNAVAILABLE
, "fopen: %s", filename
);
3976 if (cmd
!= NULL
) { /* pipe through preprocessor */
3979 if (pipe(pipedes
) == -1)
3980 err(EX_OSERR
, "cannot create pipe");
3984 err(EX_OSERR
, "cannot fork");
3988 * Child, will run the preprocessor with the
3989 * file on stdin and the pipe on stdout.
3991 if (dup2(fileno(f
), 0) == -1
3992 || dup2(pipedes
[1], 1) == -1)
3993 err(EX_OSERR
, "dup2()");
3998 err(EX_OSERR
, "execvp(%s) failed", cmd
);
3999 } else { /* parent, will reopen f as the pipe */
4002 if ((f
= fdopen(pipedes
[0], "r")) == NULL
) {
4003 int savederrno
= errno
;
4005 (void)kill(preproc
, SIGTERM
);
4007 err(EX_OSERR
, "fdopen()");
4012 while (fgets(buf
, BUFSIZ
, f
)) { /* read commands */
4017 sprintf(linename
, "Line %d", lineno
);
4018 setprogname(linename
); /* XXX */
4026 if (waitpid(preproc
, &status
, 0) == -1)
4027 errx(EX_OSERR
, "waitpid()");
4028 if (WIFEXITED(status
) && WEXITSTATUS(status
) != EX_OK
)
4029 errx(EX_UNAVAILABLE
,
4030 "preprocessor exited with status %d",
4031 WEXITSTATUS(status
));
4032 else if (WIFSIGNALED(status
))
4033 errx(EX_UNAVAILABLE
,
4034 "preprocessor exited with signal %d",
4040 main(int ac
, char *av
[])
4043 * If the last argument is an absolute pathname, interpret it
4044 * as a file to be preprocessed.
4047 if (ac
> 1 && av
[ac
- 1][0] == '/' && access(av
[ac
- 1], R_OK
) == 0)
4048 ipfw_readfile(ac
, av
);
4050 if (ipfw_main(ac
-1, av
+1))