2 * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 * Copyright (c) 2002-2003 Luigi Rizzo
24 * Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp
25 * Copyright (c) 1994 Ugen J.S.Antsilevich
27 * Idea and grammar partially left from:
28 * Copyright (c) 1993 Daniel Boulet
30 * Redistribution and use in source forms, with and without modification,
31 * are permitted provided that this entire comment appears intact.
33 * Redistribution in binary form may occur without any restrictions.
34 * Obviously, it would be nice if you gave credit where credit is due
35 * but requiring it would be too onerous.
37 * This software is provided ``AS IS'' without any warranties of any kind.
39 * NEW command line interface for IP firewall facility
41 * $FreeBSD: /repoman/r/ncvs/src/sbin/ipfw/ipfw2.c,v 1.4.2.18 2003/09/15 10:27:03 luigi Exp $
44 #include <sys/param.h>
46 #include <sys/socket.h>
47 #include <sys/sockio.h>
48 #include <sys/sysctl.h>
68 #include <netinet/in.h>
69 #include <netinet/in_systm.h>
70 #include <netinet/ip.h>
71 #include <netinet/ip_icmp.h>
73 #include <netinet/ip_fw.h>
75 #include <net/route.h> /* def. of struct route */
76 #include <netinet/ip_dummynet.h>
77 #include <netinet/tcp.h>
78 #include <arpa/inet.h>
81 do_resolv
, /* Would try to resolve all */
82 do_time
, /* Show time stamps */
83 do_quiet
, /* Be quiet in add and flush */
84 do_pipe
, /* this cmd refers to a pipe */
85 do_sort
, /* field to sort results (0 = no) */
86 do_dynamic
, /* display dynamic rules */
87 do_expired
, /* display expired dynamic rules */
88 do_compact
, /* show rules in compact mode */
89 show_sets
, /* display rule sets */
90 test_only
, /* only check syntax */
93 #define IP_MASK_ALL 0xffffffff
96 * _s_x is a structure that stores a string <-> token pairs, used in
97 * various places in the parser. Entries are stored in arrays,
98 * with an entry with s=NULL as terminator.
99 * The search routines are match_token() and match_value().
100 * Often, an element with x=0 contains an error string.
108 static struct _s_x f_tcpflags
[] = {
119 static struct _s_x f_tcpopts
[] = {
120 { "mss", IP_FW_TCPOPT_MSS
},
121 { "maxseg", IP_FW_TCPOPT_MSS
},
122 { "window", IP_FW_TCPOPT_WINDOW
},
123 { "sack", IP_FW_TCPOPT_SACK
},
124 { "ts", IP_FW_TCPOPT_TS
},
125 { "timestamp", IP_FW_TCPOPT_TS
},
126 { "cc", IP_FW_TCPOPT_CC
},
132 * IP options span the range 0 to 255 so we need to remap them
133 * (though in fact only the low 5 bits are significant).
135 static struct _s_x f_ipopts
[] = {
136 { "ssrr", IP_FW_IPOPT_SSRR
},
137 { "lsrr", IP_FW_IPOPT_LSRR
},
138 { "rr", IP_FW_IPOPT_RR
},
139 { "ts", IP_FW_IPOPT_TS
},
144 static struct _s_x f_iptos
[] = {
145 { "lowdelay", IPTOS_LOWDELAY
},
146 { "throughput", IPTOS_THROUGHPUT
},
147 { "reliability", IPTOS_RELIABILITY
},
148 { "mincost", IPTOS_MINCOST
},
149 { "congestion", IPTOS_CE
},
150 { "ecntransport", IPTOS_ECT
},
151 { "ip tos option", 0},
155 static struct _s_x limit_masks
[] = {
156 {"all", DYN_SRC_ADDR
|DYN_SRC_PORT
|DYN_DST_ADDR
|DYN_DST_PORT
},
157 {"src-addr", DYN_SRC_ADDR
},
158 {"src-port", DYN_SRC_PORT
},
159 {"dst-addr", DYN_DST_ADDR
},
160 {"dst-port", DYN_DST_PORT
},
165 * we use IPPROTO_ETHERTYPE as a fake protocol id to call the print routines
166 * This is only used in this code.
168 #define IPPROTO_ETHERTYPE 0x1000
169 static struct _s_x ether_types
[] = {
171 * Note, we cannot use "-:&/" in the names because they are field
172 * separators in the type specifications. Also, we use s = NULL as
173 * end-delimiter, because a type of 0 can be legal.
186 { "pppoe_disc", 0x8863 },
187 { "pppoe_sess", 0x8864 },
188 { "ipx_8022", 0x00E0 },
189 { "ipx_8023", 0x0000 },
190 { "ipx_ii", 0x8137 },
191 { "ipx_snap", 0x8137 },
197 static struct _s_x exception_types
[] = {
209 static void show_usage(void);
283 struct _s_x dummynet_params
[] = {
285 { "noerror", TOK_NOERROR
},
286 { "buckets", TOK_BUCKETS
},
287 { "dst-ip", TOK_DSTIP
},
288 { "src-ip", TOK_SRCIP
},
289 { "dst-port", TOK_DSTPORT
},
290 { "src-port", TOK_SRCPORT
},
291 { "proto", TOK_PROTO
},
292 { "weight", TOK_WEIGHT
},
294 { "mask", TOK_MASK
},
295 { "droptail", TOK_DROPTAIL
},
297 { "gred", TOK_GRED
},
299 { "bandwidth", TOK_BW
},
300 { "delay", TOK_DELAY
},
301 { "pipe", TOK_PIPE
},
302 { "queue", TOK_QUEUE
},
303 { "dummynet-params", TOK_NULL
},
304 { NULL
, 0 } /* terminator */
307 struct _s_x rule_actions
[] = {
308 { "accept", TOK_ACCEPT
},
309 { "pass", TOK_ACCEPT
},
310 { "allow", TOK_ACCEPT
},
311 { "permit", TOK_ACCEPT
},
312 { "count", TOK_COUNT
},
313 { "pipe", TOK_PIPE
},
314 { "queue", TOK_QUEUE
},
315 { "divert", TOK_DIVERT
},
317 { "fwd", TOK_FORWARD
},
318 { "forward", TOK_FORWARD
},
319 { "skipto", TOK_SKIPTO
},
320 { "deny", TOK_DENY
},
321 { "drop", TOK_DENY
},
322 { "reject", TOK_REJECT
},
323 { "reset", TOK_RESET
},
324 { "unreach", TOK_UNREACH
},
325 { "check-state", TOK_CHECKSTATE
},
326 { "//", TOK_COMMENT
},
327 { NULL
, 0 } /* terminator */
330 struct _s_x rule_options
[] = {
334 { "limit", TOK_LIMIT
},
335 { "keep-state", TOK_KEEPSTATE
},
336 { "bridged", TOK_LAYER2
},
337 { "layer2", TOK_LAYER2
},
339 { "xmit", TOK_XMIT
},
340 { "recv", TOK_RECV
},
342 { "fragment", TOK_FRAG
},
343 { "frag", TOK_FRAG
},
344 { "ipoptions", TOK_IPOPTS
},
345 { "ipopts", TOK_IPOPTS
},
346 { "iplen", TOK_IPLEN
},
347 { "ipid", TOK_IPID
},
348 { "ipprecedence", TOK_IPPRECEDENCE
},
349 { "iptos", TOK_IPTOS
},
350 { "ipttl", TOK_IPTTL
},
351 { "ipversion", TOK_IPVER
},
352 { "ipver", TOK_IPVER
},
353 { "estab", TOK_ESTAB
},
354 { "established", TOK_ESTAB
},
355 { "setup", TOK_SETUP
},
356 { "tcpflags", TOK_TCPFLAGS
},
357 { "tcpflgs", TOK_TCPFLAGS
},
358 { "tcpoptions", TOK_TCPOPTS
},
359 { "tcpopts", TOK_TCPOPTS
},
360 { "tcpseq", TOK_TCPSEQ
},
361 { "tcpack", TOK_TCPACK
},
362 { "tcpwin", TOK_TCPWIN
},
363 { "icmptype", TOK_ICMPTYPES
},
364 { "icmptypes", TOK_ICMPTYPES
},
365 { "dst-ip", TOK_DSTIP
},
366 { "src-ip", TOK_SRCIP
},
367 { "dst-port", TOK_DSTPORT
},
368 { "src-port", TOK_SRCPORT
},
369 { "proto", TOK_PROTO
},
372 { "mac-type", TOK_MACTYPE
},
373 { "verrevpath", TOK_VERREVPATH
},
374 { "ipsec", TOK_IPSEC
},
375 { "//", TOK_COMMENT
},
377 { "not", TOK_NOT
}, /* pseudo option */
378 { "!", /* escape ? */ TOK_NOT
}, /* pseudo option */
379 { "or", TOK_OR
}, /* pseudo option */
380 { "|", /* escape */ TOK_OR
}, /* pseudo option */
381 { "{", TOK_STARTBRACE
}, /* pseudo option */
382 { "(", TOK_STARTBRACE
}, /* pseudo option */
383 { "}", TOK_ENDBRACE
}, /* pseudo option */
384 { ")", TOK_ENDBRACE
}, /* pseudo option */
385 { NULL
, 0 } /* terminator */
388 static __inline
uint64_t
389 align_uint64(uint64_t *pll
) {
392 bcopy (pll
, &ret
, sizeof(ret
));
397 * conditionally runs the command.
400 do_cmd(int optname
, void *optval
, uintptr_t optlen
)
402 static int s
= -1; /* the socket */
409 s
= socket(AF_INET
, SOCK_RAW
, IPPROTO_RAW
);
411 err(EX_UNAVAILABLE
, "socket");
420 ((struct ip_fw
*)optval
)->version
= IP_FW_CURRENT_API_VERSION
;
425 if (optname
== IP_FW_GET
|| optname
== IP_DUMMYNET_GET
||
426 optname
== IP_FW_ADD
)
427 i
= getsockopt(s
, IPPROTO_IP
, optname
, optval
,
428 (socklen_t
*)optlen
);
430 i
= setsockopt(s
, IPPROTO_IP
, optname
, optval
, optlen
);
435 * match_token takes a table and a string, returns the value associated
436 * with the string (-1 in case of failure).
439 match_token(struct _s_x
*table
, char *string
)
442 uint i
= strlen(string
);
444 for (pt
= table
; i
&& pt
->s
!= NULL
; pt
++)
445 if (strlen(pt
->s
) == i
&& !bcmp(string
, pt
->s
, i
))
451 * match_value takes a table and a value, returns the string associated
452 * with the value (NULL in case of failure).
455 match_value(struct _s_x
*p
, int value
)
457 for (; p
->s
!= NULL
; p
++)
464 * prints one port, symbolic or numeric
467 print_port(int proto
, uint16_t port
)
470 if (proto
== IPPROTO_ETHERTYPE
) {
473 if (do_resolv
&& (s
= match_value(ether_types
, port
)) )
476 printf("0x%04x", port
);
478 struct servent
*se
= NULL
;
480 struct protoent
*pe
= getprotobynumber(proto
);
482 se
= getservbyport(htons(port
), pe
? pe
->p_name
: NULL
);
485 printf("%s", se
->s_name
);
491 struct _s_x _port_name
[] = {
492 {"dst-port", O_IP_DSTPORT
},
493 {"src-port", O_IP_SRCPORT
},
497 {"mac-type", O_MAC_TYPE
},
502 * Print the values in a list 16-bit items of the types above.
503 * XXX todo: add support for mask.
506 print_newports(ipfw_insn_u16
*cmd
, int proto
, int opcode
)
508 uint16_t *p
= cmd
->ports
;
512 if (cmd
->o
.len
& F_NOT
)
515 sep
= match_value(_port_name
, opcode
);
521 for (i
= F_LEN((ipfw_insn
*)cmd
) - 1; i
> 0; i
--, p
+= 2) {
523 print_port(proto
, p
[0]);
526 print_port(proto
, p
[1]);
533 * Like strtol, but also translates service names into port numbers
534 * for some protocols.
536 * proto == -1 disables the protocol check;
537 * proto == IPPROTO_ETHERTYPE looks up an internal table
538 * proto == <some value in /etc/protocols> matches the values there.
539 * Returns *end == s in case the parameter is not found.
542 strtoport(char *s
, char **end
, int base
, int proto
)
548 *end
= s
; /* default - not found */
550 return 0; /* not found */
553 return strtol(s
, end
, base
);
556 * find separator. '\\' escapes the next char.
558 for (s1
= s
; *s1
&& (isalnum(*s1
) || *s1
== '\\') ; s1
++)
559 if (*s1
== '\\' && s1
[1] != '\0')
562 buf
= malloc(s1
- s
+ 1);
567 * copy into a buffer skipping backslashes
569 for (p
= s
, i
= 0; p
!= s1
; p
++)
574 if ( match_token( exception_types
, buf
) != -1 ){
579 if (proto
== IPPROTO_ETHERTYPE
) {
580 i
= match_token(ether_types
, buf
);
582 if (i
!= -1) { /* found */
587 struct protoent
*pe
= NULL
;
591 pe
= getprotobynumber(proto
);
593 se
= getservbyname(buf
, pe
? pe
->p_name
: NULL
);
597 return ntohs(se
->s_port
);
600 return 0; /* not found */
604 * Fill the body of the command with the list of port ranges.
607 fill_newports(ipfw_insn_u16
*cmd
, char *av
, int proto
)
609 uint16_t a
, b
, *p
= cmd
->ports
;
614 a
= strtoport(av
, &s
, 0, proto
);
615 if (s
== av
) /* no parameter */
617 if (*s
== '-') { /* a range */
619 b
= strtoport(av
, &s
, 0, proto
);
620 if (s
== av
) /* no parameter */
624 } else if (*s
== ',' || *s
== '\0' )
626 else /* invalid separator */
627 errx(EX_DATAERR
, "invalid separator <%c> in <%s>\n",
634 if (i
+1 > F_LEN_MASK
)
635 errx(EX_DATAERR
, "too many ports/ranges\n");
636 cmd
->o
.len
|= i
+1; /* leave F_NOT and F_OR untouched */
641 static struct _s_x icmpcodes
[] = {
642 { "net", ICMP_UNREACH_NET
},
643 { "host", ICMP_UNREACH_HOST
},
644 { "protocol", ICMP_UNREACH_PROTOCOL
},
645 { "port", ICMP_UNREACH_PORT
},
646 { "needfrag", ICMP_UNREACH_NEEDFRAG
},
647 { "srcfail", ICMP_UNREACH_SRCFAIL
},
648 { "net-unknown", ICMP_UNREACH_NET_UNKNOWN
},
649 { "host-unknown", ICMP_UNREACH_HOST_UNKNOWN
},
650 { "isolated", ICMP_UNREACH_ISOLATED
},
651 { "net-prohib", ICMP_UNREACH_NET_PROHIB
},
652 { "host-prohib", ICMP_UNREACH_HOST_PROHIB
},
653 { "tosnet", ICMP_UNREACH_TOSNET
},
654 { "toshost", ICMP_UNREACH_TOSHOST
},
655 { "filter-prohib", ICMP_UNREACH_FILTER_PROHIB
},
656 { "host-precedence", ICMP_UNREACH_HOST_PRECEDENCE
},
657 { "precedence-cutoff", ICMP_UNREACH_PRECEDENCE_CUTOFF
},
662 fill_reject_code(u_short
*codep
, char *str
)
667 val
= strtoul(str
, &s
, 0);
668 if (s
== str
|| *s
!= '\0' || val
>= 0x100)
669 val
= match_token(icmpcodes
, str
);
671 errx(EX_DATAERR
, "unknown ICMP unreachable code ``%s''", str
);
677 print_reject_code(uint16_t code
)
679 char const *s
= match_value(icmpcodes
, code
);
682 printf("unreach %s", s
);
684 printf("unreach %u", code
);
688 * Returns the number of bits set (from left) in a contiguous bitmask,
689 * or -1 if the mask is not contiguous.
690 * XXX this needs a proper fix.
691 * This effectively works on masks in big-endian (network) format.
692 * when compiled on little endian architectures.
694 * First bit is bit 7 of the first byte -- note, for MAC addresses,
695 * the first bit on the wire is bit 0 of the first byte.
696 * len is the max length in bits.
699 contigmask(uint8_t *p
, int len
)
703 for (i
=0; i
<len
; i
++)
704 if ( (p
[i
/8] & (1 << (7 - (i%8
)))) == 0) /* first bit unset */
706 for (n
=i
+1; n
< len
; n
++)
707 if ( (p
[n
/8] & (1 << (7 - (n%8
)))) != 0)
708 return -1; /* mask not contiguous */
713 * print flags set/clear in the two bitmasks passed as parameters.
714 * There is a specialized check for f_tcpflags.
717 print_flags(char const *name
, ipfw_insn
*cmd
, struct _s_x
*list
)
719 char const *comma
= "";
721 uint8_t set
= cmd
->arg1
& 0xff;
722 uint8_t clear
= (cmd
->arg1
>> 8) & 0xff;
724 if (list
== f_tcpflags
&& set
== TH_SYN
&& clear
== TH_ACK
) {
729 printf(" %s ", name
);
730 for (i
=0; list
[i
].x
!= 0; i
++) {
731 if (set
& list
[i
].x
) {
733 printf("%s%s", comma
, list
[i
].s
);
736 if (clear
& list
[i
].x
) {
738 printf("%s!%s", comma
, list
[i
].s
);
745 * Print the ip address contained in a command.
748 print_ip(ipfw_insn_ip
*cmd
, char const *s
)
750 struct hostent
*he
= NULL
;
751 int len
= F_LEN((ipfw_insn
*)cmd
);
752 uint32_t *a
= ((ipfw_insn_u32
*)cmd
)->d
;
754 printf("%s%s ", cmd
->o
.len
& F_NOT
? " not": "", s
);
756 if (cmd
->o
.opcode
== O_IP_SRC_ME
|| cmd
->o
.opcode
== O_IP_DST_ME
) {
760 if (cmd
->o
.opcode
== O_IP_SRC_SET
|| cmd
->o
.opcode
== O_IP_DST_SET
) {
761 uint32_t x
, *map
= (uint32_t *)&(cmd
->mask
);
767 cmd
->addr
.s_addr
= htonl(cmd
->addr
.s_addr
);
768 printf("%s/%d", inet_ntoa(cmd
->addr
),
769 contigmask((uint8_t *)&x
, 32));
770 x
= cmd
->addr
.s_addr
= htonl(cmd
->addr
.s_addr
);
771 x
&= 0xff; /* base */
773 * Print bits and ranges.
774 * Locate first bit set (i), then locate first bit unset (j).
775 * If we have 3+ consecutive bits set, then print them as a
776 * range, otherwise only print the initial bit and rescan.
778 for (i
=0; i
< cmd
->o
.arg1
; i
++)
779 if (map
[i
/32] & (1<<(i
& 31))) {
780 for (j
=i
+1; j
< cmd
->o
.arg1
; j
++)
781 if (!(map
[ j
/32] & (1<<(j
& 31))))
783 printf("%c%d", comma
, i
+x
);
784 if (j
>i
+2) { /* range has at least 3 elements */
785 printf("-%d", j
-1+x
);
794 * len == 2 indicates a single IP, whereas lists of 1 or more
795 * addr/mask pairs have len = (2n+1). We convert len to n so we
796 * use that to count the number of entries.
798 for (len
= len
/ 2; len
> 0; len
--, a
+= 2) {
799 int mb
= /* mask length */
800 (cmd
->o
.opcode
== O_IP_SRC
|| cmd
->o
.opcode
== O_IP_DST
) ?
801 32 : contigmask((uint8_t *)&(a
[1]), 32);
802 if (mb
== 32 && do_resolv
)
803 he
= gethostbyaddr((char *)&(a
[0]), sizeof(in_addr_t
), AF_INET
);
804 if (he
!= NULL
) /* resolved to name */
805 printf("%s", he
->h_name
);
806 else if (mb
== 0) /* any */
808 else { /* numeric IP followed by some kind of mask */
809 printf("%s", inet_ntoa( *((struct in_addr
*)&a
[0]) ) );
811 printf(":%s", inet_ntoa( *((struct in_addr
*)&a
[1]) ) );
821 * prints a MAC address/mask pair
824 print_mac(uint8_t *addr
, uint8_t *mask
)
826 int l
= contigmask(mask
, 48);
831 printf(" %02x:%02x:%02x:%02x:%02x:%02x",
832 addr
[0], addr
[1], addr
[2], addr
[3], addr
[4], addr
[5]);
834 printf("&%02x:%02x:%02x:%02x:%02x:%02x",
835 mask
[0], mask
[1], mask
[2],
836 mask
[3], mask
[4], mask
[5]);
843 fill_icmptypes(ipfw_insn_u32
*cmd
, char *av
)
852 type
= strtoul(av
, &av
, 0);
854 if (*av
!= ',' && *av
!= '\0')
855 errx(EX_DATAERR
, "invalid ICMP type");
858 errx(EX_DATAERR
, "ICMP type out of range");
860 cmd
->d
[0] |= 1 << type
;
862 cmd
->o
.opcode
= O_ICMPTYPE
;
863 cmd
->o
.len
|= F_INSN_SIZE(ipfw_insn_u32
);
867 print_icmptypes(ipfw_insn_u32
*cmd
)
872 printf(" icmptypes");
873 for (i
= 0; i
< 32; i
++) {
874 if ( (cmd
->d
[0] & (1 << (i
))) == 0)
876 printf("%c%d", sep
, i
);
882 * show_ipfw() prints the body of an ipfw rule.
883 * Because the standard rule has at least proto src_ip dst_ip, we use
884 * a helper function to produce these entries if not provided explicitly.
885 * The first argument is the list of fields we have, the second is
886 * the list of fields we want to be printed.
888 * Special cases if we have provided a MAC header:
889 * + if the rule does not contain IP addresses/ports, do not print them;
890 * + if the rule does not contain an IP proto, print "all" instead of "ip";
892 * Once we have 'have_options', IP header fields are printed as options.
894 #define HAVE_PROTO 0x0001
895 #define HAVE_SRCIP 0x0002
896 #define HAVE_DSTIP 0x0004
897 #define HAVE_MAC 0x0008
898 #define HAVE_MACTYPE 0x0010
899 #define HAVE_OPTIONS 0x8000
901 #define HAVE_IP (HAVE_PROTO | HAVE_SRCIP | HAVE_DSTIP)
903 show_prerequisites(int *flags
, int want
, int cmd
)
905 if ( (*flags
& HAVE_IP
) == HAVE_IP
)
906 *flags
|= HAVE_OPTIONS
;
908 if ( (*flags
& (HAVE_MAC
|HAVE_MACTYPE
|HAVE_OPTIONS
)) == HAVE_MAC
&&
911 * mac-type was optimized out by the compiler,
915 *flags
|= HAVE_MACTYPE
| HAVE_OPTIONS
;
918 if ( !(*flags
& HAVE_OPTIONS
)) {
919 if ( !(*flags
& HAVE_PROTO
) && (want
& HAVE_PROTO
))
921 if ( !(*flags
& HAVE_SRCIP
) && (want
& HAVE_SRCIP
))
923 if ( !(*flags
& HAVE_DSTIP
) && (want
& HAVE_DSTIP
))
930 show_ipfw(struct ip_fw
*rule
, int pcwidth
, int bcwidth
)
932 static int twidth
= 0;
935 char *comment
= NULL
; /* ptr to comment if we have one */
936 int proto
= 0; /* default */
937 int flags
= 0; /* prerequisites */
938 ipfw_insn_log
*logptr
= NULL
; /* set if we find an O_LOG */
939 int or_block
= 0; /* we are in an or block */
940 uint32_t set_disable
;
942 bcopy(&rule
->next_rule
, &set_disable
, sizeof(set_disable
));
944 if (set_disable
& (1 << rule
->set
)) { /* disabled */
948 printf("# DISABLED ");
950 printf("%05u ", rule
->rulenum
);
952 if (pcwidth
>0 || bcwidth
>0)
953 printf("%*llu %*llu ", pcwidth
, align_uint64(&rule
->pcnt
),
954 bcwidth
, align_uint64(&rule
->bcnt
));
957 printf("%10u ", rule
->timestamp
);
958 else if (do_time
== 1) {
960 time_t t
= (time_t)0;
963 strcpy(timestr
, ctime(&t
));
964 *strchr(timestr
, '\n') = '\0';
965 twidth
= strlen(timestr
);
967 if (rule
->timestamp
) {
968 #if _FreeBSD_version < 500000 /* XXX check */
969 #define _long_to_time(x) (time_t)(x)
971 t
= _long_to_time(rule
->timestamp
);
973 strcpy(timestr
, ctime(&t
));
974 *strchr(timestr
, '\n') = '\0';
975 printf("%s ", timestr
);
977 printf("%*s", twidth
, " ");
982 printf("set %d ", rule
->set
);
985 * print the optional "match probability"
987 if (rule
->cmd_len
> 0) {
989 if (cmd
->opcode
== O_PROB
) {
990 ipfw_insn_u32
*p
= (ipfw_insn_u32
*)cmd
;
991 double d
= 1.0 * p
->d
[0];
993 d
= (d
/ 0x7fffffff);
994 printf("prob %f ", d
);
999 * first print actions
1001 for (l
= rule
->cmd_len
- rule
->act_ofs
, cmd
= ACTION_PTR(rule
);
1002 l
> 0 ; l
-= F_LEN(cmd
), cmd
+= F_LEN(cmd
)) {
1003 switch(cmd
->opcode
) {
1005 printf("check-state");
1006 flags
= HAVE_IP
; /* avoid printing anything else */
1022 if (cmd
->arg1
== ICMP_REJECT_RST
)
1024 else if (cmd
->arg1
== ICMP_UNREACH_HOST
)
1027 print_reject_code(cmd
->arg1
);
1031 printf("skipto %u", cmd
->arg1
);
1035 printf("pipe %u", cmd
->arg1
);
1039 printf("queue %u", cmd
->arg1
);
1043 printf("divert %u", cmd
->arg1
);
1047 printf("tee %u", cmd
->arg1
);
1052 ipfw_insn_sa
*s
= (ipfw_insn_sa
*)cmd
;
1054 printf("fwd %s", inet_ntoa(s
->sa
.sin_addr
));
1056 printf(",%d", s
->sa
.sin_port
);
1060 case O_LOG
: /* O_LOG is printed last */
1061 logptr
= (ipfw_insn_log
*)cmd
;
1065 printf("** unrecognized action %d len %d",
1066 cmd
->opcode
, cmd
->len
);
1070 if (logptr
->max_log
> 0)
1071 printf(" log logamount %d", logptr
->max_log
);
1077 * then print the body.
1079 if (rule
->_pad
& 1) { /* empty rules before options */
1081 printf(" ip from any to any");
1082 flags
|= HAVE_IP
| HAVE_OPTIONS
;
1085 for (l
= rule
->act_ofs
, cmd
= rule
->cmd
;
1086 l
> 0 ; l
-= F_LEN(cmd
) , cmd
+= F_LEN(cmd
)) {
1088 ipfw_insn_u32
*cmd32
= (ipfw_insn_u32
*)cmd
;
1090 show_prerequisites(&flags
, 0, cmd
->opcode
);
1092 switch(cmd
->opcode
) {
1094 break; /* done already */
1097 break; /* no need to print anything here */
1100 ipfw_insn_mac
*m
= (ipfw_insn_mac
*)cmd
;
1102 if ((cmd
->len
& F_OR
) && !or_block
)
1104 if (cmd
->len
& F_NOT
)
1108 print_mac(m
->addr
, m
->mask
);
1109 print_mac(m
->addr
+ 6, m
->mask
+ 6);
1114 if ((cmd
->len
& F_OR
) && !or_block
)
1116 print_newports((ipfw_insn_u16
*)cmd
, IPPROTO_ETHERTYPE
,
1117 (flags
& HAVE_OPTIONS
) ? cmd
->opcode
: 0);
1118 flags
|= HAVE_MAC
| HAVE_MACTYPE
| HAVE_OPTIONS
;
1125 show_prerequisites(&flags
, HAVE_PROTO
, 0);
1126 if (!(flags
& HAVE_SRCIP
))
1128 if ((cmd
->len
& F_OR
) && !or_block
)
1130 print_ip((ipfw_insn_ip
*)cmd
,
1131 (flags
& HAVE_OPTIONS
) ? " src-ip" : "");
1132 flags
|= HAVE_SRCIP
;
1139 show_prerequisites(&flags
, HAVE_PROTO
|HAVE_SRCIP
, 0);
1140 if (!(flags
& HAVE_DSTIP
))
1142 if ((cmd
->len
& F_OR
) && !or_block
)
1144 print_ip((ipfw_insn_ip
*)cmd
,
1145 (flags
& HAVE_OPTIONS
) ? " dst-ip" : "");
1146 flags
|= HAVE_DSTIP
;
1150 show_prerequisites(&flags
, HAVE_IP
, 0);
1152 show_prerequisites(&flags
, HAVE_PROTO
|HAVE_SRCIP
, 0);
1153 if ((cmd
->len
& F_OR
) && !or_block
)
1155 print_newports((ipfw_insn_u16
*)cmd
, proto
,
1156 (flags
& HAVE_OPTIONS
) ? cmd
->opcode
: 0);
1160 struct protoent
*pe
;
1162 if ((cmd
->len
& F_OR
) && !or_block
)
1164 if (cmd
->len
& F_NOT
)
1167 pe
= getprotobynumber(cmd
->arg1
);
1168 if (flags
& HAVE_OPTIONS
)
1171 printf(" %s", pe
->p_name
);
1173 printf(" %u", cmd
->arg1
);
1175 flags
|= HAVE_PROTO
;
1178 default: /*options ... */
1179 show_prerequisites(&flags
, HAVE_IP
| HAVE_OPTIONS
, 0);
1180 if ((cmd
->len
& F_OR
) && !or_block
)
1182 if (cmd
->len
& F_NOT
&& cmd
->opcode
!= O_IN
)
1184 switch(cmd
->opcode
) {
1190 printf(cmd
->len
& F_NOT
? " out" : " in");
1200 ipfw_insn_if
*cmdif
= (ipfw_insn_if
*)cmd
;
1202 if (cmd
->opcode
== O_XMIT
)
1204 else if (cmd
->opcode
== O_RECV
)
1206 else /* if (cmd->opcode == O_VIA) */
1208 if (cmdif
->name
[0] == '\0')
1210 inet_ntoa(cmdif
->p
.ip
));
1211 else if (cmdif
->p
.unit
== -1)
1212 printf(" %s %s*", s
, cmdif
->name
);
1214 printf(" %s %s%d", s
, cmdif
->name
,
1220 if (F_LEN(cmd
) == 1)
1221 printf(" ipid %u", cmd
->arg1
);
1223 print_newports((ipfw_insn_u16
*)cmd
, 0,
1228 if (F_LEN(cmd
) == 1)
1229 printf(" ipttl %u", cmd
->arg1
);
1231 print_newports((ipfw_insn_u16
*)cmd
, 0,
1236 printf(" ipver %u", cmd
->arg1
);
1239 case O_IPPRECEDENCE
:
1240 printf(" ipprecedence %u", (cmd
->arg1
) >> 5 );
1244 if (F_LEN(cmd
) == 1)
1245 printf(" iplen %u", cmd
->arg1
);
1247 print_newports((ipfw_insn_u16
*)cmd
, 0,
1252 print_flags("ipoptions", cmd
, f_ipopts
);
1256 print_flags("iptos", cmd
, f_iptos
);
1260 print_icmptypes((ipfw_insn_u32
*)cmd
);
1264 printf(" established");
1268 print_flags("tcpflags", cmd
, f_tcpflags
);
1272 print_flags("tcpoptions", cmd
, f_tcpopts
);
1276 printf(" tcpwin %d", ntohs(cmd
->arg1
));
1280 printf(" tcpack %d", ntohl(cmd32
->d
[0]));
1284 printf(" tcpseq %d", ntohl(cmd32
->d
[0]));
1289 struct passwd
*pwd
= getpwuid(cmd32
->d
[0]);
1292 printf(" uid %s", pwd
->pw_name
);
1294 printf(" uid %u", cmd32
->d
[0]);
1300 struct group
*grp
= getgrgid(cmd32
->d
[0]);
1303 printf(" gid %s", grp
->gr_name
);
1305 printf(" gid %u", cmd32
->d
[0]);
1310 printf(" verrevpath");
1318 comment
= (char *)(cmd
+ 1);
1322 printf(" keep-state");
1327 struct _s_x
*p
= limit_masks
;
1328 ipfw_insn_limit
*c
= (ipfw_insn_limit
*)cmd
;
1329 uint8_t x
= c
->limit_mask
;
1330 char const *comma
= " ";
1333 for (; p
->x
!= 0 ; p
++)
1334 if ((x
& p
->x
) == p
->x
) {
1336 printf("%s%s", comma
, p
->s
);
1339 printf(" %d", c
->conn_limit
);
1344 printf(" [opcode %d len %d]",
1345 cmd
->opcode
, cmd
->len
);
1348 if (cmd
->len
& F_OR
) {
1351 } else if (or_block
) {
1356 show_prerequisites(&flags
, HAVE_IP
, 0);
1358 printf(" // %s", comment
);
1363 show_dyn_ipfw(ipfw_dyn_rule
*d
, int pcwidth
, int bcwidth
)
1365 struct protoent
*pe
;
1370 if (!d
->expire
&& !(d
->dyn_type
== O_LIMIT_PARENT
))
1373 bcopy(&d
->rule
, &rulenum
, sizeof(rulenum
));
1374 printf("%05d", rulenum
);
1375 if (pcwidth
>0 || bcwidth
>0)
1376 printf(" %*llu %*llu (%ds)", pcwidth
,
1377 align_uint64(&d
->pcnt
), bcwidth
,
1378 align_uint64(&d
->bcnt
), d
->expire
);
1379 switch (d
->dyn_type
) {
1380 case O_LIMIT_PARENT
:
1381 printf(" PARENT %d", d
->count
);
1386 case O_KEEP_STATE
: /* bidir, no mask */
1391 if ((pe
= getprotobynumber(d
->id
.proto
)) != NULL
)
1392 printf(" %s", pe
->p_name
);
1394 printf(" proto %u", d
->id
.proto
);
1396 a
.s_addr
= htonl(d
->id
.src_ip
);
1397 printf(" %s %d", inet_ntoa(a
), d
->id
.src_port
);
1399 a
.s_addr
= htonl(d
->id
.dst_ip
);
1400 printf(" <-> %s %d", inet_ntoa(a
), d
->id
.dst_port
);
1405 sort_q(const void *pa
, const void *pb
)
1407 int rev
= (do_sort
< 0);
1408 int field
= rev
? -do_sort
: do_sort
;
1410 const struct dn_flow_queue
*a
= pa
;
1411 const struct dn_flow_queue
*b
= pb
;
1415 res
= a
->len
- b
->len
;
1418 res
= a
->len_bytes
- b
->len_bytes
;
1421 case 3: /* tot pkts */
1422 res
= a
->tot_pkts
- b
->tot_pkts
;
1425 case 4: /* tot bytes */
1426 res
= a
->tot_bytes
- b
->tot_bytes
;
1433 return (int)(rev
? res
: -res
);
1437 list_queues(struct dn_flow_set
*fs
, struct dn_flow_queue
*q
)
1441 printf(" mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n",
1442 fs
->flow_mask
.proto
,
1443 fs
->flow_mask
.src_ip
, fs
->flow_mask
.src_port
,
1444 fs
->flow_mask
.dst_ip
, fs
->flow_mask
.dst_port
);
1445 if (fs
->rq_elements
== 0)
1448 printf("BKT Prot ___Source IP/port____ "
1449 "____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp\n");
1451 heapsort(q
, fs
->rq_elements
, sizeof *q
, sort_q
);
1452 for (l
= 0; l
< fs
->rq_elements
; l
++) {
1454 struct protoent
*pe
;
1456 ina
.s_addr
= htonl(q
[l
].id
.src_ip
);
1457 printf("%3d ", q
[l
].hash_slot
);
1458 pe
= getprotobynumber(q
[l
].id
.proto
);
1460 printf("%-4s ", pe
->p_name
);
1462 printf("%4u ", q
[l
].id
.proto
);
1463 printf("%15s/%-5d ",
1464 inet_ntoa(ina
), q
[l
].id
.src_port
);
1465 ina
.s_addr
= htonl(q
[l
].id
.dst_ip
);
1466 printf("%15s/%-5d ",
1467 inet_ntoa(ina
), q
[l
].id
.dst_port
);
1468 printf("%4qu %8qu %2u %4u %3u\n",
1469 q
[l
].tot_pkts
, q
[l
].tot_bytes
,
1470 q
[l
].len
, q
[l
].len_bytes
, q
[l
].drops
);
1472 printf(" S %20qd F %20qd\n",
1478 print_flowset_parms(struct dn_flow_set
*fs
, char *prefix
)
1483 char red
[90]; /* Display RED parameters */
1486 if (fs
->flags_fs
& DN_QSIZE_IS_BYTES
) {
1488 sprintf(qs
, "%d KB", l
/ 1024);
1490 sprintf(qs
, "%d B", l
);
1492 sprintf(qs
, "%3d sl.", l
);
1494 sprintf(plr
, "plr %f", 1.0 * fs
->plr
/ (double)(0x7fffffff));
1497 if (fs
->flags_fs
& DN_IS_RED
) /* RED parameters */
1499 "\n\t %cRED w_q %f min_th %d max_th %d max_p %f",
1500 (fs
->flags_fs
& DN_IS_GENTLE_RED
) ? 'G' : ' ',
1501 1.0 * fs
->w_q
/ (double)(1 << SCALE_RED
),
1502 SCALE_VAL(fs
->min_th
),
1503 SCALE_VAL(fs
->max_th
),
1504 1.0 * fs
->max_p
/ (double)(1 << SCALE_RED
));
1506 sprintf(red
, "droptail");
1508 printf("%s %s%s %d queues (%d buckets) %s\n",
1509 prefix
, qs
, plr
, fs
->rq_elements
, fs
->rq_size
, red
);
1513 list_pipes(void *data
, uint nbytes
, int ac
, char *av
[])
1517 struct dn_pipe
*p
= (struct dn_pipe
*) data
;
1518 struct dn_flow_set
*fs
;
1519 struct dn_flow_queue
*q
;
1523 rulenum
= strtoul(*av
++, NULL
, 10);
1526 for (; nbytes
>= sizeof *p
; p
= (struct dn_pipe
*)next
) {
1527 double b
= p
->bandwidth
;
1531 if (p
->next
.sle_next
!= (struct dn_pipe
*)DN_IS_PIPE
)
1532 break; /* done with pipes, now queues */
1535 * compute length, as pipe have variable size
1537 l
= sizeof(*p
) + p
->fs
.rq_elements
* sizeof(*q
);
1538 next
= (char *)p
+ l
;
1541 if (rulenum
!= 0 && rulenum
!= p
->pipe_nr
)
1545 * Print rate (or clocking interface)
1547 if (p
->if_name
[0] != '\0')
1548 sprintf(buf
, "%s", p
->if_name
);
1550 sprintf(buf
, "unlimited");
1551 else if (b
>= 1000000)
1552 sprintf(buf
, "%7.3f Mbit/s", b
/1000000);
1554 sprintf(buf
, "%7.3f Kbit/s", b
/1000);
1556 sprintf(buf
, "%7.3f bit/s ", b
);
1558 sprintf(prefix
, "%05d: %s %4d ms ",
1559 p
->pipe_nr
, buf
, p
->delay
);
1560 print_flowset_parms(&(p
->fs
), prefix
);
1562 printf(" V %20qd\n", p
->V
>> MY_M
);
1564 q
= (struct dn_flow_queue
*)(p
+1);
1565 list_queues(&(p
->fs
), q
);
1567 for (fs
= next
; nbytes
>= sizeof *fs
; fs
= next
) {
1570 if (fs
->next
.sle_next
!= (struct dn_flow_set
*)DN_IS_QUEUE
)
1572 l
= sizeof(*fs
) + fs
->rq_elements
* sizeof(*q
);
1573 next
= (char *)fs
+ l
;
1575 q
= (struct dn_flow_queue
*)(fs
+1);
1576 sprintf(prefix
, "q%05d: weight %d pipe %d ",
1577 fs
->fs_nr
, fs
->weight
, fs
->parent_nr
);
1578 print_flowset_parms(fs
, prefix
);
1584 * This one handles all set-related commands
1585 * ipfw set { show | enable | disable }
1587 * ipfw set move X to Y
1588 * ipfw set move rule X to Y
1591 sets_handler(int ac
, char *av
[])
1593 uint32_t set_disable
, masks
[2];
1596 uint8_t cmd
, new_set
;
1602 errx(EX_USAGE
, "set needs command");
1603 if (!strncmp(*av
, "show", strlen(*av
)) ) {
1607 nbytes
= sizeof(struct ip_fw
);
1608 if ((data
= calloc(1, nbytes
)) == NULL
)
1609 err(EX_OSERR
, "calloc");
1611 if (do_cmd(IP_FW_GET
, data
, (uintptr_t)&nbytes
) < 0)
1612 err(EX_OSERR
, "getsockopt(IP_FW_GET)");
1613 bcopy(&((struct ip_fw
*)data
)->next_rule
,
1614 &set_disable
, sizeof(set_disable
));
1616 for (i
= 0, msg
= "disable" ; i
< RESVD_SET
; i
++)
1617 if ((set_disable
& (1<<i
))) {
1618 printf("%s %d", msg
, i
);
1621 msg
= (set_disable
) ? " enable" : "enable";
1622 for (i
= 0; i
< RESVD_SET
; i
++)
1623 if (!(set_disable
& (1<<i
))) {
1624 printf("%s %d", msg
, i
);
1628 } else if (!strncmp(*av
, "swap", strlen(*av
))) {
1632 errx(EX_USAGE
, "set swap needs 2 set numbers\n");
1633 rulenum
= atoi(av
[0]);
1634 new_set
= atoi(av
[1]);
1635 if (!isdigit(*(av
[0])) || rulenum
> RESVD_SET
)
1636 errx(EX_DATAERR
, "invalid set number %s\n", av
[0]);
1637 if (!isdigit(*(av
[1])) || new_set
> RESVD_SET
)
1638 errx(EX_DATAERR
, "invalid set number %s\n", av
[1]);
1639 masks
[0] = (4 << 24) | (new_set
<< 16) | (rulenum
);
1641 bzero(&rule
, sizeof(rule
));
1642 rule
.set_masks
[0] = masks
[0];
1644 i
= do_cmd(IP_FW_DEL
, &rule
, sizeof(rule
));
1645 } else if (!strncmp(*av
, "move", strlen(*av
))) {
1648 if (ac
&& !strncmp(*av
, "rule", strlen(*av
))) {
1653 if (ac
!= 3 || strncmp(av
[1], "to", strlen(*av
)))
1654 errx(EX_USAGE
, "syntax: set move [rule] X to Y\n");
1655 rulenum
= atoi(av
[0]);
1656 new_set
= atoi(av
[2]);
1657 if (!isdigit(*(av
[0])) || (cmd
== 3 && rulenum
> RESVD_SET
) ||
1658 (cmd
== 2 && rulenum
== 65535) )
1659 errx(EX_DATAERR
, "invalid source number %s\n", av
[0]);
1660 if (!isdigit(*(av
[2])) || new_set
> RESVD_SET
)
1661 errx(EX_DATAERR
, "invalid dest. set %s\n", av
[1]);
1662 masks
[0] = (cmd
<< 24) | (new_set
<< 16) | (rulenum
);
1664 bzero(&rule
, sizeof(rule
));
1665 rule
.set_masks
[0] = masks
[0];
1667 i
= do_cmd(IP_FW_DEL
, &rule
, sizeof(rule
));
1668 } else if (!strncmp(*av
, "disable", strlen(*av
)) ||
1669 !strncmp(*av
, "enable", strlen(*av
)) ) {
1670 int which
= !strncmp(*av
, "enable", strlen(*av
)) ? 1 : 0;
1674 masks
[0] = masks
[1] = 0;
1677 if (isdigit(**av
)) {
1679 if (i
< 0 || i
> RESVD_SET
)
1681 "invalid set number %d\n", i
);
1682 masks
[which
] |= (1<<i
);
1683 } else if (!strncmp(*av
, "disable", strlen(*av
)))
1685 else if (!strncmp(*av
, "enable", strlen(*av
)))
1689 "invalid set command %s\n", *av
);
1692 if ( (masks
[0] & masks
[1]) != 0 )
1694 "cannot enable and disable the same set\n");
1696 bzero(&rule
, sizeof(rule
));
1697 rule
.set_masks
[0] = masks
[0];
1698 rule
.set_masks
[1] = masks
[1];
1700 i
= do_cmd(IP_FW_DEL
, &rule
, sizeof(rule
));
1702 warn("set enable/disable: setsockopt(IP_FW_DEL)");
1704 errx(EX_USAGE
, "invalid set command %s\n", *av
);
1708 sysctl_handler(int ac
, char *av
[], int which
)
1714 warnx("missing keyword to enable/disable\n");
1715 } else if (strncmp(*av
, "firewall", strlen(*av
)) == 0) {
1716 sysctlbyname("net.inet.ip.fw.enable", NULL
, 0,
1717 &which
, sizeof(which
));
1718 } else if (strncmp(*av
, "one_pass", strlen(*av
)) == 0) {
1719 sysctlbyname("net.inet.ip.fw.one_pass", NULL
, 0,
1720 &which
, sizeof(which
));
1721 } else if (strncmp(*av
, "debug", strlen(*av
)) == 0) {
1722 sysctlbyname("net.inet.ip.fw.debug", NULL
, 0,
1723 &which
, sizeof(which
));
1724 } else if (strncmp(*av
, "verbose", strlen(*av
)) == 0) {
1725 sysctlbyname("net.inet.ip.fw.verbose", NULL
, 0,
1726 &which
, sizeof(which
));
1727 } else if (strncmp(*av
, "dyn_keepalive", strlen(*av
)) == 0) {
1728 sysctlbyname("net.inet.ip.fw.dyn_keepalive", NULL
, 0,
1729 &which
, sizeof(which
));
1731 warnx("unrecognize enable/disable keyword: %s\n", *av
);
1736 list(int ac
, char *av
[], int show_counters
)
1739 ipfw_dyn_rule
*dynrules
, *d
;
1741 #define NEXT(r) ((struct ip_fw *)((char *)r + RULESIZE(r)))
1744 int bcwidth
, n
, nbytes
, nstat
, ndyn
, pcwidth
, width
;
1745 int exitval
= EX_OK
;
1752 const int ocmd
= do_pipe
? IP_DUMMYNET_GET
: IP_FW_GET
;
1753 int nalloc
= 1024; /* start somewhere... */
1756 fprintf(stderr
, "Testing only, list disabled\n");
1763 /* get rules or pipes from kernel, resizing array as necessary */
1766 while (nbytes
>= nalloc
) {
1767 nalloc
= nalloc
* 2 + 200;
1769 if ((data
= realloc(data
, nbytes
)) == NULL
)
1770 err(EX_OSERR
, "realloc");
1772 if (do_cmd(ocmd
, data
, (uintptr_t)&nbytes
) < 0)
1773 err(EX_OSERR
, "getsockopt(IP_%s_GET)",
1774 do_pipe
? "DUMMYNET" : "FW");
1778 list_pipes(data
, nbytes
, ac
, av
);
1783 * Count static rules. They have variable size so we
1784 * need to scan the list to count them.
1786 for (nstat
= 1, r
= data
, lim
= (char *)data
+ nbytes
;
1787 r
->rulenum
< 65535 && (char *)r
< lim
;
1788 ++nstat
, r
= NEXT(r
) )
1792 * Count dynamic rules. This is easier as they have
1796 dynrules
= (ipfw_dyn_rule
*)r
;
1797 n
= (char *)r
- (char *)data
;
1798 ndyn
= (nbytes
- n
) / sizeof *dynrules
;
1800 /* if showing stats, figure out column widths ahead of time */
1801 bcwidth
= pcwidth
= 0;
1802 if (show_counters
) {
1803 for (n
= 0, r
= data
; n
< nstat
; n
++, r
= NEXT(r
)) {
1804 /* packet counter */
1805 width
= snprintf(NULL
, 0, "%llu",
1806 align_uint64(&r
->pcnt
));
1807 if (width
> pcwidth
)
1811 width
= snprintf(NULL
, 0, "%llu",
1812 align_uint64(&r
->bcnt
));
1813 if (width
> bcwidth
)
1817 if (do_dynamic
&& ndyn
) {
1818 for (n
= 0, d
= dynrules
; n
< ndyn
; n
++, d
++) {
1819 width
= snprintf(NULL
, 0, "%llu",
1820 align_uint64(&d
->pcnt
));
1821 if (width
> pcwidth
)
1824 width
= snprintf(NULL
, 0, "%llu",
1825 align_uint64(&d
->bcnt
));
1826 if (width
> bcwidth
)
1830 /* if no rule numbers were specified, list all rules */
1832 for (n
= 0, r
= data
; n
< nstat
; n
++, r
= NEXT(r
) )
1833 show_ipfw(r
, pcwidth
, bcwidth
);
1835 if (do_dynamic
&& ndyn
) {
1836 printf("## Dynamic rules (%d):\n", ndyn
);
1837 for (n
= 0, d
= dynrules
; n
< ndyn
; n
++, d
++)
1838 show_dyn_ipfw(d
, pcwidth
, bcwidth
);
1843 /* display specific rules requested on command line */
1845 for (lac
= ac
, lav
= av
; lac
!= 0; lac
--) {
1846 /* convert command line rule # */
1847 last
= rnum
= strtoul(*lav
++, &endptr
, 10);
1849 last
= strtoul(endptr
+1, &endptr
, 10);
1852 warnx("invalid rule number: %s", *(lav
- 1));
1855 for (n
= seen
= 0, r
= data
; n
< nstat
; n
++, r
= NEXT(r
) ) {
1856 if (r
->rulenum
> last
)
1858 if (r
->rulenum
>= rnum
&& r
->rulenum
<= last
) {
1859 show_ipfw(r
, pcwidth
, bcwidth
);
1864 /* give precedence to other error(s) */
1865 if (exitval
== EX_OK
)
1866 exitval
= EX_UNAVAILABLE
;
1867 warnx("rule %lu does not exist", rnum
);
1871 if (do_dynamic
&& ndyn
) {
1872 printf("## Dynamic rules:\n");
1873 for (lac
= ac
, lav
= av
; lac
!= 0; lac
--) {
1874 rnum
= strtoul(*lav
++, &endptr
, 10);
1876 last
= strtoul(endptr
+1, &endptr
, 10);
1878 /* already warned */
1880 for (n
= 0, d
= dynrules
; n
< ndyn
; n
++, d
++) {
1883 bcopy(&d
->rule
, &rulenum
, sizeof(rulenum
));
1886 if (r
->rulenum
>= rnum
&& r
->rulenum
<= last
)
1887 show_dyn_ipfw(d
, pcwidth
, bcwidth
);
1897 if (exitval
!= EX_OK
)
1905 fprintf(stderr
, "usage: ipfw [options]\n"
1906 "do \"ipfw -h\" or see ipfw manpage for details\n"
1915 "ipfw syntax summary (but please do read the ipfw(8) manpage):\n"
1916 "ipfw [-acdeftTnNpqS] <command> where <command> is one of:\n"
1917 "add [num] [set N] [prob x] RULE-BODY\n"
1918 "{pipe|queue} N config PIPE-BODY\n"
1919 "[pipe|queue] {zero|delete|show} [N{,N}]\n"
1920 "set [disable N... enable N...] | move [rule] X to Y | swap X Y | show\n"
1922 "RULE-BODY: check-state [LOG] | ACTION [LOG] ADDR [OPTION_LIST]\n"
1923 "ACTION: check-state | allow | count | deny | reject | skipto N |\n"
1924 " {divert|tee} PORT | forward ADDR | pipe N | queue N\n"
1925 "ADDR: [ MAC dst src ether_type ] \n"
1926 " [ from IPADDR [ PORT ] to IPADDR [ PORTLIST ] ]\n"
1927 "IPADDR: [not] { any | me | ip/bits{x,y,z} | IPLIST }\n"
1928 "IPLIST: { ip | ip/bits | ip:mask }[,IPLIST]\n"
1929 "OPTION_LIST: OPTION [OPTION_LIST]\n"
1930 "OPTION: bridged | {dst-ip|src-ip} ADDR | {dst-port|src-port} LIST |\n"
1931 " estab | frag | {gid|uid} N | icmptypes LIST | in | out | ipid LIST |\n"
1932 " iplen LIST | ipoptions SPEC | ipprecedence | ipsec | iptos SPEC |\n"
1933 " ipttl LIST | ipversion VER | keep-state | layer2 | limit ... |\n"
1934 " mac ... | mac-type LIST | proto LIST | {recv|xmit|via} {IF|IPADDR} |\n"
1935 " setup | {tcpack|tcpseq|tcpwin} NN | tcpflags SPEC | tcpoptions SPEC |\n"
1943 lookup_host (char *host
, struct in_addr
*ipaddr
)
1947 if (!inet_aton(host
, ipaddr
)) {
1948 if ((he
= gethostbyname(host
)) == NULL
)
1950 *ipaddr
= *(struct in_addr
*)he
->h_addr_list
[0];
1956 * fills the addr and mask fields in the instruction as appropriate from av.
1957 * Update length as appropriate.
1958 * The following formats are allowed:
1959 * any matches any IP. Actually returns an empty instruction.
1960 * me returns O_IP_*_ME
1961 * 1.2.3.4 single IP address
1962 * 1.2.3.4:5.6.7.8 address:mask
1963 * 1.2.3.4/24 address/mask
1964 * 1.2.3.4/26{1,6,5,4,23} set of addresses in a subnet
1965 * We can have multiple comma-separated address/mask entries.
1968 fill_ip(ipfw_insn_ip
*cmd
, char *av
)
1971 uint32_t *d
= ((ipfw_insn_u32
*)cmd
)->d
;
1973 cmd
->o
.len
&= ~F_LEN_MASK
; /* zero len */
1975 if (!strncmp(av
, "any", strlen(av
)))
1978 if (!strncmp(av
, "me", strlen(av
))) {
1979 cmd
->o
.len
|= F_INSN_SIZE(ipfw_insn
);
1985 * After the address we can have '/' or ':' indicating a mask,
1986 * ',' indicating another address follows, '{' indicating a
1987 * set of addresses of unspecified size.
1989 char *p
= strpbrk(av
, "/:,{");
1999 if (lookup_host(av
, (struct in_addr
*)&d
[0]) != 0)
2000 errx(EX_NOHOST
, "hostname ``%s'' unknown", av
);
2003 if (!inet_aton(p
, (struct in_addr
*)&d
[1]))
2004 errx(EX_DATAERR
, "bad netmask ``%s''", p
);
2009 d
[1] = htonl(0); /* mask */
2010 else if (masklen
> 32)
2011 errx(EX_DATAERR
, "bad width ``%s''", p
);
2013 d
[1] = htonl(~0 << (32 - masklen
));
2015 case '{': /* no mask, assume /24 and put back the '{' */
2016 d
[1] = htonl(~0 << (32 - 24));
2020 case ',': /* single address plus continuation */
2023 case 0: /* initialization value */
2025 d
[1] = htonl(~0); /* force /32 */
2028 d
[0] &= d
[1]; /* mask base address with mask */
2029 /* find next separator */
2031 p
= strpbrk(p
, ",{");
2032 if (p
&& *p
== '{') {
2034 * We have a set of addresses. They are stored as follows:
2035 * arg1 is the set size (powers of 2, 2..256)
2036 * addr is the base address IN HOST FORMAT
2037 * mask.. is an array of arg1 bits (rounded up to
2038 * the next multiple of 32) with bits set
2039 * for each host in the map.
2041 uint32_t *map
= (uint32_t *)&cmd
->mask
;
2043 int i
= contigmask((uint8_t *)&(d
[1]), 32);
2046 errx(EX_DATAERR
, "address set cannot be in a list");
2047 if (i
< 24 || i
> 31)
2048 errx(EX_DATAERR
, "invalid set with mask %d\n", i
);
2049 cmd
->o
.arg1
= 1<<(32-i
); /* map length */
2050 d
[0] = ntohl(d
[0]); /* base addr in host format */
2051 cmd
->o
.opcode
= O_IP_DST_SET
; /* default */
2052 cmd
->o
.len
|= F_INSN_SIZE(ipfw_insn_u32
) + (cmd
->o
.arg1
+31)/32;
2053 for (i
= 0; i
< (cmd
->o
.arg1
+31)/32 ; i
++)
2054 map
[i
] = 0; /* clear map */
2058 high
= low
+ cmd
->o
.arg1
- 1;
2060 * Here, i stores the previous value when we specify a range
2061 * of addresses within a mask, e.g. 45-63. i = -1 means we
2062 * have no previous value.
2064 i
= -1; /* previous value in a range */
2065 while (isdigit(*av
)) {
2067 int a
= strtol(av
, &s
, 0);
2069 if (s
== av
) { /* no parameter */
2071 errx(EX_DATAERR
, "set not closed\n");
2073 errx(EX_DATAERR
, "incomplete range %d-", i
);
2076 if (a
< low
|| a
> high
)
2077 errx(EX_DATAERR
, "addr %d out of range [%d-%d]\n",
2080 if (i
== -1) /* no previous in range */
2082 else { /* check that range is valid */
2084 errx(EX_DATAERR
, "invalid range %d-%d",
2087 errx(EX_DATAERR
, "double '-' in range");
2090 map
[i
/32] |= 1<<(i
& 31);
2101 if (av
) /* then *av must be a ',' */
2104 /* Check this entry */
2105 if (d
[1] == 0) { /* "any", specified as x.x.x.x/0 */
2107 * 'any' turns the entire list into a NOP.
2108 * 'not any' never matches, so it is removed from the
2109 * list unless it is the only item, in which case we
2112 if (cmd
->o
.len
& F_NOT
) { /* "not any" never matches */
2113 if (av
== NULL
&& len
== 0) /* only this entry */
2114 errx(EX_DATAERR
, "not any never matches");
2116 /* else do nothing and return */
2119 /* A single IP can be stored in an optimized format */
2120 if (d
[1] == IP_MASK_ALL
&& av
== NULL
&& len
== 0) {
2121 cmd
->o
.len
|= F_INSN_SIZE(ipfw_insn_u32
);
2124 len
+= 2; /* two words... */
2127 cmd
->o
.len
|= len
+1;
2132 * helper function to process a set of flags and set bits in the
2133 * appropriate masks.
2136 fill_flags(ipfw_insn
*cmd
, enum ipfw_opcodes opcode
,
2137 struct _s_x
*flags
, char *p
)
2139 uint8_t set
=0, clear
=0;
2142 char *q
; /* points to the separator */
2144 uint8_t *which
; /* mask we are working on */
2154 val
= match_token(flags
, p
);
2156 errx(EX_DATAERR
, "invalid flag %s", p
);
2157 *which
|= (uint8_t)val
;
2160 cmd
->opcode
= opcode
;
2161 cmd
->len
= (cmd
->len
& (F_NOT
| F_OR
)) | 1;
2162 cmd
->arg1
= (set
& 0xff) | ( (clear
& 0xff) << 8);
2167 delete(int ac
, char *av
[])
2172 int exitval
= EX_OK
;
2175 memset(&p
, 0, sizeof p
);
2178 if (ac
> 0 && !strncmp(*av
, "set", strlen(*av
))) {
2179 do_set
= 1; /* delete set */
2184 while (ac
&& isdigit(**av
)) {
2185 i
= atoi(*av
); av
++; ac
--;
2191 i
= do_cmd(IP_DUMMYNET_DEL
, &p
, sizeof p
);
2194 warn("rule %u: setsockopt(IP_DUMMYNET_DEL)",
2195 do_pipe
== 1 ? p
.pipe_nr
: p
.fs
.fs_nr
);
2198 bzero(&rule
, sizeof(rule
));
2200 rule
.set_masks
[0] = (i
& 0xffff) | (do_set
<< 24);
2205 i
= do_cmd(IP_FW_DEL
, &rule
, sizeof(rule
));
2207 exitval
= EX_UNAVAILABLE
;
2208 warn("rule %u: setsockopt(IP_FW_DEL)",
2213 if (exitval
!= EX_OK
)
2219 * fill the interface structure. We do not check the name as we can
2220 * create interfaces dynamically, so checking them at insert time
2221 * makes relatively little sense.
2222 * A '*' following the name means any unit.
2225 fill_iface(ipfw_insn_if
*cmd
, char *arg
)
2227 cmd
->name
[0] = '\0';
2228 cmd
->o
.len
|= F_INSN_SIZE(ipfw_insn_if
);
2230 /* Parse the interface or address */
2231 if (!strcmp(arg
, "any"))
2232 cmd
->o
.len
= 0; /* effectively ignore this command */
2233 else if (!isdigit(*arg
)) {
2236 strncpy(cmd
->name
, arg
, sizeof(cmd
->name
));
2237 cmd
->name
[sizeof(cmd
->name
) - 1] = '\0';
2238 /* find first digit or wildcard */
2239 for (q
= cmd
->name
; *q
&& !isdigit(*q
) && *q
!= '*'; q
++)
2241 cmd
->p
.unit
= (*q
== '*') ? -1 : atoi(q
);
2243 } else if (!inet_aton(arg
, &cmd
->p
.ip
))
2244 errx(EX_DATAERR
, "bad ip address ``%s''", arg
);
2248 * the following macro returns an error message if we run out of
2251 #define NEED1(msg) {if (!ac) errx(EX_USAGE, msg);}
2254 config_pipe(int ac
, char **av
)
2262 memset(&p
, 0, sizeof p
);
2266 if (ac
&& isdigit(**av
)) {
2267 i
= atoi(*av
); av
++; ac
--;
2275 int tok
= match_token(dummynet_params
, *av
);
2280 p
.fs
.flags_fs
|= DN_NOERROR
;
2284 NEED1("plr needs argument 0..1\n");
2285 d
= strtod(av
[0], NULL
);
2290 p
.fs
.plr
= (int)(d
*0x7fffffff);
2295 NEED1("queue needs queue size\n");
2297 p
.fs
.qsize
= strtoul(av
[0], &end
, 0);
2298 if (*end
== 'K' || *end
== 'k') {
2299 p
.fs
.flags_fs
|= DN_QSIZE_IS_BYTES
;
2301 } else if (*end
== 'B' || !strncmp(end
, "by", 2)) {
2302 p
.fs
.flags_fs
|= DN_QSIZE_IS_BYTES
;
2308 NEED1("buckets needs argument\n");
2309 p
.fs
.rq_size
= strtoul(av
[0], NULL
, 0);
2314 NEED1("mask needs mask specifier\n");
2316 * per-flow queue, mask is dst_ip, dst_port,
2317 * src_ip, src_port, proto measured in bits
2321 p
.fs
.flow_mask
.dst_ip
= 0;
2322 p
.fs
.flow_mask
.src_ip
= 0;
2323 p
.fs
.flow_mask
.dst_port
= 0;
2324 p
.fs
.flow_mask
.src_port
= 0;
2325 p
.fs
.flow_mask
.proto
= 0;
2329 uint32_t *p32
= NULL
;
2330 uint16_t *p16
= NULL
;
2332 tok
= match_token(dummynet_params
, *av
);
2337 * special case, all bits significant
2339 p
.fs
.flow_mask
.dst_ip
= ~0;
2340 p
.fs
.flow_mask
.src_ip
= ~0;
2341 p
.fs
.flow_mask
.dst_port
= ~0;
2342 p
.fs
.flow_mask
.src_port
= ~0;
2343 p
.fs
.flow_mask
.proto
= ~0;
2344 p
.fs
.flags_fs
|= DN_HAVE_FLOW_MASK
;
2348 p32
= &p
.fs
.flow_mask
.dst_ip
;
2352 p32
= &p
.fs
.flow_mask
.src_ip
;
2356 p16
= &p
.fs
.flow_mask
.dst_port
;
2360 p16
= &p
.fs
.flow_mask
.src_port
;
2367 ac
++; av
--; /* backtrack */
2371 errx(EX_USAGE
, "mask: value missing");
2372 if (*av
[0] == '/') {
2373 a
= strtoul(av
[0]+1, &end
, 0);
2374 a
= (a
== 32) ? ~0 : (1 << a
) - 1;
2376 a
= strtoul(av
[0], &end
, 0);
2379 else if (p16
!= NULL
) {
2382 "mask: must be 16 bit");
2387 "mask: must be 8 bit");
2388 p
.fs
.flow_mask
.proto
= (uint8_t)a
;
2391 p
.fs
.flags_fs
|= DN_HAVE_FLOW_MASK
;
2393 } /* end while, config masks */
2399 NEED1("red/gred needs w_q/min_th/max_th/max_p\n");
2400 p
.fs
.flags_fs
|= DN_IS_RED
;
2401 if (tok
== TOK_GRED
)
2402 p
.fs
.flags_fs
|= DN_IS_GENTLE_RED
;
2404 * the format for parameters is w_q/min_th/max_th/max_p
2406 if ((end
= strsep(&av
[0], "/"))) {
2407 double w_q
= strtod(end
, NULL
);
2408 if (w_q
> 1 || w_q
<= 0)
2409 errx(EX_DATAERR
, "0 < w_q <= 1");
2410 p
.fs
.w_q
= (int) (w_q
* (1 << SCALE_RED
));
2412 if ((end
= strsep(&av
[0], "/"))) {
2413 p
.fs
.min_th
= strtoul(end
, &end
, 0);
2414 if (*end
== 'K' || *end
== 'k')
2415 p
.fs
.min_th
*= 1024;
2417 if ((end
= strsep(&av
[0], "/"))) {
2418 p
.fs
.max_th
= strtoul(end
, &end
, 0);
2419 if (*end
== 'K' || *end
== 'k')
2420 p
.fs
.max_th
*= 1024;
2422 if ((end
= strsep(&av
[0], "/"))) {
2423 double max_p
= strtod(end
, NULL
);
2424 if (max_p
> 1 || max_p
<= 0)
2425 errx(EX_DATAERR
, "0 < max_p <= 1");
2426 p
.fs
.max_p
= (int)(max_p
* (1 << SCALE_RED
));
2432 p
.fs
.flags_fs
&= ~(DN_IS_RED
|DN_IS_GENTLE_RED
);
2436 NEED1("bw needs bandwidth or interface\n");
2438 errx(EX_DATAERR
, "bandwidth only valid for pipes");
2440 * set clocking interface or bandwidth value
2442 if (av
[0][0] >= 'a' && av
[0][0] <= 'z') {
2443 int l
= sizeof(p
.if_name
)-1;
2444 /* interface name */
2445 strncpy(p
.if_name
, av
[0], l
);
2446 p
.if_name
[l
] = '\0';
2449 p
.if_name
[0] = '\0';
2450 p
.bandwidth
= strtoul(av
[0], &end
, 0);
2451 if (*end
== 'K' || *end
== 'k') {
2453 p
.bandwidth
*= 1000;
2454 } else if (*end
== 'M') {
2456 p
.bandwidth
*= 1000000;
2458 if (*end
== 'B' || !strncmp(end
, "by", 2))
2460 if (p
.bandwidth
< 0)
2461 errx(EX_DATAERR
, "bandwidth too large");
2468 errx(EX_DATAERR
, "delay only valid for pipes");
2469 NEED1("delay needs argument 0..10000ms\n");
2470 p
.delay
= strtoul(av
[0], NULL
, 0);
2476 errx(EX_DATAERR
,"weight only valid for queues");
2477 NEED1("weight needs argument 0..100\n");
2478 p
.fs
.weight
= strtoul(av
[0], &end
, 0);
2484 errx(EX_DATAERR
,"pipe only valid for queues");
2485 NEED1("pipe needs pipe_number\n");
2486 p
.fs
.parent_nr
= strtoul(av
[0], &end
, 0);
2491 errx(EX_DATAERR
, "unrecognised option ``%s''", *(--av
));
2496 errx(EX_DATAERR
, "pipe_nr must be > 0");
2497 if (p
.delay
> 10000)
2498 errx(EX_DATAERR
, "delay must be < 10000");
2499 } else { /* do_pipe == 2, queue */
2500 if (p
.fs
.parent_nr
== 0)
2501 errx(EX_DATAERR
, "pipe must be > 0");
2502 if (p
.fs
.weight
>100)
2503 errx(EX_DATAERR
, "weight must be <= 100");
2505 if (p
.fs
.flags_fs
& DN_QSIZE_IS_BYTES
) {
2506 if (p
.fs
.qsize
> 1024*1024)
2507 errx(EX_DATAERR
, "queue size must be < 1MB");
2509 if (p
.fs
.qsize
> 100)
2510 errx(EX_DATAERR
, "2 <= queue size <= 100");
2512 if (p
.fs
.flags_fs
& DN_IS_RED
) {
2514 int lookup_depth
, avg_pkt_size
;
2515 double s
, idle
, weight
, w_q
;
2516 struct clockinfo ck
;
2519 if (p
.fs
.min_th
>= p
.fs
.max_th
)
2520 errx(EX_DATAERR
, "min_th %d must be < than max_th %d",
2521 p
.fs
.min_th
, p
.fs
.max_th
);
2522 if (p
.fs
.max_th
== 0)
2523 errx(EX_DATAERR
, "max_th must be > 0");
2526 if (sysctlbyname("net.inet.ip.dummynet.red_lookup_depth",
2527 &lookup_depth
, &len
, NULL
, 0) == -1)
2529 errx(1, "sysctlbyname(\"%s\")",
2530 "net.inet.ip.dummynet.red_lookup_depth");
2531 if (lookup_depth
== 0)
2532 errx(EX_DATAERR
, "net.inet.ip.dummynet.red_lookup_depth"
2533 " must be greater than zero");
2536 if (sysctlbyname("net.inet.ip.dummynet.red_avg_pkt_size",
2537 &avg_pkt_size
, &len
, NULL
, 0) == -1)
2539 errx(1, "sysctlbyname(\"%s\")",
2540 "net.inet.ip.dummynet.red_avg_pkt_size");
2541 if (avg_pkt_size
== 0)
2543 "net.inet.ip.dummynet.red_avg_pkt_size must"
2544 " be greater than zero");
2546 len
= sizeof(struct clockinfo
);
2547 if (sysctlbyname("kern.clockrate", &ck
, &len
, NULL
, 0) == -1)
2548 errx(1, "sysctlbyname(\"%s\")", "kern.clockrate");
2551 * Ticks needed for sending a medium-sized packet.
2552 * Unfortunately, when we are configuring a WF2Q+ queue, we
2553 * do not have bandwidth information, because that is stored
2554 * in the parent pipe, and also we have multiple queues
2555 * competing for it. So we set s=0, which is not very
2556 * correct. But on the other hand, why do we want RED with
2559 if (p
.bandwidth
==0) /* this is a WF2Q+ queue */
2562 s
= ck
.hz
* avg_pkt_size
* 8 / p
.bandwidth
;
2565 * max idle time (in ticks) before avg queue size becomes 0.
2566 * NOTA: (3/w_q) is approx the value x so that
2567 * (1-w_q)^x < 10^-3.
2569 w_q
= ((double)p
.fs
.w_q
) / (1 << SCALE_RED
);
2570 idle
= s
* 3. / w_q
;
2571 p
.fs
.lookup_step
= (int)idle
/ lookup_depth
;
2572 if (!p
.fs
.lookup_step
)
2573 p
.fs
.lookup_step
= 1;
2575 for (t
= p
.fs
.lookup_step
; t
> 0; --t
)
2577 p
.fs
.lookup_weight
= (int)(weight
* (1 << SCALE_RED
));
2579 i
= do_cmd(IP_DUMMYNET_CONFIGURE
, &p
, sizeof p
);
2581 err(1, "setsockopt(%s)", "IP_DUMMYNET_CONFIGURE");
2585 get_mac_addr_mask(char *p
, uint8_t *addr
, uint8_t *mask
)
2590 addr
[i
] = mask
[i
] = 0;
2591 if (!strcmp(p
, "any"))
2594 for (i
=0; *p
&& i
<6;i
++, p
++) {
2595 addr
[i
] = strtol(p
, &p
, 16);
2596 if (*p
!= ':') /* we start with the mask */
2599 if (*p
== '/') { /* mask len */
2600 l
= strtol(p
+1, &p
, 0);
2601 for (i
=0; l
>0; l
-=8, i
++)
2602 mask
[i
] = (l
>=8) ? 0xff : (~0) << (8-l
);
2603 } else if (*p
== '&') { /* mask */
2604 for (i
=0, p
++; *p
&& i
<6;i
++, p
++) {
2605 mask
[i
] = strtol(p
, &p
, 16);
2609 } else if (*p
== '\0') {
2618 * helper function, updates the pointer to cmd with the length
2619 * of the current command, and also cleans up the first word of
2620 * the new command in case it has been clobbered before.
2623 next_cmd(ipfw_insn
*cmd
)
2626 bzero(cmd
, sizeof(*cmd
));
2631 * Takes arguments and copies them into a comment
2634 fill_comment(ipfw_insn
*cmd
, int ac
, char **av
)
2637 char *p
= (char *)(cmd
+ 1);
2639 cmd
->opcode
= O_NOP
;
2640 cmd
->len
= (cmd
->len
& (F_NOT
| F_OR
));
2642 /* Compute length of comment string. */
2643 for (i
= 0, l
= 0; i
< ac
; i
++)
2644 l
+= strlen(av
[i
]) + 1;
2649 "comment too long (max 80 chars)");
2651 cmd
->len
= (cmd
->len
& (F_NOT
| F_OR
)) | l
;
2652 for (i
= 0; i
< ac
; i
++) {
2661 * A function to fill simple commands of size 1.
2662 * Existing flags are preserved.
2665 fill_cmd(ipfw_insn
*cmd
, enum ipfw_opcodes opcode
, int flags
, uint16_t arg
)
2667 cmd
->opcode
= opcode
;
2668 cmd
->len
= ((cmd
->len
| flags
) & (F_NOT
| F_OR
)) | 1;
2673 * Fetch and add the MAC address and type, with masks. This generates one or
2674 * two microinstructions, and returns the pointer to the last one.
2677 add_mac(ipfw_insn
*cmd
, int ac
, char *av
[])
2682 errx(EX_DATAERR
, "MAC dst src");
2684 cmd
->opcode
= O_MACADDR2
;
2685 cmd
->len
= (cmd
->len
& (F_NOT
| F_OR
)) | F_INSN_SIZE(ipfw_insn_mac
);
2687 mac
= (ipfw_insn_mac
*)cmd
;
2688 get_mac_addr_mask(av
[0], mac
->addr
, mac
->mask
); /* dst */
2689 get_mac_addr_mask(av
[1], &(mac
->addr
[6]), &(mac
->mask
[6])); /* src */
2694 add_mactype(ipfw_insn
*cmd
, int ac
, char *av
)
2697 errx(EX_DATAERR
, "missing MAC type");
2698 if (strcmp(av
, "any") != 0) { /* we have a non-null type */
2699 fill_newports((ipfw_insn_u16
*)cmd
, av
, IPPROTO_ETHERTYPE
);
2700 cmd
->opcode
= O_MAC_TYPE
;
2707 add_proto(ipfw_insn
*cmd
, char *av
)
2709 struct protoent
*pe
;
2712 if (!strncmp(av
, "all", strlen(av
)))
2713 ; /* same as "ip" */
2714 else if ((proto
= atoi(av
)) > 0)
2716 else if ((pe
= getprotobyname(av
)) != NULL
)
2717 proto
= pe
->p_proto
;
2720 if (proto
!= IPPROTO_IP
)
2721 fill_cmd(cmd
, O_PROTO
, 0, proto
);
2726 add_srcip(ipfw_insn
*cmd
, char *av
)
2728 fill_ip((ipfw_insn_ip
*)cmd
, av
);
2729 if (cmd
->opcode
== O_IP_DST_SET
) /* set */
2730 cmd
->opcode
= O_IP_SRC_SET
;
2731 else if (F_LEN(cmd
) == F_INSN_SIZE(ipfw_insn
)) /* me */
2732 cmd
->opcode
= O_IP_SRC_ME
;
2733 else if (F_LEN(cmd
) == F_INSN_SIZE(ipfw_insn_u32
)) /* one IP */
2734 cmd
->opcode
= O_IP_SRC
;
2735 else /* addr/mask */
2736 cmd
->opcode
= O_IP_SRC_MASK
;
2741 add_dstip(ipfw_insn
*cmd
, char *av
)
2743 fill_ip((ipfw_insn_ip
*)cmd
, av
);
2744 if (cmd
->opcode
== O_IP_DST_SET
) /* set */
2746 else if (F_LEN(cmd
) == F_INSN_SIZE(ipfw_insn
)) /* me */
2747 cmd
->opcode
= O_IP_DST_ME
;
2748 else if (F_LEN(cmd
) == F_INSN_SIZE(ipfw_insn_u32
)) /* one IP */
2749 cmd
->opcode
= O_IP_DST
;
2750 else /* addr/mask */
2751 cmd
->opcode
= O_IP_DST_MASK
;
2756 add_ports(ipfw_insn
*cmd
, char *av
, u_char proto
, int opcode
)
2758 if (!strncmp(av
, "any", strlen(av
))) {
2760 } else if (fill_newports((ipfw_insn_u16
*)cmd
, av
, proto
)) {
2761 /* XXX todo: check that we have a protocol with ports */
2762 cmd
->opcode
= opcode
;
2769 * Parse arguments and assemble the microinstructions which make up a rule.
2770 * Rules are added into the 'rulebuf' and then copied in the correct order
2771 * into the actual rule.
2773 * The syntax for a rule starts with the action, followed by an
2774 * optional log action, and the various match patterns.
2775 * In the assembled microcode, the first opcode must be an O_PROBE_STATE
2776 * (generated if the rule includes a keep-state option), then the
2777 * various match patterns, the "log" action, and the actual action.
2781 add(int ac
, char *av
[])
2784 * rules are added into the 'rulebuf' and then copied in
2785 * the correct order into the actual rule.
2786 * Some things that need to go out of order (prob, action etc.)
2789 static uint32_t rulebuf
[255], actbuf
[255], cmdbuf
[255];
2791 ipfw_insn
*src
, *dst
, *cmd
, *action
, *prev
=NULL
;
2792 ipfw_insn
*first_cmd
; /* first match pattern */
2797 * various flags used to record that we entered some fields.
2799 ipfw_insn
*have_state
= NULL
; /* check-state or keep-state */
2803 int open_par
= 0; /* open parenthesis ( */
2805 /* proto is here because it is used to fetch ports */
2806 u_char proto
= IPPROTO_IP
; /* default protocol */
2808 double match_prob
= 1; /* match probability, default is always match */
2810 bzero(actbuf
, sizeof(actbuf
)); /* actions go here */
2811 bzero(cmdbuf
, sizeof(cmdbuf
));
2812 bzero(rulebuf
, sizeof(rulebuf
));
2814 rule
= (struct ip_fw
*)rulebuf
;
2815 cmd
= (ipfw_insn
*)cmdbuf
;
2816 action
= (ipfw_insn
*)actbuf
;
2820 /* [rule N] -- Rule number optional */
2821 if (ac
&& isdigit(**av
)) {
2822 rule
->rulenum
= atoi(*av
);
2827 /* [set N] -- set number (0..RESVD_SET), optional */
2828 if (ac
> 1 && !strncmp(*av
, "set", strlen(*av
))) {
2829 int set
= strtoul(av
[1], NULL
, 10);
2830 if (set
< 0 || set
> RESVD_SET
)
2831 errx(EX_DATAERR
, "illegal set %s", av
[1]);
2836 /* [prob D] -- match probability, optional */
2837 if (ac
> 1 && !strncmp(*av
, "prob", strlen(*av
))) {
2838 match_prob
= strtod(av
[1], NULL
);
2840 if (match_prob
<= 0 || match_prob
> 1)
2841 errx(EX_DATAERR
, "illegal match prob. %s", av
[1]);
2845 /* action -- mandatory */
2846 NEED1("missing action");
2847 i
= match_token(rule_actions
, *av
);
2849 action
->len
= 1; /* default */
2851 case TOK_CHECKSTATE
:
2852 have_state
= action
;
2853 action
->opcode
= O_CHECK_STATE
;
2857 action
->opcode
= O_ACCEPT
;
2861 action
->opcode
= O_DENY
;
2866 action
->opcode
= O_REJECT
;
2867 action
->arg1
= ICMP_UNREACH_HOST
;
2871 action
->opcode
= O_REJECT
;
2872 action
->arg1
= ICMP_REJECT_RST
;
2876 action
->opcode
= O_REJECT
;
2877 NEED1("missing reject code");
2878 fill_reject_code(&action
->arg1
, *av
);
2883 action
->opcode
= O_COUNT
;
2888 action
->len
= F_INSN_SIZE(ipfw_insn_pipe
);
2891 action
->opcode
= O_QUEUE
;
2892 else if (i
== TOK_PIPE
)
2893 action
->opcode
= O_PIPE
;
2894 else if (i
== TOK_SKIPTO
)
2895 action
->opcode
= O_SKIPTO
;
2896 NEED1("missing skipto/pipe/queue number");
2897 action
->arg1
= strtoul(*av
, NULL
, 10);
2903 action
->opcode
= (i
== TOK_DIVERT
) ? O_DIVERT
: O_TEE
;
2904 NEED1("missing divert/tee port");
2905 action
->arg1
= strtoul(*av
, NULL
, 0);
2906 if (action
->arg1
== 0) {
2909 s
= getservbyname(av
[0], "divert");
2911 action
->arg1
= ntohs(s
->s_port
);
2913 errx(EX_DATAERR
, "illegal divert/tee port");
2919 ipfw_insn_sa
*p
= (ipfw_insn_sa
*)action
;
2922 NEED1("missing forward address[:port]");
2924 action
->opcode
= O_FORWARD_IP
;
2925 action
->len
= F_INSN_SIZE(ipfw_insn_sa
);
2927 p
->sa
.sin_len
= sizeof(struct sockaddr_in
);
2928 p
->sa
.sin_family
= AF_INET
;
2931 * locate the address-port separator (':' or ',')
2933 s
= strchr(*av
, ':');
2935 s
= strchr(*av
, ',');
2938 i
= strtoport(s
, &end
, 0 /* base */, 0 /* proto */);
2941 "illegal forwarding port ``%s''", s
);
2942 p
->sa
.sin_port
= (u_short
)i
;
2944 lookup_host(*av
, &(p
->sa
.sin_addr
));
2950 /* pretend it is a 'count' rule followed by the comment */
2951 action
->opcode
= O_COUNT
;
2952 ac
++; av
--; /* go back... */
2956 errx(EX_DATAERR
, "invalid action %s\n", av
[-1]);
2958 action
= next_cmd(action
);
2961 * [log [logamount N]] -- log, optional
2963 * If exists, it goes first in the cmdbuf, but then it is
2964 * skipped in the copy section to the end of the buffer.
2966 if (ac
&& !strncmp(*av
, "log", strlen(*av
))) {
2967 ipfw_insn_log
*c
= (ipfw_insn_log
*)cmd
;
2970 cmd
->len
= F_INSN_SIZE(ipfw_insn_log
);
2971 cmd
->opcode
= O_LOG
;
2973 if (ac
&& !strncmp(*av
, "logamount", strlen(*av
))) {
2975 NEED1("logamount requires argument");
2978 errx(EX_DATAERR
, "logamount must be positive");
2982 cmd
= next_cmd(cmd
);
2985 if (have_state
) /* must be a check-state, we are done */
2988 #define OR_START(target) \
2989 if (ac && (*av[0] == '(' || *av[0] == '{')) { \
2991 errx(EX_USAGE, "nested \"(\" not allowed\n"); \
2994 if ( (av[0])[1] == '\0') { \
3005 !strncmp(*av, ")", strlen(*av)) || \
3006 !strncmp(*av, "}", strlen(*av)) )) { \
3011 errx(EX_USAGE, "missing \")\"\n"); \
3015 if (ac && !strncmp(*av, "not", strlen(*av))) { \
3016 if (cmd->len & F_NOT) \
3017 errx(EX_USAGE, "double \"not\" not allowed\n"); \
3018 cmd->len |= F_NOT; \
3022 #define OR_BLOCK(target) \
3023 if (ac && !strncmp(*av, "or", strlen(*av))) { \
3024 if (prev == NULL || open_par == 0) \
3025 errx(EX_DATAERR, "invalid OR block"); \
3026 prev->len |= F_OR; \
3036 * MAC addresses, optional.
3037 * If we have this, we skip the part "proto from src to dst"
3038 * and jump straight to the option parsing.
3041 NEED1("missing protocol");
3042 if (!strncmp(*av
, "MAC", strlen(*av
)) ||
3043 !strncmp(*av
, "mac", strlen(*av
))) {
3044 ac
--; av
++; /* the "MAC" keyword */
3045 add_mac(cmd
, ac
, av
); /* exits in case of errors */
3046 cmd
= next_cmd(cmd
);
3047 ac
-= 2; av
+= 2; /* dst-mac and src-mac */
3049 NEED1("missing mac type");
3050 if (add_mactype(cmd
, ac
, av
[0]))
3051 cmd
= next_cmd(cmd
);
3052 ac
--; av
++; /* any or mac-type */
3058 * protocol, mandatory
3060 OR_START(get_proto
);
3062 NEED1("missing protocol");
3063 if (add_proto(cmd
, *av
)) {
3065 if (F_LEN(cmd
) == 0) /* plain IP */
3070 cmd
= next_cmd(cmd
);
3072 } else if (first_cmd
!= cmd
) {
3073 errx(EX_DATAERR
, "invalid protocol ``%s''", *av
);
3076 OR_BLOCK(get_proto
);
3081 if (!ac
|| strncmp(*av
, "from", strlen(*av
)))
3082 errx(EX_USAGE
, "missing ``from''");
3086 * source IP, mandatory
3088 OR_START(source_ip
);
3089 NOT_BLOCK
; /* optional "not" */
3090 NEED1("missing source address");
3091 if (add_srcip(cmd
, *av
)) {
3093 if (F_LEN(cmd
) != 0) { /* ! any */
3095 cmd
= next_cmd(cmd
);
3098 OR_BLOCK(source_ip
);
3101 * source ports, optional
3103 NOT_BLOCK
; /* optional "not" */
3105 if (!strncmp(*av
, "any", strlen(*av
)) ||
3106 add_ports(cmd
, *av
, proto
, O_IP_SRCPORT
)) {
3108 if (F_LEN(cmd
) != 0)
3109 cmd
= next_cmd(cmd
);
3116 if (!ac
|| strncmp(*av
, "to", strlen(*av
)))
3117 errx(EX_USAGE
, "missing ``to''");
3121 * destination, mandatory
3124 NOT_BLOCK
; /* optional "not" */
3125 NEED1("missing dst address");
3126 if (add_dstip(cmd
, *av
)) {
3128 if (F_LEN(cmd
) != 0) { /* ! any */
3130 cmd
= next_cmd(cmd
);
3136 * dest. ports, optional
3138 NOT_BLOCK
; /* optional "not" */
3140 if (!strncmp(*av
, "any", strlen(*av
)) ||
3141 add_ports(cmd
, *av
, proto
, O_IP_DSTPORT
)) {
3143 if (F_LEN(cmd
) != 0)
3144 cmd
= next_cmd(cmd
);
3149 if (ac
&& first_cmd
== cmd
) {
3151 * nothing specified so far, store in the rule to ease
3159 ipfw_insn_u32
*cmd32
; /* alias for cmd */
3162 cmd32
= (ipfw_insn_u32
*)cmd
;
3164 if (*s
== '!') { /* alternate syntax for NOT */
3165 if (cmd
->len
& F_NOT
)
3166 errx(EX_USAGE
, "double \"not\" not allowed\n");
3170 i
= match_token(rule_options
, s
);
3174 if (cmd
->len
& F_NOT
)
3175 errx(EX_USAGE
, "double \"not\" not allowed\n");
3180 if (open_par
== 0 || prev
== NULL
)
3181 errx(EX_USAGE
, "invalid \"or\" block\n");
3185 case TOK_STARTBRACE
:
3187 errx(EX_USAGE
, "+nested \"(\" not allowed\n");
3193 errx(EX_USAGE
, "+missing \")\"\n");
3199 fill_cmd(cmd
, O_IN
, 0, 0);
3203 cmd
->len
^= F_NOT
; /* toggle F_NOT */
3204 fill_cmd(cmd
, O_IN
, 0, 0);
3208 fill_cmd(cmd
, O_FRAG
, 0, 0);
3212 fill_cmd(cmd
, O_LAYER2
, 0, 0);
3218 NEED1("recv, xmit, via require interface name"
3220 fill_iface((ipfw_insn_if
*)cmd
, av
[0]);
3222 if (F_LEN(cmd
) == 0) /* not a valid address */
3225 cmd
->opcode
= O_XMIT
;
3226 else if (i
== TOK_RECV
)
3227 cmd
->opcode
= O_RECV
;
3228 else if (i
== TOK_VIA
)
3229 cmd
->opcode
= O_VIA
;
3233 NEED1("icmptypes requires list of types");
3234 fill_icmptypes((ipfw_insn_u32
*)cmd
, *av
);
3239 NEED1("ipttl requires TTL");
3240 if (strpbrk(*av
, "-,")) {
3241 if (!add_ports(cmd
, *av
, 0, O_IPTTL
))
3242 errx(EX_DATAERR
, "invalid ipttl %s", *av
);
3244 fill_cmd(cmd
, O_IPTTL
, 0, strtoul(*av
, NULL
, 0));
3249 NEED1("ipid requires id");
3250 if (strpbrk(*av
, "-,")) {
3251 if (!add_ports(cmd
, *av
, 0, O_IPID
))
3252 errx(EX_DATAERR
, "invalid ipid %s", *av
);
3254 fill_cmd(cmd
, O_IPID
, 0, strtoul(*av
, NULL
, 0));
3259 NEED1("iplen requires length");
3260 if (strpbrk(*av
, "-,")) {
3261 if (!add_ports(cmd
, *av
, 0, O_IPLEN
))
3262 errx(EX_DATAERR
, "invalid ip len %s", *av
);
3264 fill_cmd(cmd
, O_IPLEN
, 0, strtoul(*av
, NULL
, 0));
3269 NEED1("ipver requires version");
3270 fill_cmd(cmd
, O_IPVER
, 0, strtoul(*av
, NULL
, 0));
3274 case TOK_IPPRECEDENCE
:
3275 NEED1("ipprecedence requires value");
3276 fill_cmd(cmd
, O_IPPRECEDENCE
, 0,
3277 (strtoul(*av
, NULL
, 0) & 7) << 5);
3282 NEED1("missing argument for ipoptions");
3283 fill_flags(cmd
, O_IPOPT
, f_ipopts
, *av
);
3288 NEED1("missing argument for iptos");
3289 fill_flags(cmd
, O_IPTOS
, f_iptos
, *av
);
3294 NEED1("uid requires argument");
3300 cmd
->opcode
= O_UID
;
3301 uid
= strtoul(*av
, &end
, 0);
3302 pwd
= (*end
== '\0') ? getpwuid(uid
) : getpwnam(*av
);
3304 errx(EX_DATAERR
, "uid \"%s\" nonexistent", *av
);
3305 cmd32
->d
[0] = pwd
->pw_uid
;
3306 cmd
->len
= F_INSN_SIZE(ipfw_insn_u32
);
3312 NEED1("gid requires argument");
3318 cmd
->opcode
= O_GID
;
3319 gid
= strtoul(*av
, &end
, 0);
3320 grp
= (*end
== '\0') ? getgrgid(gid
) : getgrnam(*av
);
3322 errx(EX_DATAERR
, "gid \"%s\" nonexistent", *av
);
3323 cmd32
->d
[0] = grp
->gr_gid
;
3324 cmd
->len
= F_INSN_SIZE(ipfw_insn_u32
);
3330 fill_cmd(cmd
, O_ESTAB
, 0, 0);
3334 fill_cmd(cmd
, O_TCPFLAGS
, 0,
3335 (TH_SYN
) | ( (TH_ACK
) & 0xff) <<8 );
3339 NEED1("missing argument for tcpoptions");
3340 fill_flags(cmd
, O_TCPOPTS
, f_tcpopts
, *av
);
3346 NEED1("tcpseq/tcpack requires argument");
3347 cmd
->len
= F_INSN_SIZE(ipfw_insn_u32
);
3348 cmd
->opcode
= (i
== TOK_TCPSEQ
) ? O_TCPSEQ
: O_TCPACK
;
3349 cmd32
->d
[0] = htonl(strtoul(*av
, NULL
, 0));
3354 NEED1("tcpwin requires length");
3355 fill_cmd(cmd
, O_TCPWIN
, 0,
3356 htons(strtoul(*av
, NULL
, 0)));
3361 NEED1("missing argument for tcpflags");
3362 cmd
->opcode
= O_TCPFLAGS
;
3363 fill_flags(cmd
, O_TCPFLAGS
, f_tcpflags
, *av
);
3369 errx(EX_USAGE
, "keep-state cannot be part "
3372 errx(EX_USAGE
, "only one of keep-state "
3373 "and limit is allowed");
3375 fill_cmd(cmd
, O_KEEP_STATE
, 0, 0);
3380 errx(EX_USAGE
, "limit cannot be part "
3383 errx(EX_USAGE
, "only one of keep-state "
3384 "and limit is allowed");
3385 NEED1("limit needs mask and # of connections");
3388 ipfw_insn_limit
*c
= (ipfw_insn_limit
*)cmd
;
3390 cmd
->len
= F_INSN_SIZE(ipfw_insn_limit
);
3391 cmd
->opcode
= O_LIMIT
;
3397 val
= match_token(limit_masks
, *av
);
3400 c
->limit_mask
|= val
;
3403 c
->conn_limit
= atoi(*av
);
3404 if (c
->conn_limit
== 0)
3405 errx(EX_USAGE
, "limit: limit must be >0");
3406 if (c
->limit_mask
== 0)
3407 errx(EX_USAGE
, "missing limit mask");
3413 NEED1("missing protocol");
3414 if (add_proto(cmd
, *av
)) {
3418 errx(EX_DATAERR
, "invalid protocol ``%s''",
3423 NEED1("missing source IP");
3424 if (add_srcip(cmd
, *av
)) {
3430 NEED1("missing destination IP");
3431 if (add_dstip(cmd
, *av
)) {
3437 NEED1("missing source port");
3438 if (!strncmp(*av
, "any", strlen(*av
)) ||
3439 add_ports(cmd
, *av
, proto
, O_IP_SRCPORT
)) {
3442 errx(EX_DATAERR
, "invalid source port %s", *av
);
3446 NEED1("missing destination port");
3447 if (!strncmp(*av
, "any", strlen(*av
)) ||
3448 add_ports(cmd
, *av
, proto
, O_IP_DSTPORT
)) {
3451 errx(EX_DATAERR
, "invalid destination port %s",
3457 errx(EX_USAGE
, "MAC dst-mac src-mac");
3458 if (add_mac(cmd
, ac
, av
)) {
3464 NEED1("missing mac type");
3465 if (!add_mactype(cmd
, ac
, *av
))
3466 errx(EX_DATAERR
, "invalid mac type %s", *av
);
3470 case TOK_VERREVPATH
:
3471 fill_cmd(cmd
, O_VERREVPATH
, 0, 0);
3475 fill_cmd(cmd
, O_IPSEC
, 0, 0);
3479 fill_comment(cmd
, ac
, av
);
3485 errx(EX_USAGE
, "unrecognised option [%d] %s\n", i
, s
);
3487 if (F_LEN(cmd
) > 0) { /* prepare to advance */
3489 cmd
= next_cmd(cmd
);
3495 * Now copy stuff into the rule.
3496 * If we have a keep-state option, the first instruction
3497 * must be a PROBE_STATE (which is generated here).
3498 * If we have a LOG option, it was stored as the first command,
3499 * and now must be moved to the top of the action part.
3501 dst
= (ipfw_insn
*)rule
->cmd
;
3504 * First thing to write into the command stream is the match probability.
3506 if (match_prob
!= 1) { /* 1 means always match */
3507 dst
->opcode
= O_PROB
;
3509 *((int32_t *)(dst
+1)) = (int32_t)(match_prob
* 0x7fffffff);
3514 * generate O_PROBE_STATE if necessary
3516 if (have_state
&& have_state
->opcode
!= O_CHECK_STATE
) {
3517 fill_cmd(dst
, O_PROBE_STATE
, 0, 0);
3518 dst
= next_cmd(dst
);
3521 * copy all commands but O_LOG, O_KEEP_STATE, O_LIMIT
3523 for (src
= (ipfw_insn
*)cmdbuf
; src
!= cmd
; src
+= i
) {
3526 switch (src
->opcode
) {
3532 bcopy(src
, dst
, i
* sizeof(uint32_t));
3538 * put back the have_state command as last opcode
3540 if (have_state
&& have_state
->opcode
!= O_CHECK_STATE
) {
3541 i
= F_LEN(have_state
);
3542 bcopy(have_state
, dst
, i
* sizeof(uint32_t));
3546 * start action section
3548 rule
->act_ofs
= dst
- rule
->cmd
;
3551 * put back O_LOG if necessary
3553 src
= (ipfw_insn
*)cmdbuf
;
3554 if (src
->opcode
== O_LOG
) {
3556 bcopy(src
, dst
, i
* sizeof(uint32_t));
3560 * copy all other actions
3562 for (src
= (ipfw_insn
*)actbuf
; src
!= action
; src
+= i
) {
3564 bcopy(src
, dst
, i
* sizeof(uint32_t));
3568 rule
->cmd_len
= (uint32_t *)dst
- (uint32_t *)(rule
->cmd
);
3569 i
= (char *)dst
- (char *)rule
;
3571 if (do_cmd(IP_FW_ADD
, rule
, (uintptr_t)&i
) == -1)
3572 err(EX_UNAVAILABLE
, "getsockopt(%s)", "IP_FW_ADD");
3574 show_ipfw(rule
, 0, 0);
3578 zero(int ac
, char *av
[], int optname
/* IP_FW_ZERO or IP_FW_RESETLOG */)
3583 char const *name
= optname
== IP_FW_ZERO
? "ZERO" : "RESETLOG";
3586 bzero(&rule
, sizeof(rule
));
3589 /* clear all entries - send empty rule */
3590 if (do_cmd(optname
, &rule
, sizeof(rule
)) < 0)
3591 err(EX_UNAVAILABLE
, "setsockopt(IP_FW_%s)", name
);
3593 printf("%s.\n", optname
== IP_FW_ZERO
?
3594 "Accounting cleared":"Logging counts reset");
3601 if (isdigit(**av
)) {
3602 rulenum
= atoi(*av
);
3605 rule
.rulenum
= rulenum
;
3606 if (do_cmd(optname
, &rule
, sizeof(rule
))) {
3607 warn("rule %u: setsockopt(IP_FW_%s)",
3609 failed
= EX_UNAVAILABLE
;
3610 } else if (!do_quiet
)
3611 printf("Entry %d %s.\n", rulenum
,
3612 optname
== IP_FW_ZERO
?
3613 "cleared" : "logging count reset");
3615 errx(EX_USAGE
, "invalid rule number ``%s''", *av
);
3618 if (failed
!= EX_OK
)
3625 int cmd
= do_pipe
? IP_DUMMYNET_FLUSH
: IP_FW_FLUSH
;
3628 if (!force
&& !do_quiet
) { /* need to ask user */
3631 printf("Are you sure? [yn] ");
3634 c
= toupper(getc(stdin
));
3635 while (c
!= '\n' && getc(stdin
) != '\n')
3637 return; /* and do not flush */
3638 } while (c
!= 'Y' && c
!= 'N');
3640 if (c
== 'N') /* user said no */
3644 if (cmd
== IP_FW_FLUSH
) {
3645 /* send empty rule */
3646 bzero(&rule
, sizeof(rule
));
3647 if (do_cmd(cmd
, &rule
, sizeof(rule
)) < 0)
3648 err(EX_UNAVAILABLE
, "setsockopt(IP_FW_FLUSH)");
3651 if (do_cmd(cmd
, NULL
, 0) < 0)
3652 err(EX_UNAVAILABLE
, "setsockopt(IP_DUMMYNET_FLUSH)");
3655 printf("Flushed all %s.\n", do_pipe
? "pipes" : "rules");
3659 * Free a the (locally allocated) copy of command line arguments.
3662 free_args(int ac
, char **av
)
3666 for (i
=0; i
< ac
; i
++)
3672 * Called with the arguments (excluding program name).
3673 * Returns 0 if successful, 1 if empty command, errx() in case of errors.
3676 ipfw_main(int oldac
, char **oldav
)
3678 int ch
, ac
, save_ac
;
3679 char **av
, **save_av
;
3680 int do_acct
= 0; /* Show packet/byte count */
3681 int do_force
= 0; /* Don't ask for confirmation */
3683 #define WHITESP " \t\f\v\n\r"
3686 else if (oldac
== 1) {
3688 * If we are called with a single string, try to split it into
3689 * arguments for subsequent parsing.
3690 * But first, remove spaces after a ',', by copying the string
3693 char *arg
= oldav
[0]; /* The string... */
3694 int l
= strlen(arg
);
3695 int copy
= 0; /* 1 if we need to copy, 0 otherwise */
3697 for (i
= j
= 0; i
< l
; i
++) {
3698 if (arg
[i
] == '#') /* comment marker */
3702 copy
= !index("," WHITESP
, arg
[i
]);
3704 copy
= !index(WHITESP
, arg
[i
]);
3709 if (!copy
&& j
> 0) /* last char was a 'blank', remove it */
3711 l
= j
; /* the new argument length */
3713 if (l
== 0) /* empty string! */
3717 * First, count number of arguments. Because of the previous
3718 * processing, this is just the number of blanks plus 1.
3720 for (i
= 0, ac
= 1; i
< l
; i
++)
3721 if (index(WHITESP
, arg
[i
]) != NULL
)
3724 av
= calloc(ac
, sizeof(char *));
3727 * Second, copy arguments from cmd[] to av[]. For each one,
3728 * j is the initial character, i is the one past the end.
3730 for (ac
= 0, i
= j
= 0; i
< l
; i
++)
3731 if (index(WHITESP
, arg
[i
]) != NULL
|| i
== l
-1) {
3734 av
[ac
] = calloc(i
-j
+1, 1);
3735 bcopy(arg
+j
, av
[ac
], i
-j
);
3741 * If an argument ends with ',' join with the next one.
3745 av
= calloc(oldac
, sizeof(char *));
3746 for (first
= i
= ac
= 0, l
= 0; i
< oldac
; i
++) {
3747 char *arg
= oldav
[i
];
3748 int k
= strlen(arg
);
3751 if (arg
[k
-1] != ',' || i
== oldac
-1) {
3753 av
[ac
] = calloc(l
+1, 1);
3754 for (l
=0; first
<= i
; first
++) {
3755 strcat(av
[ac
]+l
, oldav
[first
]);
3756 l
+= strlen(oldav
[first
]);
3765 /* Set the force flag for non-interactive processes */
3766 do_force
= !isatty(STDIN_FILENO
);
3768 /* Save arguments for final freeing of memory. */
3772 optind
= optreset
= 0;
3773 while ((ch
= getopt(ac
, av
, "acdefhnNqs:STtv")) != -1)
3795 case 'h': /* help */
3796 free_args(save_ac
, save_av
);
3798 break; /* NOTREACHED */
3812 case 's': /* sort */
3813 do_sort
= atoi(optarg
);
3825 do_time
= 2; /* numeric timestamp */
3828 case 'v': /* verbose */
3833 free_args(save_ac
, save_av
);
3839 NEED1("bad arguments, for usage summary ``ipfw''");
3842 * An undocumented behaviour of ipfw1 was to allow rule numbers first,
3843 * e.g. "100 add allow ..." instead of "add 100 allow ...".
3844 * In case, swap first and second argument to get the normal form.
3846 if (ac
> 1 && isdigit(*av
[0])) {
3854 * optional: pipe or queue
3857 if (!strncmp(*av
, "pipe", strlen(*av
)))
3859 else if (!strncmp(*av
, "queue", strlen(*av
)))
3865 NEED1("missing command");
3868 * For pipes and queues we normally say 'pipe NN config'
3869 * but the code is easier to parse as 'pipe config NN'
3870 * so we swap the two arguments.
3872 if (do_pipe
> 0 && ac
> 1 && isdigit(*av
[0])) {
3879 if (!strncmp(*av
, "add", strlen(*av
)))
3881 else if (do_pipe
&& !strncmp(*av
, "config", strlen(*av
)))
3882 config_pipe(ac
, av
);
3883 else if (!strncmp(*av
, "delete", strlen(*av
)))
3885 else if (!strncmp(*av
, "flush", strlen(*av
)))
3887 else if (!strncmp(*av
, "zero", strlen(*av
)))
3888 zero(ac
, av
, IP_FW_ZERO
);
3889 else if (!strncmp(*av
, "resetlog", strlen(*av
)))
3890 zero(ac
, av
, IP_FW_RESETLOG
);
3891 else if (!strncmp(*av
, "print", strlen(*av
)) ||
3892 !strncmp(*av
, "list", strlen(*av
)))
3893 list(ac
, av
, do_acct
);
3894 else if (!strncmp(*av
, "set", strlen(*av
)))
3895 sets_handler(ac
, av
);
3896 else if (!strncmp(*av
, "enable", strlen(*av
)))
3897 sysctl_handler(ac
, av
, 1);
3898 else if (!strncmp(*av
, "disable", strlen(*av
)))
3899 sysctl_handler(ac
, av
, 0);
3900 else if (!strncmp(*av
, "show", strlen(*av
)))
3901 list(ac
, av
, 1 /* show counters */);
3903 errx(EX_USAGE
, "bad command `%s'", *av
);
3905 /* Free memory allocated in the argument parsing. */
3906 free_args(save_ac
, save_av
);
3912 ipfw_readfile(int ac
, char *av
[])
3916 char *cmd
= NULL
, *filename
= av
[ac
-1];
3921 filename
= av
[ac
-1];
3923 while ((c
= getopt(ac
, av
, "cNnp:qS")) != -1) {
3940 * Skip previous args and delete last one, so we
3941 * pass all but the last argument to the preprocessor
3947 fprintf(stderr
, "command is %s\n", av
[0]);
3959 errx(EX_USAGE
, "bad arguments, for usage"
3960 " summary ``ipfw''");
3967 if (cmd
== NULL
&& ac
!= optind
+ 1) {
3968 fprintf(stderr
, "ac %d, optind %d\n", ac
, optind
);
3969 errx(EX_USAGE
, "extraneous filename arguments");
3972 if ((f
= fopen(filename
, "r")) == NULL
)
3973 err(EX_UNAVAILABLE
, "fopen: %s", filename
);
3975 if (cmd
!= NULL
) { /* pipe through preprocessor */
3978 if (pipe(pipedes
) == -1)
3979 err(EX_OSERR
, "cannot create pipe");
3983 err(EX_OSERR
, "cannot fork");
3987 * Child, will run the preprocessor with the
3988 * file on stdin and the pipe on stdout.
3990 if (dup2(fileno(f
), 0) == -1
3991 || dup2(pipedes
[1], 1) == -1)
3992 err(EX_OSERR
, "dup2()");
3997 err(EX_OSERR
, "execvp(%s) failed", cmd
);
3998 } else { /* parent, will reopen f as the pipe */
4001 if ((f
= fdopen(pipedes
[0], "r")) == NULL
) {
4002 int savederrno
= errno
;
4004 (void)kill(preproc
, SIGTERM
);
4006 err(EX_OSERR
, "fdopen()");
4011 while (fgets(buf
, BUFSIZ
, f
)) { /* read commands */
4016 sprintf(linename
, "Line %d", lineno
);
4017 setprogname(linename
); /* XXX */
4025 if (waitpid(preproc
, &status
, 0) == -1)
4026 errx(EX_OSERR
, "waitpid()");
4027 if (WIFEXITED(status
) && WEXITSTATUS(status
) != EX_OK
)
4028 errx(EX_UNAVAILABLE
,
4029 "preprocessor exited with status %d",
4030 WEXITSTATUS(status
));
4031 else if (WIFSIGNALED(status
))
4032 errx(EX_UNAVAILABLE
,
4033 "preprocessor exited with signal %d",
4039 main(int ac
, char *av
[])
4042 * If the last argument is an absolute pathname, interpret it
4043 * as a file to be preprocessed.
4046 if (ac
> 1 && av
[ac
- 1][0] == '/' && access(av
[ac
- 1], R_OK
) == 0)
4047 ipfw_readfile(ac
, av
);
4049 if (ipfw_main(ac
-1, av
+1))