2 * Copyright (c) 2002-2009 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_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. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
30 * Copyright (c) 2002-2003 Luigi Rizzo
31 * Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp
32 * Copyright (c) 1994 Ugen J.S.Antsilevich
34 * Idea and grammar partially left from:
35 * Copyright (c) 1993 Daniel Boulet
37 * Redistribution and use in source forms, with and without modification,
38 * are permitted provided that this entire comment appears intact.
40 * Redistribution in binary form may occur without any restrictions.
41 * Obviously, it would be nice if you gave credit where credit is due
42 * but requiring it would be too onerous.
44 * This software is provided ``AS IS'' without any warranties of any kind.
46 * NEW command line interface for IP firewall facility
48 * $FreeBSD: /repoman/r/ncvs/src/sbin/ipfw/ipfw2.c,v 1.4.2.18 2003/09/15 10:27:03 luigi Exp $
51 #include <sys/param.h>
53 #include <sys/socket.h>
54 #include <sys/sockio.h>
55 #include <sys/sysctl.h>
75 #include <netinet/in.h>
76 #include <netinet/in_systm.h>
77 #include <netinet/ip.h>
78 #include <netinet/ip_icmp.h>
80 #include <netinet/ip_fw.h>
82 #include <net/route.h> /* def. of struct route */
83 #include <netinet/ip_dummynet.h>
84 #include <netinet/tcp.h>
85 #include <arpa/inet.h>
88 do_resolv
, /* Would try to resolve all */
89 do_time
, /* Show time stamps */
90 do_quiet
, /* Be quiet in add and flush */
91 do_pipe
, /* this cmd refers to a pipe */
92 do_sort
, /* field to sort results (0 = no) */
93 do_dynamic
, /* display dynamic rules */
94 do_expired
, /* display expired dynamic rules */
95 do_compact
, /* show rules in compact mode */
96 show_sets
, /* display rule sets */
97 test_only
, /* only check syntax */
100 #define IP_MASK_ALL 0xffffffff
103 * _s_x is a structure that stores a string <-> token pairs, used in
104 * various places in the parser. Entries are stored in arrays,
105 * with an entry with s=NULL as terminator.
106 * The search routines are match_token() and match_value().
107 * Often, an element with x=0 contains an error string.
115 static struct _s_x f_tcpflags
[] = {
126 static struct _s_x f_tcpopts
[] = {
127 { "mss", IP_FW_TCPOPT_MSS
},
128 { "maxseg", IP_FW_TCPOPT_MSS
},
129 { "window", IP_FW_TCPOPT_WINDOW
},
130 { "sack", IP_FW_TCPOPT_SACK
},
131 { "ts", IP_FW_TCPOPT_TS
},
132 { "timestamp", IP_FW_TCPOPT_TS
},
133 { "cc", IP_FW_TCPOPT_CC
},
139 * IP options span the range 0 to 255 so we need to remap them
140 * (though in fact only the low 5 bits are significant).
142 static struct _s_x f_ipopts
[] = {
143 { "ssrr", IP_FW_IPOPT_SSRR
},
144 { "lsrr", IP_FW_IPOPT_LSRR
},
145 { "rr", IP_FW_IPOPT_RR
},
146 { "ts", IP_FW_IPOPT_TS
},
151 static struct _s_x f_iptos
[] = {
152 { "lowdelay", IPTOS_LOWDELAY
},
153 { "throughput", IPTOS_THROUGHPUT
},
154 { "reliability", IPTOS_RELIABILITY
},
155 { "mincost", IPTOS_MINCOST
},
156 { "congestion", IPTOS_CE
},
157 { "ecntransport", IPTOS_ECT
},
158 { "ip tos option", 0},
162 static struct _s_x limit_masks
[] = {
163 {"all", DYN_SRC_ADDR
|DYN_SRC_PORT
|DYN_DST_ADDR
|DYN_DST_PORT
},
164 {"src-addr", DYN_SRC_ADDR
},
165 {"src-port", DYN_SRC_PORT
},
166 {"dst-addr", DYN_DST_ADDR
},
167 {"dst-port", DYN_DST_PORT
},
172 * we use IPPROTO_ETHERTYPE as a fake protocol id to call the print routines
173 * This is only used in this code.
175 #define IPPROTO_ETHERTYPE 0x1000
176 static struct _s_x ether_types
[] = {
178 * Note, we cannot use "-:&/" in the names because they are field
179 * separators in the type specifications. Also, we use s = NULL as
180 * end-delimiter, because a type of 0 can be legal.
193 { "pppoe_disc", 0x8863 },
194 { "pppoe_sess", 0x8864 },
195 { "ipx_8022", 0x00E0 },
196 { "ipx_8023", 0x0000 },
197 { "ipx_ii", 0x8137 },
198 { "ipx_snap", 0x8137 },
204 static struct _s_x exception_types
[] = {
216 static void show_usage(void);
290 struct _s_x dummynet_params
[] = {
292 { "noerror", TOK_NOERROR
},
293 { "buckets", TOK_BUCKETS
},
294 { "dst-ip", TOK_DSTIP
},
295 { "src-ip", TOK_SRCIP
},
296 { "dst-port", TOK_DSTPORT
},
297 { "src-port", TOK_SRCPORT
},
298 { "proto", TOK_PROTO
},
299 { "weight", TOK_WEIGHT
},
301 { "mask", TOK_MASK
},
302 { "droptail", TOK_DROPTAIL
},
304 { "gred", TOK_GRED
},
306 { "bandwidth", TOK_BW
},
307 { "delay", TOK_DELAY
},
308 { "pipe", TOK_PIPE
},
309 { "queue", TOK_QUEUE
},
310 { "dummynet-params", TOK_NULL
},
311 { NULL
, 0 } /* terminator */
314 struct _s_x rule_actions
[] = {
315 { "accept", TOK_ACCEPT
},
316 { "pass", TOK_ACCEPT
},
317 { "allow", TOK_ACCEPT
},
318 { "permit", TOK_ACCEPT
},
319 { "count", TOK_COUNT
},
320 { "pipe", TOK_PIPE
},
321 { "queue", TOK_QUEUE
},
322 { "divert", TOK_DIVERT
},
324 { "fwd", TOK_FORWARD
},
325 { "forward", TOK_FORWARD
},
326 { "skipto", TOK_SKIPTO
},
327 { "deny", TOK_DENY
},
328 { "drop", TOK_DENY
},
329 { "reject", TOK_REJECT
},
330 { "reset", TOK_RESET
},
331 { "unreach", TOK_UNREACH
},
332 { "check-state", TOK_CHECKSTATE
},
333 { "//", TOK_COMMENT
},
334 { NULL
, 0 } /* terminator */
337 struct _s_x rule_options
[] = {
341 { "limit", TOK_LIMIT
},
342 { "keep-state", TOK_KEEPSTATE
},
343 { "bridged", TOK_LAYER2
},
344 { "layer2", TOK_LAYER2
},
346 { "xmit", TOK_XMIT
},
347 { "recv", TOK_RECV
},
349 { "fragment", TOK_FRAG
},
350 { "frag", TOK_FRAG
},
351 { "ipoptions", TOK_IPOPTS
},
352 { "ipopts", TOK_IPOPTS
},
353 { "iplen", TOK_IPLEN
},
354 { "ipid", TOK_IPID
},
355 { "ipprecedence", TOK_IPPRECEDENCE
},
356 { "iptos", TOK_IPTOS
},
357 { "ipttl", TOK_IPTTL
},
358 { "ipversion", TOK_IPVER
},
359 { "ipver", TOK_IPVER
},
360 { "estab", TOK_ESTAB
},
361 { "established", TOK_ESTAB
},
362 { "setup", TOK_SETUP
},
363 { "tcpflags", TOK_TCPFLAGS
},
364 { "tcpflgs", TOK_TCPFLAGS
},
365 { "tcpoptions", TOK_TCPOPTS
},
366 { "tcpopts", TOK_TCPOPTS
},
367 { "tcpseq", TOK_TCPSEQ
},
368 { "tcpack", TOK_TCPACK
},
369 { "tcpwin", TOK_TCPWIN
},
370 { "icmptype", TOK_ICMPTYPES
},
371 { "icmptypes", TOK_ICMPTYPES
},
372 { "dst-ip", TOK_DSTIP
},
373 { "src-ip", TOK_SRCIP
},
374 { "dst-port", TOK_DSTPORT
},
375 { "src-port", TOK_SRCPORT
},
376 { "proto", TOK_PROTO
},
379 { "mac-type", TOK_MACTYPE
},
380 { "verrevpath", TOK_VERREVPATH
},
381 { "ipsec", TOK_IPSEC
},
382 { "//", TOK_COMMENT
},
384 { "not", TOK_NOT
}, /* pseudo option */
385 { "!", /* escape ? */ TOK_NOT
}, /* pseudo option */
386 { "or", TOK_OR
}, /* pseudo option */
387 { "|", /* escape */ TOK_OR
}, /* pseudo option */
388 { "{", TOK_STARTBRACE
}, /* pseudo option */
389 { "(", TOK_STARTBRACE
}, /* pseudo option */
390 { "}", TOK_ENDBRACE
}, /* pseudo option */
391 { ")", TOK_ENDBRACE
}, /* pseudo option */
392 { NULL
, 0 } /* terminator */
395 static __inline
uint64_t
396 align_uint64(uint64_t *pll
) {
399 bcopy (pll
, &ret
, sizeof(ret
));
404 * conditionally runs the command.
407 do_cmd(int optname
, void *optval
, uintptr_t optlen
)
409 static int s
= -1; /* the socket */
416 s
= socket(AF_INET
, SOCK_RAW
, IPPROTO_RAW
);
418 err(EX_UNAVAILABLE
, "socket");
427 ((struct ip_fw
*)optval
)->version
= IP_FW_CURRENT_API_VERSION
;
432 if (optname
== IP_FW_GET
|| optname
== IP_DUMMYNET_GET
||
433 optname
== IP_FW_ADD
)
434 i
= getsockopt(s
, IPPROTO_IP
, optname
, optval
,
435 (socklen_t
*)optlen
);
437 i
= setsockopt(s
, IPPROTO_IP
, optname
, optval
, optlen
);
442 * match_token takes a table and a string, returns the value associated
443 * with the string (-1 in case of failure).
446 match_token(struct _s_x
*table
, char *string
)
449 uint i
= strlen(string
);
451 for (pt
= table
; i
&& pt
->s
!= NULL
; pt
++)
452 if (strlen(pt
->s
) == i
&& !bcmp(string
, pt
->s
, i
))
458 * match_value takes a table and a value, returns the string associated
459 * with the value (NULL in case of failure).
462 match_value(struct _s_x
*p
, int value
)
464 for (; p
->s
!= NULL
; p
++)
471 * prints one port, symbolic or numeric
474 print_port(int proto
, uint16_t port
)
477 if (proto
== IPPROTO_ETHERTYPE
) {
480 if (do_resolv
&& (s
= match_value(ether_types
, port
)) )
483 printf("0x%04x", port
);
485 struct servent
*se
= NULL
;
487 struct protoent
*pe
= getprotobynumber(proto
);
489 se
= getservbyport(htons(port
), pe
? pe
->p_name
: NULL
);
492 printf("%s", se
->s_name
);
498 struct _s_x _port_name
[] = {
499 {"dst-port", O_IP_DSTPORT
},
500 {"src-port", O_IP_SRCPORT
},
504 {"mac-type", O_MAC_TYPE
},
509 * Print the values in a list 16-bit items of the types above.
510 * XXX todo: add support for mask.
513 print_newports(ipfw_insn_u16
*cmd
, int proto
, int opcode
)
515 uint16_t *p
= cmd
->ports
;
519 if (cmd
->o
.len
& F_NOT
)
522 sep
= match_value(_port_name
, opcode
);
528 for (i
= F_LEN((ipfw_insn
*)cmd
) - 1; i
> 0; i
--, p
+= 2) {
530 print_port(proto
, p
[0]);
533 print_port(proto
, p
[1]);
540 * Like strtol, but also translates service names into port numbers
541 * for some protocols.
543 * proto == -1 disables the protocol check;
544 * proto == IPPROTO_ETHERTYPE looks up an internal table
545 * proto == <some value in /etc/protocols> matches the values there.
546 * Returns *end == s in case the parameter is not found.
549 strtoport(char *s
, char **end
, int base
, int proto
)
555 *end
= s
; /* default - not found */
557 return 0; /* not found */
560 return strtol(s
, end
, base
);
563 * find separator. '\\' escapes the next char.
565 for (s1
= s
; *s1
&& (isalnum(*s1
) || *s1
== '\\') ; s1
++)
566 if (*s1
== '\\' && s1
[1] != '\0')
569 buf
= malloc(s1
- s
+ 1);
574 * copy into a buffer skipping backslashes
576 for (p
= s
, i
= 0; p
!= s1
; p
++)
581 if ( match_token( exception_types
, buf
) != -1 ){
586 if (proto
== IPPROTO_ETHERTYPE
) {
587 i
= match_token(ether_types
, buf
);
589 if (i
!= -1) { /* found */
594 struct protoent
*pe
= NULL
;
598 pe
= getprotobynumber(proto
);
600 se
= getservbyname(buf
, pe
? pe
->p_name
: NULL
);
604 return ntohs(se
->s_port
);
607 return 0; /* not found */
611 * Fill the body of the command with the list of port ranges.
614 fill_newports(ipfw_insn_u16
*cmd
, char *av
, int proto
)
616 uint16_t a
, b
, *p
= cmd
->ports
;
621 a
= strtoport(av
, &s
, 0, proto
);
622 if (s
== av
) /* no parameter */
624 if (*s
== '-') { /* a range */
626 b
= strtoport(av
, &s
, 0, proto
);
627 if (s
== av
) /* no parameter */
631 } else if (*s
== ',' || *s
== '\0' )
633 else /* invalid separator */
634 errx(EX_DATAERR
, "invalid separator <%c> in <%s>",
641 if (i
+1 > F_LEN_MASK
)
642 errx(EX_DATAERR
, "too many ports/ranges");
643 cmd
->o
.len
|= i
+1; /* leave F_NOT and F_OR untouched */
648 static struct _s_x icmpcodes
[] = {
649 { "net", ICMP_UNREACH_NET
},
650 { "host", ICMP_UNREACH_HOST
},
651 { "protocol", ICMP_UNREACH_PROTOCOL
},
652 { "port", ICMP_UNREACH_PORT
},
653 { "needfrag", ICMP_UNREACH_NEEDFRAG
},
654 { "srcfail", ICMP_UNREACH_SRCFAIL
},
655 { "net-unknown", ICMP_UNREACH_NET_UNKNOWN
},
656 { "host-unknown", ICMP_UNREACH_HOST_UNKNOWN
},
657 { "isolated", ICMP_UNREACH_ISOLATED
},
658 { "net-prohib", ICMP_UNREACH_NET_PROHIB
},
659 { "host-prohib", ICMP_UNREACH_HOST_PROHIB
},
660 { "tosnet", ICMP_UNREACH_TOSNET
},
661 { "toshost", ICMP_UNREACH_TOSHOST
},
662 { "filter-prohib", ICMP_UNREACH_FILTER_PROHIB
},
663 { "host-precedence", ICMP_UNREACH_HOST_PRECEDENCE
},
664 { "precedence-cutoff", ICMP_UNREACH_PRECEDENCE_CUTOFF
},
669 fill_reject_code(u_short
*codep
, char *str
)
674 val
= strtoul(str
, &s
, 0);
675 if (s
== str
|| *s
!= '\0' || val
>= 0x100)
676 val
= match_token(icmpcodes
, str
);
678 errx(EX_DATAERR
, "unknown ICMP unreachable code ``%s''", str
);
684 print_reject_code(uint16_t code
)
686 char const *s
= match_value(icmpcodes
, code
);
689 printf("unreach %s", s
);
691 printf("unreach %u", code
);
695 * Returns the number of bits set (from left) in a contiguous bitmask,
696 * or -1 if the mask is not contiguous.
697 * XXX this needs a proper fix.
698 * This effectively works on masks in big-endian (network) format.
699 * when compiled on little endian architectures.
701 * First bit is bit 7 of the first byte -- note, for MAC addresses,
702 * the first bit on the wire is bit 0 of the first byte.
703 * len is the max length in bits.
706 contigmask(uint8_t *p
, int len
)
710 for (i
=0; i
<len
; i
++)
711 if ( (p
[i
/8] & (1 << (7 - (i%8
)))) == 0) /* first bit unset */
713 for (n
=i
+1; n
< len
; n
++)
714 if ( (p
[n
/8] & (1 << (7 - (n%8
)))) != 0)
715 return -1; /* mask not contiguous */
720 * print flags set/clear in the two bitmasks passed as parameters.
721 * There is a specialized check for f_tcpflags.
724 print_flags(char const *name
, ipfw_insn
*cmd
, struct _s_x
*list
)
726 char const *comma
= "";
728 uint8_t set
= cmd
->arg1
& 0xff;
729 uint8_t clear
= (cmd
->arg1
>> 8) & 0xff;
731 if (list
== f_tcpflags
&& set
== TH_SYN
&& clear
== TH_ACK
) {
736 printf(" %s ", name
);
737 for (i
=0; list
[i
].x
!= 0; i
++) {
738 if (set
& list
[i
].x
) {
740 printf("%s%s", comma
, list
[i
].s
);
743 if (clear
& list
[i
].x
) {
745 printf("%s!%s", comma
, list
[i
].s
);
752 * Print the ip address contained in a command.
755 print_ip(ipfw_insn_ip
*cmd
, char const *s
)
757 struct hostent
*he
= NULL
;
758 int len
= F_LEN((ipfw_insn
*)cmd
);
759 uint32_t *a
= ((ipfw_insn_u32
*)cmd
)->d
;
761 printf("%s%s ", cmd
->o
.len
& F_NOT
? " not": "", s
);
763 if (cmd
->o
.opcode
== O_IP_SRC_ME
|| cmd
->o
.opcode
== O_IP_DST_ME
) {
767 if (cmd
->o
.opcode
== O_IP_SRC_SET
|| cmd
->o
.opcode
== O_IP_DST_SET
) {
768 uint32_t x
, *map
= (uint32_t *)&(cmd
->mask
);
774 cmd
->addr
.s_addr
= htonl(cmd
->addr
.s_addr
);
775 printf("%s/%d", inet_ntoa(cmd
->addr
),
776 contigmask((uint8_t *)&x
, 32));
777 x
= cmd
->addr
.s_addr
= htonl(cmd
->addr
.s_addr
);
778 x
&= 0xff; /* base */
780 * Print bits and ranges.
781 * Locate first bit set (i), then locate first bit unset (j).
782 * If we have 3+ consecutive bits set, then print them as a
783 * range, otherwise only print the initial bit and rescan.
785 for (i
=0; i
< cmd
->o
.arg1
; i
++)
786 if (map
[i
/32] & (1<<(i
& 31))) {
787 for (j
=i
+1; j
< cmd
->o
.arg1
; j
++)
788 if (!(map
[ j
/32] & (1<<(j
& 31))))
790 printf("%c%d", comma
, i
+x
);
791 if (j
>i
+2) { /* range has at least 3 elements */
792 printf("-%d", j
-1+x
);
801 * len == 2 indicates a single IP, whereas lists of 1 or more
802 * addr/mask pairs have len = (2n+1). We convert len to n so we
803 * use that to count the number of entries.
805 for (len
= len
/ 2; len
> 0; len
--, a
+= 2) {
806 int mb
= /* mask length */
807 (cmd
->o
.opcode
== O_IP_SRC
|| cmd
->o
.opcode
== O_IP_DST
) ?
808 32 : contigmask((uint8_t *)&(a
[1]), 32);
809 if (mb
== 32 && do_resolv
)
810 he
= gethostbyaddr((char *)&(a
[0]), sizeof(in_addr_t
), AF_INET
);
811 if (he
!= NULL
) /* resolved to name */
812 printf("%s", he
->h_name
);
813 else if (mb
== 0) /* any */
815 else { /* numeric IP followed by some kind of mask */
816 printf("%s", inet_ntoa( *((struct in_addr
*)&a
[0]) ) );
818 printf(":%s", inet_ntoa( *((struct in_addr
*)&a
[1]) ) );
828 * prints a MAC address/mask pair
831 print_mac(uint8_t *addr
, uint8_t *mask
)
833 int l
= contigmask(mask
, 48);
838 printf(" %02x:%02x:%02x:%02x:%02x:%02x",
839 addr
[0], addr
[1], addr
[2], addr
[3], addr
[4], addr
[5]);
841 printf("&%02x:%02x:%02x:%02x:%02x:%02x",
842 mask
[0], mask
[1], mask
[2],
843 mask
[3], mask
[4], mask
[5]);
850 fill_icmptypes(ipfw_insn_u32
*cmd
, char *av
)
859 type
= strtoul(av
, &av
, 0);
861 if (*av
!= ',' && *av
!= '\0')
862 errx(EX_DATAERR
, "invalid ICMP type");
865 errx(EX_DATAERR
, "ICMP type out of range");
867 cmd
->d
[0] |= 1 << type
;
869 cmd
->o
.opcode
= O_ICMPTYPE
;
870 cmd
->o
.len
|= F_INSN_SIZE(ipfw_insn_u32
);
874 print_icmptypes(ipfw_insn_u32
*cmd
)
879 printf(" icmptypes");
880 for (i
= 0; i
< 32; i
++) {
881 if ( (cmd
->d
[0] & (1 << (i
))) == 0)
883 printf("%c%d", sep
, i
);
889 * show_ipfw() prints the body of an ipfw rule.
890 * Because the standard rule has at least proto src_ip dst_ip, we use
891 * a helper function to produce these entries if not provided explicitly.
892 * The first argument is the list of fields we have, the second is
893 * the list of fields we want to be printed.
895 * Special cases if we have provided a MAC header:
896 * + if the rule does not contain IP addresses/ports, do not print them;
897 * + if the rule does not contain an IP proto, print "all" instead of "ip";
899 * Once we have 'have_options', IP header fields are printed as options.
901 #define HAVE_PROTO 0x0001
902 #define HAVE_SRCIP 0x0002
903 #define HAVE_DSTIP 0x0004
904 #define HAVE_MAC 0x0008
905 #define HAVE_MACTYPE 0x0010
906 #define HAVE_OPTIONS 0x8000
908 #define HAVE_IP (HAVE_PROTO | HAVE_SRCIP | HAVE_DSTIP)
910 show_prerequisites(int *flags
, int want
, int cmd
)
912 if ( (*flags
& HAVE_IP
) == HAVE_IP
)
913 *flags
|= HAVE_OPTIONS
;
915 if ( (*flags
& (HAVE_MAC
|HAVE_MACTYPE
|HAVE_OPTIONS
)) == HAVE_MAC
&&
918 * mac-type was optimized out by the compiler,
922 *flags
|= HAVE_MACTYPE
| HAVE_OPTIONS
;
925 if ( !(*flags
& HAVE_OPTIONS
)) {
926 if ( !(*flags
& HAVE_PROTO
) && (want
& HAVE_PROTO
))
928 if ( !(*flags
& HAVE_SRCIP
) && (want
& HAVE_SRCIP
))
930 if ( !(*flags
& HAVE_DSTIP
) && (want
& HAVE_DSTIP
))
937 show_ipfw(struct ip_fw
*rule
, int pcwidth
, int bcwidth
)
939 static int twidth
= 0;
942 char *comment
= NULL
; /* ptr to comment if we have one */
943 int proto
= 0; /* default */
944 int flags
= 0; /* prerequisites */
945 ipfw_insn_log
*logptr
= NULL
; /* set if we find an O_LOG */
946 int or_block
= 0; /* we are in an or block */
947 uint32_t set_disable
;
949 bcopy(&rule
->next_rule
, &set_disable
, sizeof(set_disable
));
951 if (set_disable
& (1 << rule
->set
)) { /* disabled */
955 printf("# DISABLED ");
957 printf("%05u ", rule
->rulenum
);
959 if (pcwidth
>0 || bcwidth
>0)
960 printf("%*llu %*llu ", pcwidth
, align_uint64(&rule
->pcnt
),
961 bcwidth
, align_uint64(&rule
->bcnt
));
964 printf("%10u ", rule
->timestamp
);
965 else if (do_time
== 1) {
967 time_t t
= (time_t)0;
970 strlcpy(timestr
, ctime(&t
), sizeof(timestr
));
971 *strchr(timestr
, '\n') = '\0';
972 twidth
= strlen(timestr
);
974 if (rule
->timestamp
) {
975 #if _FreeBSD_version < 500000 /* XXX check */
976 #define _long_to_time(x) (time_t)(x)
978 t
= _long_to_time(rule
->timestamp
);
980 strlcpy(timestr
, ctime(&t
), sizeof(timestr
));
981 *strchr(timestr
, '\n') = '\0';
982 printf("%s ", timestr
);
984 printf("%*s", twidth
, " ");
989 printf("set %d ", rule
->set
);
992 * print the optional "match probability"
994 if (rule
->cmd_len
> 0) {
996 if (cmd
->opcode
== O_PROB
) {
997 ipfw_insn_u32
*p
= (ipfw_insn_u32
*)cmd
;
998 double d
= 1.0 * p
->d
[0];
1000 d
= (d
/ 0x7fffffff);
1001 printf("prob %f ", d
);
1006 * first print actions
1008 for (l
= rule
->cmd_len
- rule
->act_ofs
, cmd
= ACTION_PTR(rule
);
1009 l
> 0 ; l
-= F_LEN(cmd
), cmd
+= F_LEN(cmd
)) {
1010 switch(cmd
->opcode
) {
1012 printf("check-state");
1013 flags
= HAVE_IP
; /* avoid printing anything else */
1029 if (cmd
->arg1
== ICMP_REJECT_RST
)
1031 else if (cmd
->arg1
== ICMP_UNREACH_HOST
)
1034 print_reject_code(cmd
->arg1
);
1038 printf("skipto %u", cmd
->arg1
);
1042 printf("pipe %u", cmd
->arg1
);
1046 printf("queue %u", cmd
->arg1
);
1050 printf("divert %u", cmd
->arg1
);
1054 printf("tee %u", cmd
->arg1
);
1059 ipfw_insn_sa
*s
= (ipfw_insn_sa
*)cmd
;
1061 printf("fwd %s", inet_ntoa(s
->sa
.sin_addr
));
1063 printf(",%d", s
->sa
.sin_port
);
1067 case O_LOG
: /* O_LOG is printed last */
1068 logptr
= (ipfw_insn_log
*)cmd
;
1072 printf("** unrecognized action %d len %d",
1073 cmd
->opcode
, cmd
->len
);
1077 if (logptr
->max_log
> 0)
1078 printf(" log logamount %d", logptr
->max_log
);
1084 * then print the body.
1086 if (rule
->_pad
& 1) { /* empty rules before options */
1088 printf(" ip from any to any");
1089 flags
|= HAVE_IP
| HAVE_OPTIONS
;
1092 for (l
= rule
->act_ofs
, cmd
= rule
->cmd
;
1093 l
> 0 ; l
-= F_LEN(cmd
) , cmd
+= F_LEN(cmd
)) {
1095 ipfw_insn_u32
*cmd32
= (ipfw_insn_u32
*)cmd
;
1097 show_prerequisites(&flags
, 0, cmd
->opcode
);
1099 switch(cmd
->opcode
) {
1101 break; /* done already */
1104 break; /* no need to print anything here */
1107 ipfw_insn_mac
*m
= (ipfw_insn_mac
*)cmd
;
1109 if ((cmd
->len
& F_OR
) && !or_block
)
1111 if (cmd
->len
& F_NOT
)
1115 print_mac(m
->addr
, m
->mask
);
1116 print_mac(m
->addr
+ 6, m
->mask
+ 6);
1121 if ((cmd
->len
& F_OR
) && !or_block
)
1123 print_newports((ipfw_insn_u16
*)cmd
, IPPROTO_ETHERTYPE
,
1124 (flags
& HAVE_OPTIONS
) ? cmd
->opcode
: 0);
1125 flags
|= HAVE_MAC
| HAVE_MACTYPE
| HAVE_OPTIONS
;
1132 show_prerequisites(&flags
, HAVE_PROTO
, 0);
1133 if (!(flags
& HAVE_SRCIP
))
1135 if ((cmd
->len
& F_OR
) && !or_block
)
1137 print_ip((ipfw_insn_ip
*)cmd
,
1138 (flags
& HAVE_OPTIONS
) ? " src-ip" : "");
1139 flags
|= HAVE_SRCIP
;
1146 show_prerequisites(&flags
, HAVE_PROTO
|HAVE_SRCIP
, 0);
1147 if (!(flags
& HAVE_DSTIP
))
1149 if ((cmd
->len
& F_OR
) && !or_block
)
1151 print_ip((ipfw_insn_ip
*)cmd
,
1152 (flags
& HAVE_OPTIONS
) ? " dst-ip" : "");
1153 flags
|= HAVE_DSTIP
;
1157 show_prerequisites(&flags
, HAVE_IP
, 0);
1159 show_prerequisites(&flags
, HAVE_PROTO
|HAVE_SRCIP
, 0);
1160 if ((cmd
->len
& F_OR
) && !or_block
)
1162 print_newports((ipfw_insn_u16
*)cmd
, proto
,
1163 (flags
& HAVE_OPTIONS
) ? cmd
->opcode
: 0);
1167 struct protoent
*pe
;
1169 if ((cmd
->len
& F_OR
) && !or_block
)
1171 if (cmd
->len
& F_NOT
)
1174 pe
= getprotobynumber(cmd
->arg1
);
1175 if (flags
& HAVE_OPTIONS
)
1178 printf(" %s", pe
->p_name
);
1180 printf(" %u", cmd
->arg1
);
1182 flags
|= HAVE_PROTO
;
1185 default: /*options ... */
1186 show_prerequisites(&flags
, HAVE_IP
| HAVE_OPTIONS
, 0);
1187 if ((cmd
->len
& F_OR
) && !or_block
)
1189 if (cmd
->len
& F_NOT
&& cmd
->opcode
!= O_IN
)
1191 switch(cmd
->opcode
) {
1197 printf(cmd
->len
& F_NOT
? " out" : " in");
1207 ipfw_insn_if
*cmdif
= (ipfw_insn_if
*)cmd
;
1209 if (cmd
->opcode
== O_XMIT
)
1211 else if (cmd
->opcode
== O_RECV
)
1213 else /* if (cmd->opcode == O_VIA) */
1215 if (cmdif
->name
[0] == '\0')
1217 inet_ntoa(cmdif
->p
.ip
));
1218 else if (cmdif
->p
.unit
== -1)
1219 printf(" %s %s*", s
, cmdif
->name
);
1221 printf(" %s %s%d", s
, cmdif
->name
,
1227 if (F_LEN(cmd
) == 1)
1228 printf(" ipid %u", cmd
->arg1
);
1230 print_newports((ipfw_insn_u16
*)cmd
, 0,
1235 if (F_LEN(cmd
) == 1)
1236 printf(" ipttl %u", cmd
->arg1
);
1238 print_newports((ipfw_insn_u16
*)cmd
, 0,
1243 printf(" ipver %u", cmd
->arg1
);
1246 case O_IPPRECEDENCE
:
1247 printf(" ipprecedence %u", (cmd
->arg1
) >> 5 );
1251 if (F_LEN(cmd
) == 1)
1252 printf(" iplen %u", cmd
->arg1
);
1254 print_newports((ipfw_insn_u16
*)cmd
, 0,
1259 print_flags("ipoptions", cmd
, f_ipopts
);
1263 print_flags("iptos", cmd
, f_iptos
);
1267 print_icmptypes((ipfw_insn_u32
*)cmd
);
1271 printf(" established");
1275 print_flags("tcpflags", cmd
, f_tcpflags
);
1279 print_flags("tcpoptions", cmd
, f_tcpopts
);
1283 printf(" tcpwin %d", ntohs(cmd
->arg1
));
1287 printf(" tcpack %d", ntohl(cmd32
->d
[0]));
1291 printf(" tcpseq %d", ntohl(cmd32
->d
[0]));
1296 struct passwd
*pwd
= getpwuid(cmd32
->d
[0]);
1299 printf(" uid %s", pwd
->pw_name
);
1301 printf(" uid %u", cmd32
->d
[0]);
1307 struct group
*grp
= getgrgid(cmd32
->d
[0]);
1310 printf(" gid %s", grp
->gr_name
);
1312 printf(" gid %u", cmd32
->d
[0]);
1317 printf(" verrevpath");
1325 comment
= (char *)(cmd
+ 1);
1329 printf(" keep-state");
1334 struct _s_x
*p
= limit_masks
;
1335 ipfw_insn_limit
*c
= (ipfw_insn_limit
*)cmd
;
1336 uint8_t x
= c
->limit_mask
;
1337 char const *comma
= " ";
1340 for (; p
->x
!= 0 ; p
++)
1341 if ((x
& p
->x
) == p
->x
) {
1343 printf("%s%s", comma
, p
->s
);
1346 printf(" %d", c
->conn_limit
);
1351 printf(" [opcode %d len %d]",
1352 cmd
->opcode
, cmd
->len
);
1355 if (cmd
->len
& F_OR
) {
1358 } else if (or_block
) {
1363 show_prerequisites(&flags
, HAVE_IP
, 0);
1365 printf(" // %s", comment
);
1370 show_dyn_ipfw(ipfw_dyn_rule
*d
, int pcwidth
, int bcwidth
)
1372 struct protoent
*pe
;
1377 if (!d
->expire
&& !(d
->dyn_type
== O_LIMIT_PARENT
))
1380 bcopy(&d
->rule
, &rulenum
, sizeof(rulenum
));
1381 printf("%05d", rulenum
);
1382 if (pcwidth
>0 || bcwidth
>0)
1383 printf(" %*llu %*llu (%ds)", pcwidth
,
1384 align_uint64(&d
->pcnt
), bcwidth
,
1385 align_uint64(&d
->bcnt
), d
->expire
);
1386 switch (d
->dyn_type
) {
1387 case O_LIMIT_PARENT
:
1388 printf(" PARENT %d", d
->count
);
1393 case O_KEEP_STATE
: /* bidir, no mask */
1398 if ((pe
= getprotobynumber(d
->id
.proto
)) != NULL
)
1399 printf(" %s", pe
->p_name
);
1401 printf(" proto %u", d
->id
.proto
);
1403 a
.s_addr
= htonl(d
->id
.src_ip
);
1404 printf(" %s %d", inet_ntoa(a
), d
->id
.src_port
);
1406 a
.s_addr
= htonl(d
->id
.dst_ip
);
1407 printf(" <-> %s %d", inet_ntoa(a
), d
->id
.dst_port
);
1412 sort_q(const void *pa
, const void *pb
)
1414 int rev
= (do_sort
< 0);
1415 int field
= rev
? -do_sort
: do_sort
;
1417 const struct dn_flow_queue
*a
= pa
;
1418 const struct dn_flow_queue
*b
= pb
;
1422 res
= a
->len
- b
->len
;
1425 res
= a
->len_bytes
- b
->len_bytes
;
1428 case 3: /* tot pkts */
1429 res
= a
->tot_pkts
- b
->tot_pkts
;
1432 case 4: /* tot bytes */
1433 res
= a
->tot_bytes
- b
->tot_bytes
;
1440 return (int)(rev
? res
: -res
);
1444 list_queues(struct dn_flow_set
*fs
, struct dn_flow_queue
*q
)
1448 printf(" mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n",
1449 fs
->flow_mask
.proto
,
1450 fs
->flow_mask
.src_ip
, fs
->flow_mask
.src_port
,
1451 fs
->flow_mask
.dst_ip
, fs
->flow_mask
.dst_port
);
1452 if (fs
->rq_elements
== 0)
1455 printf("BKT Prot ___Source IP/port____ "
1456 "____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp\n");
1458 heapsort(q
, fs
->rq_elements
, sizeof *q
, sort_q
);
1459 for (l
= 0; l
< fs
->rq_elements
; l
++) {
1461 struct protoent
*pe
;
1463 ina
.s_addr
= htonl(q
[l
].id
.src_ip
);
1464 printf("%3d ", q
[l
].hash_slot
);
1465 pe
= getprotobynumber(q
[l
].id
.proto
);
1467 printf("%-4s ", pe
->p_name
);
1469 printf("%4u ", q
[l
].id
.proto
);
1470 printf("%15s/%-5d ",
1471 inet_ntoa(ina
), q
[l
].id
.src_port
);
1472 ina
.s_addr
= htonl(q
[l
].id
.dst_ip
);
1473 printf("%15s/%-5d ",
1474 inet_ntoa(ina
), q
[l
].id
.dst_port
);
1475 printf("%4qu %8qu %2u %4u %3u\n",
1476 q
[l
].tot_pkts
, q
[l
].tot_bytes
,
1477 q
[l
].len
, q
[l
].len_bytes
, q
[l
].drops
);
1479 printf(" S %20qd F %20qd\n",
1485 print_flowset_parms(struct dn_flow_set
*fs
, char *prefix
)
1490 char red
[90]; /* Display RED parameters */
1493 if (fs
->flags_fs
& DN_QSIZE_IS_BYTES
) {
1495 snprintf(qs
, sizeof(qs
), "%d KB", l
/ 1024);
1497 snprintf(qs
, sizeof(qs
), "%d B", l
);
1499 snprintf(qs
, sizeof(qs
), "%3d sl.", l
);
1501 snprintf(plr
, sizeof(plr
), "plr %f", 1.0 * fs
->plr
/ (double)(0x7fffffff));
1504 if (fs
->flags_fs
& DN_IS_RED
) /* RED parameters */
1505 snprintf(red
, sizeof(red
),
1506 "\n\t %cRED w_q %f min_th %d max_th %d max_p %f",
1507 (fs
->flags_fs
& DN_IS_GENTLE_RED
) ? 'G' : ' ',
1508 1.0 * fs
->w_q
/ (double)(1 << SCALE_RED
),
1509 SCALE_VAL(fs
->min_th
),
1510 SCALE_VAL(fs
->max_th
),
1511 1.0 * fs
->max_p
/ (double)(1 << SCALE_RED
));
1513 snprintf(red
, sizeof(red
), "droptail");
1515 printf("%s %s%s %d queues (%d buckets) %s\n",
1516 prefix
, qs
, plr
, fs
->rq_elements
, fs
->rq_size
, red
);
1520 list_pipes(void *data
, uint nbytes
, int ac
, char *av
[])
1524 struct dn_pipe
*p
= (struct dn_pipe
*) data
;
1525 struct dn_flow_set
*fs
;
1526 struct dn_flow_queue
*q
;
1530 rulenum
= strtoul(*av
++, NULL
, 10);
1533 for (; nbytes
>= sizeof *p
; p
= (struct dn_pipe
*)next
) {
1534 double b
= p
->bandwidth
;
1538 if (p
->next
.sle_next
!= (struct dn_pipe
*)DN_IS_PIPE
)
1539 break; /* done with pipes, now queues */
1542 * compute length, as pipe have variable size
1544 l
= sizeof(*p
) + p
->fs
.rq_elements
* sizeof(*q
);
1545 next
= (char *)p
+ l
;
1548 if (rulenum
!= 0 && rulenum
!= p
->pipe_nr
)
1552 * Print rate (or clocking interface)
1554 if (p
->if_name
[0] != '\0')
1555 snprintf(buf
, sizeof(buf
), "%s", p
->if_name
);
1557 snprintf(buf
, sizeof(buf
), "unlimited");
1558 else if (b
>= 1000000)
1559 snprintf(buf
, sizeof(buf
), "%7.3f Mbit/s", b
/1000000);
1561 snprintf(buf
, sizeof(buf
), "%7.3f Kbit/s", b
/1000);
1563 snprintf(buf
, sizeof(buf
), "%7.3f bit/s ", b
);
1565 snprintf(prefix
, sizeof(prefix
), "%05d: %s %4d ms ",
1566 p
->pipe_nr
, buf
, p
->delay
);
1567 print_flowset_parms(&(p
->fs
), prefix
);
1569 printf(" V %20qd\n", p
->V
>> MY_M
);
1571 q
= (struct dn_flow_queue
*)(p
+1);
1572 list_queues(&(p
->fs
), q
);
1574 for (fs
= next
; nbytes
>= sizeof *fs
; fs
= next
) {
1577 if (fs
->next
.sle_next
!= (struct dn_flow_set
*)DN_IS_QUEUE
)
1579 l
= sizeof(*fs
) + fs
->rq_elements
* sizeof(*q
);
1580 next
= (char *)fs
+ l
;
1582 q
= (struct dn_flow_queue
*)(fs
+1);
1583 snprintf(prefix
, sizeof(prefix
), "q%05d: weight %d pipe %d ",
1584 fs
->fs_nr
, fs
->weight
, fs
->parent_nr
);
1585 print_flowset_parms(fs
, prefix
);
1591 * This one handles all set-related commands
1592 * ipfw set { show | enable | disable }
1594 * ipfw set move X to Y
1595 * ipfw set move rule X to Y
1598 sets_handler(int ac
, char *av
[])
1600 uint32_t set_disable
, masks
[2];
1603 uint8_t cmd
, new_set
;
1609 errx(EX_USAGE
, "set needs command");
1610 if (!strncmp(*av
, "show", strlen(*av
)) ) {
1614 nbytes
= sizeof(struct ip_fw
);
1615 if ((data
= calloc(1, nbytes
)) == NULL
)
1616 err(EX_OSERR
, "calloc");
1618 if (do_cmd(IP_FW_GET
, data
, (uintptr_t)&nbytes
) < 0)
1619 err(EX_OSERR
, "getsockopt(IP_FW_GET)");
1620 bcopy(&((struct ip_fw
*)data
)->next_rule
,
1621 &set_disable
, sizeof(set_disable
));
1623 for (i
= 0, msg
= "disable" ; i
< RESVD_SET
; i
++)
1624 if ((set_disable
& (1<<i
))) {
1625 printf("%s %d", msg
, i
);
1628 msg
= (set_disable
) ? " enable" : "enable";
1629 for (i
= 0; i
< RESVD_SET
; i
++)
1630 if (!(set_disable
& (1<<i
))) {
1631 printf("%s %d", msg
, i
);
1635 } else if (!strncmp(*av
, "swap", strlen(*av
))) {
1639 errx(EX_USAGE
, "set swap needs 2 set numbers");
1640 rulenum
= atoi(av
[0]);
1641 new_set
= atoi(av
[1]);
1642 if (!isdigit(*(av
[0])) || rulenum
> RESVD_SET
)
1643 errx(EX_DATAERR
, "invalid set number %s", av
[0]);
1644 if (!isdigit(*(av
[1])) || new_set
> RESVD_SET
)
1645 errx(EX_DATAERR
, "invalid set number %s", av
[1]);
1646 masks
[0] = (4 << 24) | (new_set
<< 16) | (rulenum
);
1648 bzero(&rule
, sizeof(rule
));
1649 rule
.set_masks
[0] = masks
[0];
1651 i
= do_cmd(IP_FW_DEL
, &rule
, sizeof(rule
));
1652 } else if (!strncmp(*av
, "move", strlen(*av
))) {
1655 if (ac
&& !strncmp(*av
, "rule", strlen(*av
))) {
1660 if (ac
!= 3 || strncmp(av
[1], "to", strlen(*av
)))
1661 errx(EX_USAGE
, "syntax: set move [rule] X to Y");
1662 rulenum
= atoi(av
[0]);
1663 new_set
= atoi(av
[2]);
1664 if (!isdigit(*(av
[0])) || (cmd
== 3 && rulenum
> RESVD_SET
) ||
1665 (cmd
== 2 && rulenum
== 65535) )
1666 errx(EX_DATAERR
, "invalid source number %s", av
[0]);
1667 if (!isdigit(*(av
[2])) || new_set
> RESVD_SET
)
1668 errx(EX_DATAERR
, "invalid dest. set %s", av
[1]);
1669 masks
[0] = (cmd
<< 24) | (new_set
<< 16) | (rulenum
);
1671 bzero(&rule
, sizeof(rule
));
1672 rule
.set_masks
[0] = masks
[0];
1674 i
= do_cmd(IP_FW_DEL
, &rule
, sizeof(rule
));
1675 } else if (!strncmp(*av
, "disable", strlen(*av
)) ||
1676 !strncmp(*av
, "enable", strlen(*av
)) ) {
1677 int which
= !strncmp(*av
, "enable", strlen(*av
)) ? 1 : 0;
1681 masks
[0] = masks
[1] = 0;
1684 if (isdigit(**av
)) {
1686 if (i
< 0 || i
> RESVD_SET
)
1688 "invalid set number %d", i
);
1689 masks
[which
] |= (1<<i
);
1690 } else if (!strncmp(*av
, "disable", strlen(*av
)))
1692 else if (!strncmp(*av
, "enable", strlen(*av
)))
1696 "invalid set command %s", *av
);
1699 if ( (masks
[0] & masks
[1]) != 0 )
1701 "cannot enable and disable the same set");
1703 bzero(&rule
, sizeof(rule
));
1704 rule
.set_masks
[0] = masks
[0];
1705 rule
.set_masks
[1] = masks
[1];
1707 i
= do_cmd(IP_FW_DEL
, &rule
, sizeof(rule
));
1709 warn("set enable/disable: setsockopt(IP_FW_DEL)");
1711 errx(EX_USAGE
, "invalid set command %s", *av
);
1715 sysctl_handler(int ac
, char *av
[], int which
)
1721 warnx("missing keyword to enable/disable");
1722 } else if (strncmp(*av
, "firewall", strlen(*av
)) == 0) {
1723 sysctlbyname("net.inet.ip.fw.enable", NULL
, 0,
1724 &which
, sizeof(which
));
1725 } else if (strncmp(*av
, "one_pass", strlen(*av
)) == 0) {
1726 sysctlbyname("net.inet.ip.fw.one_pass", NULL
, 0,
1727 &which
, sizeof(which
));
1728 } else if (strncmp(*av
, "debug", strlen(*av
)) == 0) {
1729 sysctlbyname("net.inet.ip.fw.debug", NULL
, 0,
1730 &which
, sizeof(which
));
1731 } else if (strncmp(*av
, "verbose", strlen(*av
)) == 0) {
1732 sysctlbyname("net.inet.ip.fw.verbose", NULL
, 0,
1733 &which
, sizeof(which
));
1734 } else if (strncmp(*av
, "dyn_keepalive", strlen(*av
)) == 0) {
1735 sysctlbyname("net.inet.ip.fw.dyn_keepalive", NULL
, 0,
1736 &which
, sizeof(which
));
1738 warnx("unrecognize enable/disable keyword: %s", *av
);
1743 list(int ac
, char *av
[], int show_counters
)
1746 ipfw_dyn_rule
*dynrules
, *d
;
1748 #define NEXT(r) ((struct ip_fw *)((char *)r + RULESIZE(r)))
1751 int bcwidth
, n
, nbytes
, nstat
, ndyn
, pcwidth
, width
;
1752 int exitval
= EX_OK
;
1759 const int ocmd
= do_pipe
? IP_DUMMYNET_GET
: IP_FW_GET
;
1760 int nalloc
= 1024; /* start somewhere... */
1763 fprintf(stderr
, "Testing only, list disabled\n");
1770 /* get rules or pipes from kernel, resizing array as necessary */
1773 while (nbytes
>= nalloc
) {
1774 nalloc
= nalloc
* 2 + 200;
1776 if ((data
= realloc(data
, nbytes
)) == NULL
)
1777 err(EX_OSERR
, "realloc");
1779 if (do_cmd(ocmd
, data
, (uintptr_t)&nbytes
) < 0)
1780 err(EX_OSERR
, "getsockopt(IP_%s_GET)",
1781 do_pipe
? "DUMMYNET" : "FW");
1785 list_pipes(data
, nbytes
, ac
, av
);
1790 * Count static rules. They have variable size so we
1791 * need to scan the list to count them.
1793 for (nstat
= 1, r
= data
, lim
= (char *)data
+ nbytes
;
1794 r
->rulenum
< 65535 && (char *)r
< lim
;
1795 ++nstat
, r
= NEXT(r
) )
1799 * Count dynamic rules. This is easier as they have
1803 dynrules
= (ipfw_dyn_rule
*)r
;
1804 n
= (char *)r
- (char *)data
;
1805 ndyn
= (nbytes
- n
) / sizeof *dynrules
;
1807 /* if showing stats, figure out column widths ahead of time */
1808 bcwidth
= pcwidth
= 0;
1809 if (show_counters
) {
1810 for (n
= 0, r
= data
; n
< nstat
; n
++, r
= NEXT(r
)) {
1811 /* packet counter */
1812 width
= snprintf(NULL
, 0, "%llu",
1813 align_uint64(&r
->pcnt
));
1814 if (width
> pcwidth
)
1818 width
= snprintf(NULL
, 0, "%llu",
1819 align_uint64(&r
->bcnt
));
1820 if (width
> bcwidth
)
1824 if (do_dynamic
&& ndyn
) {
1825 for (n
= 0, d
= dynrules
; n
< ndyn
; n
++, d
++) {
1826 width
= snprintf(NULL
, 0, "%llu",
1827 align_uint64(&d
->pcnt
));
1828 if (width
> pcwidth
)
1831 width
= snprintf(NULL
, 0, "%llu",
1832 align_uint64(&d
->bcnt
));
1833 if (width
> bcwidth
)
1837 /* if no rule numbers were specified, list all rules */
1839 for (n
= 0, r
= data
; n
< nstat
; n
++, r
= NEXT(r
) )
1840 show_ipfw(r
, pcwidth
, bcwidth
);
1842 if (do_dynamic
&& ndyn
) {
1843 printf("## Dynamic rules (%d):\n", ndyn
);
1844 for (n
= 0, d
= dynrules
; n
< ndyn
; n
++, d
++)
1845 show_dyn_ipfw(d
, pcwidth
, bcwidth
);
1850 /* display specific rules requested on command line */
1852 for (lac
= ac
, lav
= av
; lac
!= 0; lac
--) {
1853 /* convert command line rule # */
1854 last
= rnum
= strtoul(*lav
++, &endptr
, 10);
1856 last
= strtoul(endptr
+1, &endptr
, 10);
1859 warnx("invalid rule number: %s", *(lav
- 1));
1862 for (n
= seen
= 0, r
= data
; n
< nstat
; n
++, r
= NEXT(r
) ) {
1863 if (r
->rulenum
> last
)
1865 if (r
->rulenum
>= rnum
&& r
->rulenum
<= last
) {
1866 show_ipfw(r
, pcwidth
, bcwidth
);
1871 /* give precedence to other error(s) */
1872 if (exitval
== EX_OK
)
1873 exitval
= EX_UNAVAILABLE
;
1874 warnx("rule %lu does not exist", rnum
);
1878 if (do_dynamic
&& ndyn
) {
1879 printf("## Dynamic rules:\n");
1880 for (lac
= ac
, lav
= av
; lac
!= 0; lac
--) {
1881 rnum
= strtoul(*lav
++, &endptr
, 10);
1883 last
= strtoul(endptr
+1, &endptr
, 10);
1885 /* already warned */
1887 for (n
= 0, d
= dynrules
; n
< ndyn
; n
++, d
++) {
1890 bcopy(&d
->rule
, &rulenum
, sizeof(rulenum
));
1893 if (r
->rulenum
>= rnum
&& r
->rulenum
<= last
)
1894 show_dyn_ipfw(d
, pcwidth
, bcwidth
);
1904 if (exitval
!= EX_OK
)
1912 fprintf(stderr
, "usage: ipfw [options]\n"
1913 "do \"ipfw -h\" or see ipfw manpage for details\n"
1922 "ipfw syntax summary (but please do read the ipfw(8) manpage):\n"
1923 "ipfw [-acdeftTnNpqS] <command> where <command> is one of:\n"
1924 "add [num] [set N] [prob x] RULE-BODY\n"
1925 "{pipe|queue} N config PIPE-BODY\n"
1926 "[pipe|queue] {zero|delete|show} [N{,N}]\n"
1927 "set [disable N... enable N...] | move [rule] X to Y | swap X Y | show\n"
1929 "RULE-BODY: check-state [LOG] | ACTION [LOG] ADDR [OPTION_LIST]\n"
1930 "ACTION: check-state | allow | count | deny | reject | skipto N |\n"
1931 " {divert|tee} PORT | forward ADDR | pipe N | queue N\n"
1932 "ADDR: [ MAC dst src ether_type ] \n"
1933 " [ from IPADDR [ PORT ] to IPADDR [ PORTLIST ] ]\n"
1934 "IPADDR: [not] { any | me | ip/bits{x,y,z} | IPLIST }\n"
1935 "IPLIST: { ip | ip/bits | ip:mask }[,IPLIST]\n"
1936 "OPTION_LIST: OPTION [OPTION_LIST]\n"
1937 "OPTION: bridged | {dst-ip|src-ip} ADDR | {dst-port|src-port} LIST |\n"
1938 " estab | frag | {gid|uid} N | icmptypes LIST | in | out | ipid LIST |\n"
1939 " iplen LIST | ipoptions SPEC | ipprecedence | ipsec | iptos SPEC |\n"
1940 " ipttl LIST | ipversion VER | keep-state | layer2 | limit ... |\n"
1941 " mac ... | mac-type LIST | proto LIST | {recv|xmit|via} {IF|IPADDR} |\n"
1942 " setup | {tcpack|tcpseq|tcpwin} NN | tcpflags SPEC | tcpoptions SPEC |\n"
1950 lookup_host (char *host
, struct in_addr
*ipaddr
)
1954 if (!inet_aton(host
, ipaddr
)) {
1955 if ((he
= gethostbyname(host
)) == NULL
)
1957 *ipaddr
= *(struct in_addr
*)he
->h_addr_list
[0];
1963 * fills the addr and mask fields in the instruction as appropriate from av.
1964 * Update length as appropriate.
1965 * The following formats are allowed:
1966 * any matches any IP. Actually returns an empty instruction.
1967 * me returns O_IP_*_ME
1968 * 1.2.3.4 single IP address
1969 * 1.2.3.4:5.6.7.8 address:mask
1970 * 1.2.3.4/24 address/mask
1971 * 1.2.3.4/26{1,6,5,4,23} set of addresses in a subnet
1972 * We can have multiple comma-separated address/mask entries.
1975 fill_ip(ipfw_insn_ip
*cmd
, char *av
)
1978 uint32_t *d
= ((ipfw_insn_u32
*)cmd
)->d
;
1980 cmd
->o
.len
&= ~F_LEN_MASK
; /* zero len */
1982 if (!strncmp(av
, "any", strlen(av
)))
1985 if (!strncmp(av
, "me", strlen(av
))) {
1986 cmd
->o
.len
|= F_INSN_SIZE(ipfw_insn
);
1992 * After the address we can have '/' or ':' indicating a mask,
1993 * ',' indicating another address follows, '{' indicating a
1994 * set of addresses of unspecified size.
1996 char *p
= strpbrk(av
, "/:,{");
2006 if (lookup_host(av
, (struct in_addr
*)&d
[0]) != 0)
2007 errx(EX_NOHOST
, "hostname ``%s'' unknown", av
);
2010 if (!inet_aton(p
, (struct in_addr
*)&d
[1]))
2011 errx(EX_DATAERR
, "bad netmask ``%s''", p
);
2016 d
[1] = htonl(0); /* mask */
2017 else if (masklen
> 32)
2018 errx(EX_DATAERR
, "bad width ``%s''", p
);
2020 d
[1] = htonl(~0 << (32 - masklen
));
2022 case '{': /* no mask, assume /24 and put back the '{' */
2023 d
[1] = htonl(~0 << (32 - 24));
2027 case ',': /* single address plus continuation */
2030 case 0: /* initialization value */
2032 d
[1] = htonl(~0); /* force /32 */
2035 d
[0] &= d
[1]; /* mask base address with mask */
2036 /* find next separator */
2038 p
= strpbrk(p
, ",{");
2039 if (p
&& *p
== '{') {
2041 * We have a set of addresses. They are stored as follows:
2042 * arg1 is the set size (powers of 2, 2..256)
2043 * addr is the base address IN HOST FORMAT
2044 * mask.. is an array of arg1 bits (rounded up to
2045 * the next multiple of 32) with bits set
2046 * for each host in the map.
2048 uint32_t *map
= (uint32_t *)&cmd
->mask
;
2050 int i
= contigmask((uint8_t *)&(d
[1]), 32);
2053 errx(EX_DATAERR
, "address set cannot be in a list");
2054 if (i
< 24 || i
> 31)
2055 errx(EX_DATAERR
, "invalid set with mask %d", i
);
2056 cmd
->o
.arg1
= 1<<(32-i
); /* map length */
2057 d
[0] = ntohl(d
[0]); /* base addr in host format */
2058 cmd
->o
.opcode
= O_IP_DST_SET
; /* default */
2059 cmd
->o
.len
|= F_INSN_SIZE(ipfw_insn_u32
) + (cmd
->o
.arg1
+31)/32;
2060 for (i
= 0; i
< (cmd
->o
.arg1
+31)/32 ; i
++)
2061 map
[i
] = 0; /* clear map */
2065 high
= low
+ cmd
->o
.arg1
- 1;
2067 * Here, i stores the previous value when we specify a range
2068 * of addresses within a mask, e.g. 45-63. i = -1 means we
2069 * have no previous value.
2071 i
= -1; /* previous value in a range */
2072 while (isdigit(*av
)) {
2074 int a
= strtol(av
, &s
, 0);
2076 if (s
== av
) { /* no parameter */
2078 errx(EX_DATAERR
, "set not closed");
2080 errx(EX_DATAERR
, "incomplete range %d-", i
);
2083 if (a
< low
|| a
> high
)
2084 errx(EX_DATAERR
, "addr %d out of range [%d-%d]",
2087 if (i
== -1) /* no previous in range */
2089 else { /* check that range is valid */
2091 errx(EX_DATAERR
, "invalid range %d-%d",
2094 errx(EX_DATAERR
, "double '-' in range");
2097 map
[i
/32] |= 1<<(i
& 31);
2108 if (av
) /* then *av must be a ',' */
2111 /* Check this entry */
2112 if (d
[1] == 0) { /* "any", specified as x.x.x.x/0 */
2114 * 'any' turns the entire list into a NOP.
2115 * 'not any' never matches, so it is removed from the
2116 * list unless it is the only item, in which case we
2119 if (cmd
->o
.len
& F_NOT
) { /* "not any" never matches */
2120 if (av
== NULL
&& len
== 0) /* only this entry */
2121 errx(EX_DATAERR
, "not any never matches");
2123 /* else do nothing and return */
2126 /* A single IP can be stored in an optimized format */
2127 if (d
[1] == IP_MASK_ALL
&& av
== NULL
&& len
== 0) {
2128 cmd
->o
.len
|= F_INSN_SIZE(ipfw_insn_u32
);
2131 len
+= 2; /* two words... */
2134 cmd
->o
.len
|= len
+1;
2139 * helper function to process a set of flags and set bits in the
2140 * appropriate masks.
2143 fill_flags(ipfw_insn
*cmd
, enum ipfw_opcodes opcode
,
2144 struct _s_x
*flags
, char *p
)
2146 uint8_t set
=0, clear
=0;
2149 char *q
; /* points to the separator */
2151 uint8_t *which
; /* mask we are working on */
2161 val
= match_token(flags
, p
);
2163 errx(EX_DATAERR
, "invalid flag %s", p
);
2164 *which
|= (uint8_t)val
;
2167 cmd
->opcode
= opcode
;
2168 cmd
->len
= (cmd
->len
& (F_NOT
| F_OR
)) | 1;
2169 cmd
->arg1
= (set
& 0xff) | ( (clear
& 0xff) << 8);
2174 delete(int ac
, char *av
[])
2179 int exitval
= EX_OK
;
2182 memset(&p
, 0, sizeof p
);
2185 if (ac
> 0 && !strncmp(*av
, "set", strlen(*av
))) {
2186 do_set
= 1; /* delete set */
2191 while (ac
&& isdigit(**av
)) {
2192 i
= atoi(*av
); av
++; ac
--;
2198 i
= do_cmd(IP_DUMMYNET_DEL
, &p
, sizeof p
);
2201 warn("rule %u: setsockopt(IP_DUMMYNET_DEL)",
2202 do_pipe
== 1 ? p
.pipe_nr
: p
.fs
.fs_nr
);
2205 bzero(&rule
, sizeof(rule
));
2207 rule
.set_masks
[0] = (i
& 0xffff) | (do_set
<< 24);
2212 i
= do_cmd(IP_FW_DEL
, &rule
, sizeof(rule
));
2214 exitval
= EX_UNAVAILABLE
;
2215 warn("rule %u: setsockopt(IP_FW_DEL)",
2220 if (exitval
!= EX_OK
)
2226 * fill the interface structure. We do not check the name as we can
2227 * create interfaces dynamically, so checking them at insert time
2228 * makes relatively little sense.
2229 * A '*' following the name means any unit.
2232 fill_iface(ipfw_insn_if
*cmd
, char *arg
)
2234 cmd
->name
[0] = '\0';
2235 cmd
->o
.len
|= F_INSN_SIZE(ipfw_insn_if
);
2237 /* Parse the interface or address */
2238 if (!strcmp(arg
, "any"))
2239 cmd
->o
.len
= 0; /* effectively ignore this command */
2240 else if (!isdigit(*arg
)) {
2243 strncpy(cmd
->name
, arg
, sizeof(cmd
->name
));
2244 cmd
->name
[sizeof(cmd
->name
) - 1] = '\0';
2245 /* find first digit or wildcard */
2246 for (q
= cmd
->name
; *q
&& !isdigit(*q
) && *q
!= '*'; q
++)
2248 cmd
->p
.unit
= (*q
== '*') ? -1 : atoi(q
);
2250 } else if (!inet_aton(arg
, &cmd
->p
.ip
))
2251 errx(EX_DATAERR
, "bad ip address ``%s''", arg
);
2255 * the following macro returns an error message if we run out of
2258 #define NEED1(msg) {if (!ac) errx(EX_USAGE, msg);}
2261 config_pipe(int ac
, char **av
)
2269 memset(&p
, 0, sizeof p
);
2273 if (ac
&& isdigit(**av
)) {
2274 i
= atoi(*av
); av
++; ac
--;
2282 int tok
= match_token(dummynet_params
, *av
);
2287 p
.fs
.flags_fs
|= DN_NOERROR
;
2291 NEED1("plr needs argument 0..1\n");
2292 d
= strtod(av
[0], NULL
);
2297 p
.fs
.plr
= (int)(d
*0x7fffffff);
2302 NEED1("queue needs queue size\n");
2304 p
.fs
.qsize
= strtoul(av
[0], &end
, 0);
2305 if (*end
== 'K' || *end
== 'k') {
2306 p
.fs
.flags_fs
|= DN_QSIZE_IS_BYTES
;
2308 } else if (*end
== 'B' || !strncmp(end
, "by", 2)) {
2309 p
.fs
.flags_fs
|= DN_QSIZE_IS_BYTES
;
2315 NEED1("buckets needs argument\n");
2316 p
.fs
.rq_size
= strtoul(av
[0], NULL
, 0);
2321 NEED1("mask needs mask specifier\n");
2323 * per-flow queue, mask is dst_ip, dst_port,
2324 * src_ip, src_port, proto measured in bits
2328 p
.fs
.flow_mask
.dst_ip
= 0;
2329 p
.fs
.flow_mask
.src_ip
= 0;
2330 p
.fs
.flow_mask
.dst_port
= 0;
2331 p
.fs
.flow_mask
.src_port
= 0;
2332 p
.fs
.flow_mask
.proto
= 0;
2336 uint32_t *p32
= NULL
;
2337 uint16_t *p16
= NULL
;
2339 tok
= match_token(dummynet_params
, *av
);
2344 * special case, all bits significant
2346 p
.fs
.flow_mask
.dst_ip
= ~0;
2347 p
.fs
.flow_mask
.src_ip
= ~0;
2348 p
.fs
.flow_mask
.dst_port
= ~0;
2349 p
.fs
.flow_mask
.src_port
= ~0;
2350 p
.fs
.flow_mask
.proto
= ~0;
2351 p
.fs
.flags_fs
|= DN_HAVE_FLOW_MASK
;
2355 p32
= &p
.fs
.flow_mask
.dst_ip
;
2359 p32
= &p
.fs
.flow_mask
.src_ip
;
2363 p16
= &p
.fs
.flow_mask
.dst_port
;
2367 p16
= &p
.fs
.flow_mask
.src_port
;
2374 ac
++; av
--; /* backtrack */
2378 errx(EX_USAGE
, "mask: value missing");
2379 if (*av
[0] == '/') {
2380 a
= strtoul(av
[0]+1, &end
, 0);
2381 a
= (a
== 32) ? ~0 : (1 << a
) - 1;
2383 a
= strtoul(av
[0], &end
, 0);
2386 else if (p16
!= NULL
) {
2389 "mask: must be 16 bit");
2394 "mask: must be 8 bit");
2395 p
.fs
.flow_mask
.proto
= (uint8_t)a
;
2398 p
.fs
.flags_fs
|= DN_HAVE_FLOW_MASK
;
2400 } /* end while, config masks */
2406 NEED1("red/gred needs w_q/min_th/max_th/max_p\n");
2407 p
.fs
.flags_fs
|= DN_IS_RED
;
2408 if (tok
== TOK_GRED
)
2409 p
.fs
.flags_fs
|= DN_IS_GENTLE_RED
;
2411 * the format for parameters is w_q/min_th/max_th/max_p
2413 if ((end
= strsep(&av
[0], "/"))) {
2414 double w_q
= strtod(end
, NULL
);
2415 if (w_q
> 1 || w_q
<= 0)
2416 errx(EX_DATAERR
, "0 < w_q <= 1");
2417 p
.fs
.w_q
= (int) (w_q
* (1 << SCALE_RED
));
2419 if ((end
= strsep(&av
[0], "/"))) {
2420 p
.fs
.min_th
= strtoul(end
, &end
, 0);
2421 if (*end
== 'K' || *end
== 'k')
2422 p
.fs
.min_th
*= 1024;
2424 if ((end
= strsep(&av
[0], "/"))) {
2425 p
.fs
.max_th
= strtoul(end
, &end
, 0);
2426 if (*end
== 'K' || *end
== 'k')
2427 p
.fs
.max_th
*= 1024;
2429 if ((end
= strsep(&av
[0], "/"))) {
2430 double max_p
= strtod(end
, NULL
);
2431 if (max_p
> 1 || max_p
<= 0)
2432 errx(EX_DATAERR
, "0 < max_p <= 1");
2433 p
.fs
.max_p
= (int)(max_p
* (1 << SCALE_RED
));
2439 p
.fs
.flags_fs
&= ~(DN_IS_RED
|DN_IS_GENTLE_RED
);
2443 NEED1("bw needs bandwidth or interface\n");
2445 errx(EX_DATAERR
, "bandwidth only valid for pipes");
2447 * set clocking interface or bandwidth value
2449 if (av
[0][0] >= 'a' && av
[0][0] <= 'z') {
2450 int l
= sizeof(p
.if_name
)-1;
2451 /* interface name */
2452 strncpy(p
.if_name
, av
[0], l
);
2453 p
.if_name
[l
] = '\0';
2456 p
.if_name
[0] = '\0';
2457 p
.bandwidth
= strtoul(av
[0], &end
, 0);
2458 if (*end
== 'K' || *end
== 'k') {
2460 p
.bandwidth
*= 1000;
2461 } else if (*end
== 'M') {
2463 p
.bandwidth
*= 1000000;
2465 if (*end
== 'B' || !strncmp(end
, "by", 2))
2467 if (p
.bandwidth
< 0)
2468 errx(EX_DATAERR
, "bandwidth too large");
2475 errx(EX_DATAERR
, "delay only valid for pipes");
2476 NEED1("delay needs argument 0..10000ms\n");
2477 p
.delay
= strtoul(av
[0], NULL
, 0);
2483 errx(EX_DATAERR
,"weight only valid for queues");
2484 NEED1("weight needs argument 0..100\n");
2485 p
.fs
.weight
= strtoul(av
[0], &end
, 0);
2491 errx(EX_DATAERR
,"pipe only valid for queues");
2492 NEED1("pipe needs pipe_number\n");
2493 p
.fs
.parent_nr
= strtoul(av
[0], &end
, 0);
2498 errx(EX_DATAERR
, "unrecognised option ``%s''", *(--av
));
2503 errx(EX_DATAERR
, "pipe_nr must be > 0");
2504 if (p
.delay
> 10000)
2505 errx(EX_DATAERR
, "delay must be < 10000");
2506 } else { /* do_pipe == 2, queue */
2507 if (p
.fs
.parent_nr
== 0)
2508 errx(EX_DATAERR
, "pipe must be > 0");
2509 if (p
.fs
.weight
>100)
2510 errx(EX_DATAERR
, "weight must be <= 100");
2512 if (p
.fs
.flags_fs
& DN_QSIZE_IS_BYTES
) {
2513 if (p
.fs
.qsize
> 1024*1024)
2514 errx(EX_DATAERR
, "queue size must be < 1MB");
2516 if (p
.fs
.qsize
> 100)
2517 errx(EX_DATAERR
, "2 <= queue size <= 100");
2519 if (p
.fs
.flags_fs
& DN_IS_RED
) {
2521 int lookup_depth
, avg_pkt_size
;
2522 double s
, idle
, weight
, w_q
;
2523 struct clockinfo ck
;
2526 if (p
.fs
.min_th
>= p
.fs
.max_th
)
2527 errx(EX_DATAERR
, "min_th %d must be < than max_th %d",
2528 p
.fs
.min_th
, p
.fs
.max_th
);
2529 if (p
.fs
.max_th
== 0)
2530 errx(EX_DATAERR
, "max_th must be > 0");
2533 if (sysctlbyname("net.inet.ip.dummynet.red_lookup_depth",
2534 &lookup_depth
, &len
, NULL
, 0) == -1)
2536 errx(1, "sysctlbyname(\"%s\")",
2537 "net.inet.ip.dummynet.red_lookup_depth");
2538 if (lookup_depth
== 0)
2539 errx(EX_DATAERR
, "net.inet.ip.dummynet.red_lookup_depth"
2540 " must be greater than zero");
2543 if (sysctlbyname("net.inet.ip.dummynet.red_avg_pkt_size",
2544 &avg_pkt_size
, &len
, NULL
, 0) == -1)
2546 errx(1, "sysctlbyname(\"%s\")",
2547 "net.inet.ip.dummynet.red_avg_pkt_size");
2548 if (avg_pkt_size
== 0)
2550 "net.inet.ip.dummynet.red_avg_pkt_size must"
2551 " be greater than zero");
2553 len
= sizeof(struct clockinfo
);
2554 if (sysctlbyname("kern.clockrate", &ck
, &len
, NULL
, 0) == -1)
2555 errx(1, "sysctlbyname(\"%s\")", "kern.clockrate");
2558 * Ticks needed for sending a medium-sized packet.
2559 * Unfortunately, when we are configuring a WF2Q+ queue, we
2560 * do not have bandwidth information, because that is stored
2561 * in the parent pipe, and also we have multiple queues
2562 * competing for it. So we set s=0, which is not very
2563 * correct. But on the other hand, why do we want RED with
2566 if (p
.bandwidth
==0) /* this is a WF2Q+ queue */
2569 s
= ck
.hz
* avg_pkt_size
* 8 / p
.bandwidth
;
2572 * max idle time (in ticks) before avg queue size becomes 0.
2573 * NOTA: (3/w_q) is approx the value x so that
2574 * (1-w_q)^x < 10^-3.
2576 w_q
= ((double)p
.fs
.w_q
) / (1 << SCALE_RED
);
2577 idle
= s
* 3. / w_q
;
2578 p
.fs
.lookup_step
= (int)idle
/ lookup_depth
;
2579 if (!p
.fs
.lookup_step
)
2580 p
.fs
.lookup_step
= 1;
2582 for (t
= p
.fs
.lookup_step
; t
> 0; --t
)
2584 p
.fs
.lookup_weight
= (int)(weight
* (1 << SCALE_RED
));
2586 i
= do_cmd(IP_DUMMYNET_CONFIGURE
, &p
, sizeof p
);
2588 err(1, "setsockopt(%s)", "IP_DUMMYNET_CONFIGURE");
2592 get_mac_addr_mask(char *p
, uint8_t *addr
, uint8_t *mask
)
2597 addr
[i
] = mask
[i
] = 0;
2598 if (!strcmp(p
, "any"))
2601 for (i
=0; *p
&& i
<6;i
++, p
++) {
2602 addr
[i
] = strtol(p
, &p
, 16);
2603 if (*p
!= ':') /* we start with the mask */
2606 if (*p
== '/') { /* mask len */
2607 l
= strtol(p
+1, &p
, 0);
2608 for (i
=0; l
>0; l
-=8, i
++)
2609 mask
[i
] = (l
>=8) ? 0xff : (~0) << (8-l
);
2610 } else if (*p
== '&') { /* mask */
2611 for (i
=0, p
++; *p
&& i
<6;i
++, p
++) {
2612 mask
[i
] = strtol(p
, &p
, 16);
2616 } else if (*p
== '\0') {
2625 * helper function, updates the pointer to cmd with the length
2626 * of the current command, and also cleans up the first word of
2627 * the new command in case it has been clobbered before.
2630 next_cmd(ipfw_insn
*cmd
)
2633 bzero(cmd
, sizeof(*cmd
));
2638 * Takes arguments and copies them into a comment
2641 fill_comment(ipfw_insn
*cmd
, int ac
, char **av
)
2644 char *p
= (char *)(cmd
+ 1);
2646 cmd
->opcode
= O_NOP
;
2647 cmd
->len
= (cmd
->len
& (F_NOT
| F_OR
));
2649 /* Compute length of comment string. */
2650 for (i
= 0, l
= 0; i
< ac
; i
++)
2651 l
+= strlen(av
[i
]) + 1;
2656 "comment too long (max 80 chars)");
2658 cmd
->len
= (cmd
->len
& (F_NOT
| F_OR
)) | l
;
2659 for (i
= 0; i
< ac
; i
++) {
2660 /* length being checked above (max 80 chars) */
2661 strlcpy(p
, av
[i
], 80);
2669 * A function to fill simple commands of size 1.
2670 * Existing flags are preserved.
2673 fill_cmd(ipfw_insn
*cmd
, enum ipfw_opcodes opcode
, int flags
, uint16_t arg
)
2675 cmd
->opcode
= opcode
;
2676 cmd
->len
= ((cmd
->len
| flags
) & (F_NOT
| F_OR
)) | 1;
2681 * Fetch and add the MAC address and type, with masks. This generates one or
2682 * two microinstructions, and returns the pointer to the last one.
2685 add_mac(ipfw_insn
*cmd
, int ac
, char *av
[])
2690 errx(EX_DATAERR
, "MAC dst src");
2692 cmd
->opcode
= O_MACADDR2
;
2693 cmd
->len
= (cmd
->len
& (F_NOT
| F_OR
)) | F_INSN_SIZE(ipfw_insn_mac
);
2695 mac
= (ipfw_insn_mac
*)cmd
;
2696 get_mac_addr_mask(av
[0], mac
->addr
, mac
->mask
); /* dst */
2697 get_mac_addr_mask(av
[1], &(mac
->addr
[6]), &(mac
->mask
[6])); /* src */
2702 add_mactype(ipfw_insn
*cmd
, int ac
, char *av
)
2705 errx(EX_DATAERR
, "missing MAC type");
2706 if (strcmp(av
, "any") != 0) { /* we have a non-null type */
2707 fill_newports((ipfw_insn_u16
*)cmd
, av
, IPPROTO_ETHERTYPE
);
2708 cmd
->opcode
= O_MAC_TYPE
;
2715 add_proto(ipfw_insn
*cmd
, char *av
)
2717 struct protoent
*pe
;
2720 if (!strncmp(av
, "all", strlen(av
)))
2721 ; /* same as "ip" */
2722 else if ((proto
= atoi(av
)) > 0)
2724 else if ((pe
= getprotobyname(av
)) != NULL
)
2725 proto
= pe
->p_proto
;
2728 if (proto
!= IPPROTO_IP
)
2729 fill_cmd(cmd
, O_PROTO
, 0, proto
);
2734 add_srcip(ipfw_insn
*cmd
, char *av
)
2736 fill_ip((ipfw_insn_ip
*)cmd
, av
);
2737 if (cmd
->opcode
== O_IP_DST_SET
) /* set */
2738 cmd
->opcode
= O_IP_SRC_SET
;
2739 else if (F_LEN(cmd
) == F_INSN_SIZE(ipfw_insn
)) /* me */
2740 cmd
->opcode
= O_IP_SRC_ME
;
2741 else if (F_LEN(cmd
) == F_INSN_SIZE(ipfw_insn_u32
)) /* one IP */
2742 cmd
->opcode
= O_IP_SRC
;
2743 else /* addr/mask */
2744 cmd
->opcode
= O_IP_SRC_MASK
;
2749 add_dstip(ipfw_insn
*cmd
, char *av
)
2751 fill_ip((ipfw_insn_ip
*)cmd
, av
);
2752 if (cmd
->opcode
== O_IP_DST_SET
) /* set */
2754 else if (F_LEN(cmd
) == F_INSN_SIZE(ipfw_insn
)) /* me */
2755 cmd
->opcode
= O_IP_DST_ME
;
2756 else if (F_LEN(cmd
) == F_INSN_SIZE(ipfw_insn_u32
)) /* one IP */
2757 cmd
->opcode
= O_IP_DST
;
2758 else /* addr/mask */
2759 cmd
->opcode
= O_IP_DST_MASK
;
2764 add_ports(ipfw_insn
*cmd
, char *av
, u_char proto
, int opcode
)
2766 if (!strncmp(av
, "any", strlen(av
))) {
2768 } else if (fill_newports((ipfw_insn_u16
*)cmd
, av
, proto
)) {
2769 /* XXX todo: check that we have a protocol with ports */
2770 cmd
->opcode
= opcode
;
2777 * Parse arguments and assemble the microinstructions which make up a rule.
2778 * Rules are added into the 'rulebuf' and then copied in the correct order
2779 * into the actual rule.
2781 * The syntax for a rule starts with the action, followed by an
2782 * optional log action, and the various match patterns.
2783 * In the assembled microcode, the first opcode must be an O_PROBE_STATE
2784 * (generated if the rule includes a keep-state option), then the
2785 * various match patterns, the "log" action, and the actual action.
2789 add(int ac
, char *av
[])
2792 * rules are added into the 'rulebuf' and then copied in
2793 * the correct order into the actual rule.
2794 * Some things that need to go out of order (prob, action etc.)
2797 static uint32_t rulebuf
[255], actbuf
[255], cmdbuf
[255];
2799 ipfw_insn
*src
, *dst
, *cmd
, *action
, *prev
=NULL
;
2800 ipfw_insn
*first_cmd
; /* first match pattern */
2805 * various flags used to record that we entered some fields.
2807 ipfw_insn
*have_state
= NULL
; /* check-state or keep-state */
2811 int open_par
= 0; /* open parenthesis ( */
2813 /* proto is here because it is used to fetch ports */
2814 u_char proto
= IPPROTO_IP
; /* default protocol */
2816 double match_prob
= 1; /* match probability, default is always match */
2818 bzero(actbuf
, sizeof(actbuf
)); /* actions go here */
2819 bzero(cmdbuf
, sizeof(cmdbuf
));
2820 bzero(rulebuf
, sizeof(rulebuf
));
2822 rule
= (struct ip_fw
*)rulebuf
;
2823 cmd
= (ipfw_insn
*)cmdbuf
;
2824 action
= (ipfw_insn
*)actbuf
;
2828 /* [rule N] -- Rule number optional */
2829 if (ac
&& isdigit(**av
)) {
2830 rule
->rulenum
= atoi(*av
);
2835 /* [set N] -- set number (0..RESVD_SET), optional */
2836 if (ac
> 1 && !strncmp(*av
, "set", strlen(*av
))) {
2837 int set
= strtoul(av
[1], NULL
, 10);
2838 if (set
< 0 || set
> RESVD_SET
)
2839 errx(EX_DATAERR
, "illegal set %s", av
[1]);
2844 /* [prob D] -- match probability, optional */
2845 if (ac
> 1 && !strncmp(*av
, "prob", strlen(*av
))) {
2846 match_prob
= strtod(av
[1], NULL
);
2848 if (match_prob
<= 0 || match_prob
> 1)
2849 errx(EX_DATAERR
, "illegal match prob. %s", av
[1]);
2853 /* action -- mandatory */
2854 NEED1("missing action");
2855 i
= match_token(rule_actions
, *av
);
2857 action
->len
= 1; /* default */
2859 case TOK_CHECKSTATE
:
2860 have_state
= action
;
2861 action
->opcode
= O_CHECK_STATE
;
2865 action
->opcode
= O_ACCEPT
;
2869 action
->opcode
= O_DENY
;
2874 action
->opcode
= O_REJECT
;
2875 action
->arg1
= ICMP_UNREACH_HOST
;
2879 action
->opcode
= O_REJECT
;
2880 action
->arg1
= ICMP_REJECT_RST
;
2884 action
->opcode
= O_REJECT
;
2885 NEED1("missing reject code");
2886 fill_reject_code(&action
->arg1
, *av
);
2891 action
->opcode
= O_COUNT
;
2896 action
->len
= F_INSN_SIZE(ipfw_insn_pipe
);
2899 action
->opcode
= O_QUEUE
;
2900 else if (i
== TOK_PIPE
)
2901 action
->opcode
= O_PIPE
;
2902 else if (i
== TOK_SKIPTO
)
2903 action
->opcode
= O_SKIPTO
;
2904 NEED1("missing skipto/pipe/queue number");
2905 action
->arg1
= strtoul(*av
, NULL
, 10);
2911 action
->opcode
= (i
== TOK_DIVERT
) ? O_DIVERT
: O_TEE
;
2912 NEED1("missing divert/tee port");
2913 action
->arg1
= strtoul(*av
, NULL
, 0);
2914 if (action
->arg1
== 0) {
2917 s
= getservbyname(av
[0], "divert");
2919 action
->arg1
= ntohs(s
->s_port
);
2921 errx(EX_DATAERR
, "illegal divert/tee port");
2927 ipfw_insn_sa
*p
= (ipfw_insn_sa
*)action
;
2930 NEED1("missing forward address[:port]");
2932 action
->opcode
= O_FORWARD_IP
;
2933 action
->len
= F_INSN_SIZE(ipfw_insn_sa
);
2935 p
->sa
.sin_len
= sizeof(struct sockaddr_in
);
2936 p
->sa
.sin_family
= AF_INET
;
2939 * locate the address-port separator (':' or ',')
2941 s
= strchr(*av
, ':');
2943 s
= strchr(*av
, ',');
2946 i
= strtoport(s
, &end
, 0 /* base */, 0 /* proto */);
2949 "illegal forwarding port ``%s''", s
);
2950 p
->sa
.sin_port
= (u_short
)i
;
2952 lookup_host(*av
, &(p
->sa
.sin_addr
));
2958 /* pretend it is a 'count' rule followed by the comment */
2959 action
->opcode
= O_COUNT
;
2960 ac
++; av
--; /* go back... */
2964 errx(EX_DATAERR
, "invalid action %s", av
[-1]);
2966 action
= next_cmd(action
);
2969 * [log [logamount N]] -- log, optional
2971 * If exists, it goes first in the cmdbuf, but then it is
2972 * skipped in the copy section to the end of the buffer.
2974 if (ac
&& !strncmp(*av
, "log", strlen(*av
))) {
2975 ipfw_insn_log
*c
= (ipfw_insn_log
*)cmd
;
2978 cmd
->len
= F_INSN_SIZE(ipfw_insn_log
);
2979 cmd
->opcode
= O_LOG
;
2981 if (ac
&& !strncmp(*av
, "logamount", strlen(*av
))) {
2983 NEED1("logamount requires argument");
2986 errx(EX_DATAERR
, "logamount must be positive");
2990 cmd
= next_cmd(cmd
);
2993 if (have_state
) /* must be a check-state, we are done */
2996 #define OR_START(target) \
2997 if (ac && (*av[0] == '(' || *av[0] == '{')) { \
2999 errx(EX_USAGE, "nested \"(\" not allowed"); \
3002 if ( (av[0])[1] == '\0') { \
3013 !strncmp(*av, ")", strlen(*av)) || \
3014 !strncmp(*av, "}", strlen(*av)) )) { \
3019 errx(EX_USAGE, "missing \")\""); \
3023 if (ac && !strncmp(*av, "not", strlen(*av))) { \
3024 if (cmd->len & F_NOT) \
3025 errx(EX_USAGE, "double \"not\" not allowed"); \
3026 cmd->len |= F_NOT; \
3030 #define OR_BLOCK(target) \
3031 if (ac && !strncmp(*av, "or", strlen(*av))) { \
3032 if (prev == NULL || open_par == 0) \
3033 errx(EX_DATAERR, "invalid OR block"); \
3034 prev->len |= F_OR; \
3044 * MAC addresses, optional.
3045 * If we have this, we skip the part "proto from src to dst"
3046 * and jump straight to the option parsing.
3049 NEED1("missing protocol");
3050 if (!strncmp(*av
, "MAC", strlen(*av
)) ||
3051 !strncmp(*av
, "mac", strlen(*av
))) {
3052 ac
--; av
++; /* the "MAC" keyword */
3053 add_mac(cmd
, ac
, av
); /* exits in case of errors */
3054 cmd
= next_cmd(cmd
);
3055 ac
-= 2; av
+= 2; /* dst-mac and src-mac */
3057 NEED1("missing mac type");
3058 if (add_mactype(cmd
, ac
, av
[0]))
3059 cmd
= next_cmd(cmd
);
3060 ac
--; av
++; /* any or mac-type */
3066 * protocol, mandatory
3068 OR_START(get_proto
);
3070 NEED1("missing protocol");
3071 if (add_proto(cmd
, *av
)) {
3073 if (F_LEN(cmd
) == 0) /* plain IP */
3078 cmd
= next_cmd(cmd
);
3080 } else if (first_cmd
!= cmd
) {
3081 errx(EX_DATAERR
, "invalid protocol ``%s''", *av
);
3084 OR_BLOCK(get_proto
);
3089 if (!ac
|| strncmp(*av
, "from", strlen(*av
)))
3090 errx(EX_USAGE
, "missing ``from''");
3094 * source IP, mandatory
3096 OR_START(source_ip
);
3097 NOT_BLOCK
; /* optional "not" */
3098 NEED1("missing source address");
3099 if (add_srcip(cmd
, *av
)) {
3101 if (F_LEN(cmd
) != 0) { /* ! any */
3103 cmd
= next_cmd(cmd
);
3106 OR_BLOCK(source_ip
);
3109 * source ports, optional
3111 NOT_BLOCK
; /* optional "not" */
3113 if (!strncmp(*av
, "any", strlen(*av
)) ||
3114 add_ports(cmd
, *av
, proto
, O_IP_SRCPORT
)) {
3116 if (F_LEN(cmd
) != 0)
3117 cmd
= next_cmd(cmd
);
3124 if (!ac
|| strncmp(*av
, "to", strlen(*av
)))
3125 errx(EX_USAGE
, "missing ``to''");
3129 * destination, mandatory
3132 NOT_BLOCK
; /* optional "not" */
3133 NEED1("missing dst address");
3134 if (add_dstip(cmd
, *av
)) {
3136 if (F_LEN(cmd
) != 0) { /* ! any */
3138 cmd
= next_cmd(cmd
);
3144 * dest. ports, optional
3146 NOT_BLOCK
; /* optional "not" */
3148 if (!strncmp(*av
, "any", strlen(*av
)) ||
3149 add_ports(cmd
, *av
, proto
, O_IP_DSTPORT
)) {
3151 if (F_LEN(cmd
) != 0)
3152 cmd
= next_cmd(cmd
);
3157 if (ac
&& first_cmd
== cmd
) {
3159 * nothing specified so far, store in the rule to ease
3167 ipfw_insn_u32
*cmd32
; /* alias for cmd */
3170 cmd32
= (ipfw_insn_u32
*)cmd
;
3172 if (*s
== '!') { /* alternate syntax for NOT */
3173 if (cmd
->len
& F_NOT
)
3174 errx(EX_USAGE
, "double \"not\" not allowed");
3178 i
= match_token(rule_options
, s
);
3182 if (cmd
->len
& F_NOT
)
3183 errx(EX_USAGE
, "double \"not\" not allowed");
3188 if (open_par
== 0 || prev
== NULL
)
3189 errx(EX_USAGE
, "invalid \"or\" block");
3193 case TOK_STARTBRACE
:
3195 errx(EX_USAGE
, "+nested \"(\" not allowed");
3201 errx(EX_USAGE
, "+missing \")\"");
3207 fill_cmd(cmd
, O_IN
, 0, 0);
3211 cmd
->len
^= F_NOT
; /* toggle F_NOT */
3212 fill_cmd(cmd
, O_IN
, 0, 0);
3216 fill_cmd(cmd
, O_FRAG
, 0, 0);
3220 fill_cmd(cmd
, O_LAYER2
, 0, 0);
3226 NEED1("recv, xmit, via require interface name"
3228 fill_iface((ipfw_insn_if
*)cmd
, av
[0]);
3230 if (F_LEN(cmd
) == 0) /* not a valid address */
3233 cmd
->opcode
= O_XMIT
;
3234 else if (i
== TOK_RECV
)
3235 cmd
->opcode
= O_RECV
;
3236 else if (i
== TOK_VIA
)
3237 cmd
->opcode
= O_VIA
;
3241 NEED1("icmptypes requires list of types");
3242 fill_icmptypes((ipfw_insn_u32
*)cmd
, *av
);
3247 NEED1("ipttl requires TTL");
3248 if (strpbrk(*av
, "-,")) {
3249 if (!add_ports(cmd
, *av
, 0, O_IPTTL
))
3250 errx(EX_DATAERR
, "invalid ipttl %s", *av
);
3252 fill_cmd(cmd
, O_IPTTL
, 0, strtoul(*av
, NULL
, 0));
3257 NEED1("ipid requires id");
3258 if (strpbrk(*av
, "-,")) {
3259 if (!add_ports(cmd
, *av
, 0, O_IPID
))
3260 errx(EX_DATAERR
, "invalid ipid %s", *av
);
3262 fill_cmd(cmd
, O_IPID
, 0, strtoul(*av
, NULL
, 0));
3267 NEED1("iplen requires length");
3268 if (strpbrk(*av
, "-,")) {
3269 if (!add_ports(cmd
, *av
, 0, O_IPLEN
))
3270 errx(EX_DATAERR
, "invalid ip len %s", *av
);
3272 fill_cmd(cmd
, O_IPLEN
, 0, strtoul(*av
, NULL
, 0));
3277 NEED1("ipver requires version");
3278 fill_cmd(cmd
, O_IPVER
, 0, strtoul(*av
, NULL
, 0));
3282 case TOK_IPPRECEDENCE
:
3283 NEED1("ipprecedence requires value");
3284 fill_cmd(cmd
, O_IPPRECEDENCE
, 0,
3285 (strtoul(*av
, NULL
, 0) & 7) << 5);
3290 NEED1("missing argument for ipoptions");
3291 fill_flags(cmd
, O_IPOPT
, f_ipopts
, *av
);
3296 NEED1("missing argument for iptos");
3297 fill_flags(cmd
, O_IPTOS
, f_iptos
, *av
);
3302 NEED1("uid requires argument");
3308 cmd
->opcode
= O_UID
;
3309 uid
= strtoul(*av
, &end
, 0);
3310 pwd
= (*end
== '\0') ? getpwuid(uid
) : getpwnam(*av
);
3312 errx(EX_DATAERR
, "uid \"%s\" nonexistent", *av
);
3313 cmd32
->d
[0] = pwd
->pw_uid
;
3314 cmd
->len
= F_INSN_SIZE(ipfw_insn_u32
);
3320 NEED1("gid requires argument");
3326 cmd
->opcode
= O_GID
;
3327 gid
= strtoul(*av
, &end
, 0);
3328 grp
= (*end
== '\0') ? getgrgid(gid
) : getgrnam(*av
);
3330 errx(EX_DATAERR
, "gid \"%s\" nonexistent", *av
);
3331 cmd32
->d
[0] = grp
->gr_gid
;
3332 cmd
->len
= F_INSN_SIZE(ipfw_insn_u32
);
3338 fill_cmd(cmd
, O_ESTAB
, 0, 0);
3342 fill_cmd(cmd
, O_TCPFLAGS
, 0,
3343 (TH_SYN
) | ( (TH_ACK
) & 0xff) <<8 );
3347 NEED1("missing argument for tcpoptions");
3348 fill_flags(cmd
, O_TCPOPTS
, f_tcpopts
, *av
);
3354 NEED1("tcpseq/tcpack requires argument");
3355 cmd
->len
= F_INSN_SIZE(ipfw_insn_u32
);
3356 cmd
->opcode
= (i
== TOK_TCPSEQ
) ? O_TCPSEQ
: O_TCPACK
;
3357 cmd32
->d
[0] = htonl(strtoul(*av
, NULL
, 0));
3362 NEED1("tcpwin requires length");
3363 fill_cmd(cmd
, O_TCPWIN
, 0,
3364 htons(strtoul(*av
, NULL
, 0)));
3369 NEED1("missing argument for tcpflags");
3370 cmd
->opcode
= O_TCPFLAGS
;
3371 fill_flags(cmd
, O_TCPFLAGS
, f_tcpflags
, *av
);
3377 errx(EX_USAGE
, "keep-state cannot be part "
3380 errx(EX_USAGE
, "only one of keep-state "
3381 "and limit is allowed");
3383 fill_cmd(cmd
, O_KEEP_STATE
, 0, 0);
3388 errx(EX_USAGE
, "limit cannot be part "
3391 errx(EX_USAGE
, "only one of keep-state "
3392 "and limit is allowed");
3393 NEED1("limit needs mask and # of connections");
3396 ipfw_insn_limit
*c
= (ipfw_insn_limit
*)cmd
;
3398 cmd
->len
= F_INSN_SIZE(ipfw_insn_limit
);
3399 cmd
->opcode
= O_LIMIT
;
3405 val
= match_token(limit_masks
, *av
);
3408 c
->limit_mask
|= val
;
3411 c
->conn_limit
= atoi(*av
);
3412 if (c
->conn_limit
== 0)
3413 errx(EX_USAGE
, "limit: limit must be >0");
3414 if (c
->limit_mask
== 0)
3415 errx(EX_USAGE
, "missing limit mask");
3421 NEED1("missing protocol");
3422 if (add_proto(cmd
, *av
)) {
3426 errx(EX_DATAERR
, "invalid protocol ``%s''",
3431 NEED1("missing source IP");
3432 if (add_srcip(cmd
, *av
)) {
3438 NEED1("missing destination IP");
3439 if (add_dstip(cmd
, *av
)) {
3445 NEED1("missing source port");
3446 if (!strncmp(*av
, "any", strlen(*av
)) ||
3447 add_ports(cmd
, *av
, proto
, O_IP_SRCPORT
)) {
3450 errx(EX_DATAERR
, "invalid source port %s", *av
);
3454 NEED1("missing destination port");
3455 if (!strncmp(*av
, "any", strlen(*av
)) ||
3456 add_ports(cmd
, *av
, proto
, O_IP_DSTPORT
)) {
3459 errx(EX_DATAERR
, "invalid destination port %s",
3465 errx(EX_USAGE
, "MAC dst-mac src-mac");
3466 if (add_mac(cmd
, ac
, av
)) {
3472 NEED1("missing mac type");
3473 if (!add_mactype(cmd
, ac
, *av
))
3474 errx(EX_DATAERR
, "invalid mac type %s", *av
);
3478 case TOK_VERREVPATH
:
3479 fill_cmd(cmd
, O_VERREVPATH
, 0, 0);
3483 fill_cmd(cmd
, O_IPSEC
, 0, 0);
3487 fill_comment(cmd
, ac
, av
);
3493 errx(EX_USAGE
, "unrecognised option [%d] %s", i
, s
);
3495 if (F_LEN(cmd
) > 0) { /* prepare to advance */
3497 cmd
= next_cmd(cmd
);
3503 * Now copy stuff into the rule.
3504 * If we have a keep-state option, the first instruction
3505 * must be a PROBE_STATE (which is generated here).
3506 * If we have a LOG option, it was stored as the first command,
3507 * and now must be moved to the top of the action part.
3509 dst
= (ipfw_insn
*)rule
->cmd
;
3512 * First thing to write into the command stream is the match probability.
3514 if (match_prob
!= 1) { /* 1 means always match */
3515 dst
->opcode
= O_PROB
;
3517 *((int32_t *)(dst
+1)) = (int32_t)(match_prob
* 0x7fffffff);
3522 * generate O_PROBE_STATE if necessary
3524 if (have_state
&& have_state
->opcode
!= O_CHECK_STATE
) {
3525 fill_cmd(dst
, O_PROBE_STATE
, 0, 0);
3526 dst
= next_cmd(dst
);
3529 * copy all commands but O_LOG, O_KEEP_STATE, O_LIMIT
3531 for (src
= (ipfw_insn
*)cmdbuf
; src
!= cmd
; src
+= i
) {
3534 switch (src
->opcode
) {
3540 bcopy(src
, dst
, i
* sizeof(uint32_t));
3546 * put back the have_state command as last opcode
3548 if (have_state
&& have_state
->opcode
!= O_CHECK_STATE
) {
3549 i
= F_LEN(have_state
);
3550 bcopy(have_state
, dst
, i
* sizeof(uint32_t));
3554 * start action section
3556 rule
->act_ofs
= dst
- rule
->cmd
;
3559 * put back O_LOG if necessary
3561 src
= (ipfw_insn
*)cmdbuf
;
3562 if (src
->opcode
== O_LOG
) {
3564 bcopy(src
, dst
, i
* sizeof(uint32_t));
3568 * copy all other actions
3570 for (src
= (ipfw_insn
*)actbuf
; src
!= action
; src
+= i
) {
3572 bcopy(src
, dst
, i
* sizeof(uint32_t));
3576 rule
->cmd_len
= (uint32_t *)dst
- (uint32_t *)(rule
->cmd
);
3577 i
= (char *)dst
- (char *)rule
;
3579 if (do_cmd(IP_FW_ADD
, rule
, (uintptr_t)&i
) == -1)
3580 err(EX_UNAVAILABLE
, "getsockopt(%s)", "IP_FW_ADD");
3582 show_ipfw(rule
, 0, 0);
3586 zero(int ac
, char *av
[], int optname
/* IP_FW_ZERO or IP_FW_RESETLOG */)
3591 char const *name
= optname
== IP_FW_ZERO
? "ZERO" : "RESETLOG";
3594 bzero(&rule
, sizeof(rule
));
3597 /* clear all entries - send empty rule */
3598 if (do_cmd(optname
, &rule
, sizeof(rule
)) < 0)
3599 err(EX_UNAVAILABLE
, "setsockopt(IP_FW_%s)", name
);
3601 printf("%s.\n", optname
== IP_FW_ZERO
?
3602 "Accounting cleared":"Logging counts reset");
3609 if (isdigit(**av
)) {
3610 rulenum
= atoi(*av
);
3613 rule
.rulenum
= rulenum
;
3614 if (do_cmd(optname
, &rule
, sizeof(rule
))) {
3615 warn("rule %u: setsockopt(IP_FW_%s)",
3617 failed
= EX_UNAVAILABLE
;
3618 } else if (!do_quiet
)
3619 printf("Entry %d %s.\n", rulenum
,
3620 optname
== IP_FW_ZERO
?
3621 "cleared" : "logging count reset");
3623 errx(EX_USAGE
, "invalid rule number ``%s''", *av
);
3626 if (failed
!= EX_OK
)
3633 int cmd
= do_pipe
? IP_DUMMYNET_FLUSH
: IP_FW_FLUSH
;
3636 if (!force
&& !do_quiet
) { /* need to ask user */
3639 printf("Are you sure? [yn] ");
3642 c
= toupper(getc(stdin
));
3643 while (c
!= '\n' && getc(stdin
) != '\n')
3645 return; /* and do not flush */
3646 } while (c
!= 'Y' && c
!= 'N');
3648 if (c
== 'N') /* user said no */
3652 if (cmd
== IP_FW_FLUSH
) {
3653 /* send empty rule */
3654 bzero(&rule
, sizeof(rule
));
3655 if (do_cmd(cmd
, &rule
, sizeof(rule
)) < 0)
3656 err(EX_UNAVAILABLE
, "setsockopt(IP_FW_FLUSH)");
3659 if (do_cmd(cmd
, NULL
, 0) < 0)
3660 err(EX_UNAVAILABLE
, "setsockopt(IP_DUMMYNET_FLUSH)");
3663 printf("Flushed all %s.\n", do_pipe
? "pipes" : "rules");
3667 * Free a the (locally allocated) copy of command line arguments.
3670 free_args(int ac
, char **av
)
3674 for (i
=0; i
< ac
; i
++)
3680 * Called with the arguments (excluding program name).
3681 * Returns 0 if successful, 1 if empty command, errx() in case of errors.
3684 ipfw_main(int oldac
, char **oldav
)
3686 int ch
, ac
, save_ac
;
3687 char **av
, **save_av
;
3688 int do_acct
= 0; /* Show packet/byte count */
3689 int do_force
= 0; /* Don't ask for confirmation */
3691 #define WHITESP " \t\f\v\n\r"
3694 else if (oldac
== 1) {
3696 * If we are called with a single string, try to split it into
3697 * arguments for subsequent parsing.
3698 * But first, remove spaces after a ',', by copying the string
3701 char *arg
= oldav
[0]; /* The string... */
3702 int l
= strlen(arg
);
3703 int copy
= 0; /* 1 if we need to copy, 0 otherwise */
3705 for (i
= j
= 0; i
< l
; i
++) {
3706 if (arg
[i
] == '#') /* comment marker */
3710 copy
= !index("," WHITESP
, arg
[i
]);
3712 copy
= !index(WHITESP
, arg
[i
]);
3717 if (!copy
&& j
> 0) /* last char was a 'blank', remove it */
3719 l
= j
; /* the new argument length */
3721 if (l
== 0) /* empty string! */
3725 * First, count number of arguments. Because of the previous
3726 * processing, this is just the number of blanks plus 1.
3728 for (i
= 0, ac
= 1; i
< l
; i
++)
3729 if (index(WHITESP
, arg
[i
]) != NULL
)
3732 av
= calloc(ac
, sizeof(char *));
3735 * Second, copy arguments from cmd[] to av[]. For each one,
3736 * j is the initial character, i is the one past the end.
3738 for (ac
= 0, i
= j
= 0; i
< l
; i
++)
3739 if (index(WHITESP
, arg
[i
]) != NULL
|| i
== l
-1) {
3742 av
[ac
] = calloc(i
-j
+1, 1);
3743 bcopy(arg
+j
, av
[ac
], i
-j
);
3749 * If an argument ends with ',' join with the next one.
3750 * Just add its length to 'l' and continue. When we have a string
3751 * without a ',' ending, we'll have the combined length in 'l'
3755 av
= calloc(oldac
, sizeof(char *));
3756 for (first
= i
= ac
= 0, l
= 0; i
< oldac
; i
++) {
3757 char *arg
= oldav
[i
];
3758 int k
= strlen(arg
);
3761 if (arg
[k
-1] != ',' || i
== oldac
-1) {
3764 av
[ac
] = calloc(l
+1, 1);
3765 for (l
=0; first
<= i
; first
++) {
3766 strlcat(av
[ac
]+l
, oldav
[first
], buflen
-l
);
3767 l
+= strlen(oldav
[first
]);
3776 /* Set the force flag for non-interactive processes */
3777 do_force
= !isatty(STDIN_FILENO
);
3779 /* Save arguments for final freeing of memory. */
3783 optind
= optreset
= 0;
3784 while ((ch
= getopt(ac
, av
, "acdefhnNqs:STtv")) != -1)
3806 case 'h': /* help */
3807 free_args(save_ac
, save_av
);
3809 break; /* NOTREACHED */
3823 case 's': /* sort */
3824 do_sort
= atoi(optarg
);
3836 do_time
= 2; /* numeric timestamp */
3839 case 'v': /* verbose */
3844 free_args(save_ac
, save_av
);
3850 NEED1("bad arguments, for usage summary ``ipfw''");
3853 * An undocumented behaviour of ipfw1 was to allow rule numbers first,
3854 * e.g. "100 add allow ..." instead of "add 100 allow ...".
3855 * In case, swap first and second argument to get the normal form.
3857 if (ac
> 1 && isdigit(*av
[0])) {
3865 * optional: pipe or queue
3868 if (!strncmp(*av
, "pipe", strlen(*av
)))
3870 else if (!strncmp(*av
, "queue", strlen(*av
)))
3876 NEED1("missing command");
3879 * For pipes and queues we normally say 'pipe NN config'
3880 * but the code is easier to parse as 'pipe config NN'
3881 * so we swap the two arguments.
3883 if (do_pipe
> 0 && ac
> 1 && isdigit(*av
[0])) {
3890 if (!strncmp(*av
, "add", strlen(*av
)))
3892 else if (do_pipe
&& !strncmp(*av
, "config", strlen(*av
)))
3893 config_pipe(ac
, av
);
3894 else if (!strncmp(*av
, "delete", strlen(*av
)))
3896 else if (!strncmp(*av
, "flush", strlen(*av
)))
3898 else if (!strncmp(*av
, "zero", strlen(*av
)))
3899 zero(ac
, av
, IP_FW_ZERO
);
3900 else if (!strncmp(*av
, "resetlog", strlen(*av
)))
3901 zero(ac
, av
, IP_FW_RESETLOG
);
3902 else if (!strncmp(*av
, "print", strlen(*av
)) ||
3903 !strncmp(*av
, "list", strlen(*av
)))
3904 list(ac
, av
, do_acct
);
3905 else if (!strncmp(*av
, "set", strlen(*av
)))
3906 sets_handler(ac
, av
);
3907 else if (!strncmp(*av
, "enable", strlen(*av
)))
3908 sysctl_handler(ac
, av
, 1);
3909 else if (!strncmp(*av
, "disable", strlen(*av
)))
3910 sysctl_handler(ac
, av
, 0);
3911 else if (!strncmp(*av
, "show", strlen(*av
)))
3912 list(ac
, av
, 1 /* show counters */);
3914 errx(EX_USAGE
, "bad command `%s'", *av
);
3916 /* Free memory allocated in the argument parsing. */
3917 free_args(save_ac
, save_av
);
3923 ipfw_readfile(int ac
, char *av
[])
3927 char *cmd
= NULL
, *filename
= av
[ac
-1];
3932 filename
= av
[ac
-1];
3934 while ((c
= getopt(ac
, av
, "cNnp:qS")) != -1) {
3951 * Skip previous args and delete last one, so we
3952 * pass all but the last argument to the preprocessor
3958 fprintf(stderr
, "command is %s\n", av
[0]);
3970 errx(EX_USAGE
, "bad arguments, for usage"
3971 " summary ``ipfw''");
3978 if (cmd
== NULL
&& ac
!= optind
+ 1) {
3979 fprintf(stderr
, "ac %d, optind %d\n", ac
, optind
);
3980 errx(EX_USAGE
, "extraneous filename arguments");
3983 if ((f
= fopen(filename
, "r")) == NULL
)
3984 err(EX_UNAVAILABLE
, "fopen: %s", filename
);
3986 if (cmd
!= NULL
) { /* pipe through preprocessor */
3989 if (pipe(pipedes
) == -1)
3990 err(EX_OSERR
, "cannot create pipe");
3994 err(EX_OSERR
, "cannot fork");
3998 * Child, will run the preprocessor with the
3999 * file on stdin and the pipe on stdout.
4001 if (dup2(fileno(f
), 0) == -1
4002 || dup2(pipedes
[1], 1) == -1)
4003 err(EX_OSERR
, "dup2()");
4008 err(EX_OSERR
, "execvp(%s) failed", cmd
);
4009 } else { /* parent, will reopen f as the pipe */
4012 if ((f
= fdopen(pipedes
[0], "r")) == NULL
) {
4013 int savederrno
= errno
;
4015 (void)kill(preproc
, SIGTERM
);
4017 err(EX_OSERR
, "fdopen()");
4022 while (fgets(buf
, BUFSIZ
, f
)) { /* read commands */
4027 snprintf(linename
, sizeof(linename
), "Line %d", lineno
);
4028 setprogname(linename
); /* XXX */
4036 if (waitpid(preproc
, &status
, 0) == -1)
4037 errx(EX_OSERR
, "waitpid()");
4038 if (WIFEXITED(status
) && WEXITSTATUS(status
) != EX_OK
)
4039 errx(EX_UNAVAILABLE
,
4040 "preprocessor exited with status %d",
4041 WEXITSTATUS(status
));
4042 else if (WIFSIGNALED(status
))
4043 errx(EX_UNAVAILABLE
,
4044 "preprocessor exited with signal %d",
4050 main(int ac
, char *av
[])
4053 * If the last argument is an absolute pathname, interpret it
4054 * as a file to be preprocessed.
4057 if (ac
> 1 && av
[ac
- 1][0] == '/' && access(av
[ac
- 1], R_OK
) == 0)
4058 ipfw_readfile(ac
, av
);
4060 if (ipfw_main(ac
-1, av
+1))