2 * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 * Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp
27 * Copyright (c) 1994 Ugen J.S.Antsilevich
29 * Idea and grammar partially left from:
30 * Copyright (c) 1993 Daniel Boulet
32 * Redistribution and use in source forms, with and without modification,
33 * are permitted provided that this entire comment appears intact.
35 * Redistribution in binary form may occur without any restrictions.
36 * Obviously, it would be nice if you gave credit where credit is due
37 * but requiring it would be too onerous.
39 * This software is provided ``AS IS'' without any warranties of any kind.
41 * NEW command line interface for IP firewall facility
47 #include <sys/param.h>
49 #include <sys/socket.h>
50 #include <sys/sockio.h>
51 #include <sys/sysctl.h>
54 #include <sys/ioctl.h>
72 #include <netinet/in.h>
73 #include <netinet/in_systm.h>
74 #include <netinet/ip.h>
75 #include <netinet/ip_icmp.h>
76 #include <netinet/ip_fw.h>
77 #include <net/route.h> /* def. of struct route */
79 #include <netinet/ip_dummynet.h>
81 #include <netinet/tcp.h>
82 #include <arpa/inet.h>
84 int s
, /* main RAW socket */
85 do_resolv
, /* Would try to resolve all */
86 do_acct
, /* Show packet/byte count */
87 do_time
, /* Show time stamps */
88 do_quiet
, /* Be quiet in add and flush */
89 do_force
, /* Don't ask for confirmation */
91 do_pipe
, /* this cmd refers to a pipe */
93 do_sort
, /* field to sort results (0 = no) */
101 static struct icmpcode icmpcodes
[] = {
102 { ICMP_UNREACH_NET
, "net" },
103 { ICMP_UNREACH_HOST
, "host" },
104 { ICMP_UNREACH_PROTOCOL
, "protocol" },
105 { ICMP_UNREACH_PORT
, "port" },
106 { ICMP_UNREACH_NEEDFRAG
, "needfrag" },
107 { ICMP_UNREACH_SRCFAIL
, "srcfail" },
108 { ICMP_UNREACH_NET_UNKNOWN
, "net-unknown" },
109 { ICMP_UNREACH_HOST_UNKNOWN
, "host-unknown" },
110 { ICMP_UNREACH_ISOLATED
, "isolated" },
111 { ICMP_UNREACH_NET_PROHIB
, "net-prohib" },
112 { ICMP_UNREACH_HOST_PROHIB
, "host-prohib" },
113 { ICMP_UNREACH_TOSNET
, "tosnet" },
114 { ICMP_UNREACH_TOSHOST
, "toshost" },
115 { ICMP_UNREACH_FILTER_PROHIB
, "filter-prohib" },
116 { ICMP_UNREACH_HOST_PRECEDENCE
, "host-precedence" },
117 { ICMP_UNREACH_PRECEDENCE_CUTOFF
, "precedence-cutoff" },
121 static void show_usage(const char *fmt
, ...);
124 mask_bits(struct in_addr m_ad
)
126 int h_fnd
= 0, h_num
= 0, i
;
129 mask
= ntohl(m_ad
.s_addr
);
130 for (i
= 0; i
< sizeof(u_long
) * CHAR_BIT
; i
++) {
144 print_port(prot
, port
, comma
)
151 const char *protocol
;
154 if (!strcmp(comma
, ":")) {
155 printf("%s0x%04x", comma
, port
);
159 pe
= getprotobynumber(prot
);
161 protocol
= pe
->p_name
;
165 se
= getservbyport(htons(port
), protocol
);
167 printf("%s%s", comma
, se
->s_name
);
172 printf("%s%d", comma
, port
);
176 print_iface(char *key
, union ip_fw_if
*un
, int byname
)
178 char ifnb
[FW_IFNLEN
+1];
181 strncpy(ifnb
, un
->fu_via_if
.name
, FW_IFNLEN
);
182 ifnb
[FW_IFNLEN
] = '\0';
183 if (un
->fu_via_if
.unit
== -1)
184 printf(" %s %s*", key
, ifnb
);
186 printf(" %s %s%d", key
, ifnb
, un
->fu_via_if
.unit
);
187 } else if (un
->fu_via_ip
.s_addr
!= 0) {
188 printf(" %s %s", key
, inet_ntoa(un
->fu_via_ip
));
190 printf(" %s any", key
);
194 print_reject_code(int code
)
198 for (ic
= icmpcodes
; ic
->str
; ic
++)
199 if (ic
->code
== code
) {
200 printf("%s", ic
->str
);
207 show_ipfw(struct ip_fw
*chain
, int pcwidth
, int bcwidth
)
214 int nsp
= IP_FW_GETNSRCP(chain
);
215 int ndp
= IP_FW_GETNDSTP(chain
);
218 setservent(1/*stay open*/);
220 printf("%05u ", chain
->fw_number
);
223 printf("%*qu %*qu ", pcwidth
, chain
->fw_pcnt
, bcwidth
, chain
->fw_bcnt
);
226 if (chain
->timestamp
) {
229 strcpy(timestr
, ctime((time_t *)&chain
->timestamp
));
230 *strchr(timestr
, '\n') = '\0';
231 printf("%s ", timestr
);
236 if (chain
->fw_flg
== IP_FW_F_CHECK_S
) {
237 printf("check-state\n");
241 if (chain
->fw_flg
& IP_FW_F_RND_MATCH
) {
242 double d
= 1.0 * (int)(chain
->pipe_ptr
);
243 d
= 1 - (d
/ 0x7fffffff);
244 printf("prob %f ", d
);
247 switch (chain
->fw_flg
& IP_FW_F_COMMAND
) {
258 printf("divert %u", chain
->fw_divert_port
);
261 printf("tee %u", chain
->fw_divert_port
);
264 printf("skipto %u", chain
->fw_skipto_rule
);
268 printf("pipe %u", chain
->fw_skipto_rule
);
271 printf("queue %u", chain
->fw_skipto_rule
);
274 if (chain
->fw_reject_code
== IP_FW_REJECT_RST
)
278 print_reject_code(chain
->fw_reject_code
);
282 printf("fwd %s", inet_ntoa(chain
->fw_fwd_ip
.sin_addr
));
283 if(chain
->fw_fwd_ip
.sin_port
)
284 printf(",%d", chain
->fw_fwd_ip
.sin_port
);
287 errx(EX_OSERR
, "impossible");
290 if (chain
->fw_flg
& IP_FW_F_PRN
) {
292 if (chain
->fw_logamount
)
293 printf(" logamount %d", chain
->fw_logamount
);
296 pe
= getprotobynumber(chain
->fw_prot
);
298 printf(" %s", pe
->p_name
);
300 printf(" %u", chain
->fw_prot
);
302 if (chain
->fw_flg
& IP_FW_F_SME
) {
305 printf(" from %s", chain
->fw_flg
& IP_FW_F_INVSRC
? "not " : "");
307 adrt
= ntohl(chain
->fw_smsk
.s_addr
);
308 if (adrt
== ULONG_MAX
&& do_resolv
) {
309 adrt
= (chain
->fw_src
.s_addr
);
310 he
= gethostbyaddr((char *)&adrt
,
311 sizeof(u_long
), AF_INET
);
313 printf("%s", inet_ntoa(chain
->fw_src
));
315 printf("%s", he
->h_name
);
317 if (adrt
!= ULONG_MAX
) {
318 mb
= mask_bits(chain
->fw_smsk
);
323 printf("%s", inet_ntoa(chain
->fw_src
));
326 printf("%s", inet_ntoa(chain
->fw_src
));
328 printf("%s", inet_ntoa(chain
->fw_smsk
));
332 printf("%s", inet_ntoa(chain
->fw_src
));
336 if (chain
->fw_prot
== IPPROTO_TCP
|| chain
->fw_prot
== IPPROTO_UDP
) {
338 for (i
= 0; i
< nsp
; i
++) {
339 print_port(chain
->fw_prot
, chain
->fw_uar
.fw_pts
[i
], comma
);
340 if (i
== 0 && (chain
->fw_flg
& IP_FW_F_SRNG
))
342 else if (i
== 0 && (chain
->fw_flg
& IP_FW_F_SMSK
))
349 if (chain
->fw_flg
& IP_FW_F_DME
) {
352 printf(" to %s", chain
->fw_flg
& IP_FW_F_INVDST
? "not " : "");
354 adrt
= ntohl(chain
->fw_dmsk
.s_addr
);
355 if (adrt
== ULONG_MAX
&& do_resolv
) {
356 adrt
= (chain
->fw_dst
.s_addr
);
357 he
= gethostbyaddr((char *)&adrt
,
358 sizeof(u_long
), AF_INET
);
360 printf("%s", inet_ntoa(chain
->fw_dst
));
362 printf("%s", he
->h_name
);
364 if (adrt
!= ULONG_MAX
) {
365 mb
= mask_bits(chain
->fw_dmsk
);
370 printf("%s", inet_ntoa(chain
->fw_dst
));
373 printf("%s", inet_ntoa(chain
->fw_dst
));
375 printf("%s", inet_ntoa(chain
->fw_dmsk
));
379 printf("%s", inet_ntoa(chain
->fw_dst
));
383 if (chain
->fw_prot
== IPPROTO_TCP
|| chain
->fw_prot
== IPPROTO_UDP
) {
385 for (i
= 0; i
< ndp
; i
++) {
386 print_port(chain
->fw_prot
, chain
->fw_uar
.fw_pts
[nsp
+i
], comma
);
387 if (i
== 0 && (chain
->fw_flg
& IP_FW_F_DRNG
))
389 else if (i
== 0 && (chain
->fw_flg
& IP_FW_F_DMSK
))
396 if (chain
->fw_flg
& IP_FW_F_UID
) {
397 struct passwd
*pwd
= getpwuid(chain
->fw_uid
);
400 printf(" uid %s", pwd
->pw_name
);
402 printf(" uid %u", chain
->fw_uid
);
405 if (chain
->fw_flg
& IP_FW_F_KEEP_S
) {
406 if (chain
->next_rule_ptr
)
407 printf(" keep-state %d", (int)chain
->next_rule_ptr
);
409 printf(" keep-state");
412 if (chain
->fw_flg
& IP_FW_BRIDGED
)
414 if ((chain
->fw_flg
& IP_FW_F_IN
) && !(chain
->fw_flg
& IP_FW_F_OUT
))
416 if (!(chain
->fw_flg
& IP_FW_F_IN
) && (chain
->fw_flg
& IP_FW_F_OUT
))
419 /* Handle hack for "via" backwards compatibility */
420 if ((chain
->fw_flg
& IF_FW_F_VIAHACK
) == IF_FW_F_VIAHACK
) {
422 &chain
->fw_in_if
, chain
->fw_flg
& IP_FW_F_IIFNAME
);
424 /* Receive interface specified */
425 if (chain
->fw_flg
& IP_FW_F_IIFACE
)
426 print_iface("recv", &chain
->fw_in_if
,
427 chain
->fw_flg
& IP_FW_F_IIFNAME
);
428 /* Transmit interface specified */
429 if (chain
->fw_flg
& IP_FW_F_OIFACE
)
430 print_iface("xmit", &chain
->fw_out_if
,
431 chain
->fw_flg
& IP_FW_F_OIFNAME
);
434 if (chain
->fw_flg
& IP_FW_F_FRAG
)
437 if (chain
->fw_ipopt
|| chain
->fw_ipnopt
) {
438 int _opt_printed
= 0;
439 #define PRINTOPT(x) {if (_opt_printed) printf(",");\
440 printf(x); _opt_printed = 1;}
443 if (chain
->fw_ipopt
& IP_FW_IPOPT_SSRR
) PRINTOPT("ssrr");
444 if (chain
->fw_ipnopt
& IP_FW_IPOPT_SSRR
) PRINTOPT("!ssrr");
445 if (chain
->fw_ipopt
& IP_FW_IPOPT_LSRR
) PRINTOPT("lsrr");
446 if (chain
->fw_ipnopt
& IP_FW_IPOPT_LSRR
) PRINTOPT("!lsrr");
447 if (chain
->fw_ipopt
& IP_FW_IPOPT_RR
) PRINTOPT("rr");
448 if (chain
->fw_ipnopt
& IP_FW_IPOPT_RR
) PRINTOPT("!rr");
449 if (chain
->fw_ipopt
& IP_FW_IPOPT_TS
) PRINTOPT("ts");
450 if (chain
->fw_ipnopt
& IP_FW_IPOPT_TS
) PRINTOPT("!ts");
453 if (chain
->fw_ipflg
& IP_FW_IF_TCPEST
)
454 printf(" established");
455 else if (chain
->fw_tcpf
== IP_FW_TCPF_SYN
&&
456 chain
->fw_tcpnf
== IP_FW_TCPF_ACK
)
458 else if (chain
->fw_tcpf
|| chain
->fw_tcpnf
) {
459 int _flg_printed
= 0;
460 #define PRINTFLG(x) {if (_flg_printed) printf(",");\
461 printf(x); _flg_printed = 1;}
463 printf(" tcpflags ");
464 if (chain
->fw_tcpf
& IP_FW_TCPF_FIN
) PRINTFLG("fin");
465 if (chain
->fw_tcpnf
& IP_FW_TCPF_FIN
) PRINTFLG("!fin");
466 if (chain
->fw_tcpf
& IP_FW_TCPF_SYN
) PRINTFLG("syn");
467 if (chain
->fw_tcpnf
& IP_FW_TCPF_SYN
) PRINTFLG("!syn");
468 if (chain
->fw_tcpf
& IP_FW_TCPF_RST
) PRINTFLG("rst");
469 if (chain
->fw_tcpnf
& IP_FW_TCPF_RST
) PRINTFLG("!rst");
470 if (chain
->fw_tcpf
& IP_FW_TCPF_PSH
) PRINTFLG("psh");
471 if (chain
->fw_tcpnf
& IP_FW_TCPF_PSH
) PRINTFLG("!psh");
472 if (chain
->fw_tcpf
& IP_FW_TCPF_ACK
) PRINTFLG("ack");
473 if (chain
->fw_tcpnf
& IP_FW_TCPF_ACK
) PRINTFLG("!ack");
474 if (chain
->fw_tcpf
& IP_FW_TCPF_URG
) PRINTFLG("urg");
475 if (chain
->fw_tcpnf
& IP_FW_TCPF_URG
) PRINTFLG("!urg");
477 if (chain
->fw_tcpopt
|| chain
->fw_tcpnopt
) {
478 int _opt_printed
= 0;
479 #define PRINTTOPT(x) {if (_opt_printed) printf(",");\
480 printf(x); _opt_printed = 1;}
482 printf(" tcpoptions ");
483 if (chain
->fw_tcpopt
& IP_FW_TCPOPT_MSS
) PRINTTOPT("mss");
484 if (chain
->fw_tcpnopt
& IP_FW_TCPOPT_MSS
) PRINTTOPT("!mss");
485 if (chain
->fw_tcpopt
& IP_FW_TCPOPT_WINDOW
) PRINTTOPT("window");
486 if (chain
->fw_tcpnopt
& IP_FW_TCPOPT_WINDOW
) PRINTTOPT("!window");
487 if (chain
->fw_tcpopt
& IP_FW_TCPOPT_SACK
) PRINTTOPT("sack");
488 if (chain
->fw_tcpnopt
& IP_FW_TCPOPT_SACK
) PRINTTOPT("!sack");
489 if (chain
->fw_tcpopt
& IP_FW_TCPOPT_TS
) PRINTTOPT("ts");
490 if (chain
->fw_tcpnopt
& IP_FW_TCPOPT_TS
) PRINTTOPT("!ts");
491 if (chain
->fw_tcpopt
& IP_FW_TCPOPT_CC
) PRINTTOPT("cc");
492 if (chain
->fw_tcpnopt
& IP_FW_TCPOPT_CC
) PRINTTOPT("!cc");
495 if (chain
->fw_flg
& IP_FW_F_ICMPBIT
) {
501 for (type_index
= 0; type_index
< IP_FW_ICMPTYPES_DIM
* sizeof(unsigned) * 8; ++type_index
)
502 if (chain
->fw_uar
.fw_icmptypes
[type_index
/ (sizeof(unsigned) * 8)] &
503 (1U << (type_index
% (sizeof(unsigned) * 8)))) {
504 printf("%c%d", first
== 1 ? ' ' : ',', type_index
);
516 sort_q(const void *pa
, const void *pb
)
518 int rev
= (do_sort
< 0);
519 int field
= rev
? -do_sort
: do_sort
;
521 const struct dn_flow_queue
*a
= pa
;
522 const struct dn_flow_queue
*b
= pb
;
526 res
= a
->len
- b
->len
;
529 res
= a
->len_bytes
- b
->len_bytes
;
532 case 3 : /* tot pkts */
533 res
= a
->tot_pkts
- b
->tot_pkts
;
536 case 4 : /* tot bytes */
537 res
= a
->tot_bytes
- b
->tot_bytes
;
544 return (int)(rev
? res
: -res
);
548 list_queues(struct dn_flow_set
*fs
, struct dn_flow_queue
*q
)
552 printf(" mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n",
554 fs
->flow_mask
.src_ip
, fs
->flow_mask
.src_port
,
555 fs
->flow_mask
.dst_ip
, fs
->flow_mask
.dst_port
);
556 if (fs
->rq_elements
== 0)
559 printf("BKT Prot ___Source IP/port____ "
560 "____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp\n");
562 heapsort(q
, fs
->rq_elements
, sizeof(*q
), sort_q
);
563 for (l
= 0; l
< fs
->rq_elements
; l
++) {
567 ina
.s_addr
= htonl(q
[l
].id
.src_ip
);
568 printf("%3d ", q
[l
].hash_slot
);
569 pe
= getprotobynumber(q
[l
].id
.proto
);
571 printf("%-4s ", pe
->p_name
);
573 printf("%4u ", q
[l
].id
.proto
);
574 printf("%15s/%-5d ", inet_ntoa(ina
), q
[l
].id
.src_port
);
575 ina
.s_addr
= htonl(q
[l
].id
.dst_ip
);
577 inet_ntoa(ina
), q
[l
].id
.dst_port
);
578 printf("%4qu %8qu %2u %4u %3u\n",
579 q
[l
].tot_pkts
, q
[l
].tot_bytes
,
580 q
[l
].len
, q
[l
].len_bytes
, q
[l
].drops
);
582 printf(" S %20qd F %20qd\n", q
[l
].S
, q
[l
].F
);
587 print_flowset_parms(struct dn_flow_set
*fs
, char *prefix
)
592 char red
[90]; /* Display RED parameters */
595 if (fs
->flags_fs
& DN_QSIZE_IS_BYTES
) {
597 sprintf(qs
, "%d KB", l
/ 1024);
599 sprintf(qs
, "%d B", l
);
601 sprintf(qs
, "%3d sl.", l
);
603 sprintf(plr
, "plr %f", 1.0*fs
->plr
/(double)(0x7fffffff));
606 if (fs
->flags_fs
& DN_IS_RED
) /* RED parameters */
608 "\n %cRED w_q %f min_th %d max_th %d max_p %f",
609 (fs
->flags_fs
& DN_IS_GENTLE_RED
)? 'G' : ' ',
610 1.0 * fs
->w_q
/ (double)(1 << SCALE_RED
),
611 SCALE_VAL(fs
->min_th
),
612 SCALE_VAL(fs
->max_th
),
613 1.0 * fs
->max_p
/ (double)(1 << SCALE_RED
) ) ;
615 sprintf(red
, "droptail");
617 printf("%s %s%s %d queues (%d buckets) %s\n", prefix
, qs
, plr
,
618 fs
->rq_elements
, fs
->rq_size
, red
);
620 #endif /* DUMMYNET */
629 struct dn_pipe
*pipes
;
630 #endif /* DUMMYNET */
637 /* get rules or pipes from kernel, resizing array as necessary */
640 const int unit
= do_pipe
? sizeof(*pipes
) : sizeof(*rules
);
641 const int ocmd
= do_pipe
? IP_DUMMYNET_GET
: IP_FW_GET
;
643 const int unit
= sizeof(*rules
);
644 const int ocmd
= IP_FW_GET
;
645 #endif /* DUMMYNET */
649 while (nbytes
>= nalloc
) {
650 nalloc
= nalloc
* 2 + 200;
652 if ((data
= realloc(data
, nbytes
)) == NULL
)
653 err(EX_OSERR
, "realloc");
655 rules
->version
= IP_FW_CURRENT_API_VERSION
;
656 if (getsockopt(s
, IPPROTO_IP
, ocmd
, data
, &nbytes
) < 0)
658 err(EX_OSERR
, "getsockopt(IP_%s_GET)",
659 do_pipe
? "DUMMYNET" : "FW");
661 err(EX_OSERR
, "getsockopt(IP_FW_GET)");
662 #endif /* DUMMYNET */
666 /* display requested pipes */
671 struct dn_pipe
*p
= (struct dn_pipe
*) data
;
672 struct dn_flow_set
*fs
;
673 struct dn_flow_queue
*q
;
677 rulenum
= strtoul(*av
++, NULL
, 10);
680 for (; nbytes
>= sizeof(*p
); p
= (struct dn_pipe
*)next
) {
681 double b
= p
->bandwidth
;
685 if (p
->next
!= (struct dn_pipe
*)DN_IS_PIPE
)
687 l
= sizeof(*p
) + p
->fs
.rq_elements
* sizeof(*q
);
688 next
= (void *)p
+ l
;
690 q
= (struct dn_flow_queue
*)(p
+1);
692 if (rulenum
!= 0 && rulenum
!= p
->pipe_nr
)
694 if (p
->if_name
[0] != '\0')
695 sprintf(buf
, "%s", p
->if_name
);
697 sprintf(buf
, "unlimited");
698 else if (b
>= 1000000)
699 sprintf(buf
, "%7.3f Mbit/s", b
/1000000);
701 sprintf(buf
, "%7.3f Kbit/s", b
/1000);
703 sprintf(buf
, "%7.3f bit/s ", b
);
705 sprintf(prefix
, "%05d: %s %4d ms ",
706 p
->pipe_nr
, buf
, p
->delay
);
707 print_flowset_parms(&(p
->fs
), prefix
);
709 printf(" V %20qd\n", p
->V
>> MY_M
);
710 list_queues(&(p
->fs
), q
);
712 fs
= (struct dn_flow_set
*) next
;
713 for (; nbytes
>= sizeof(*fs
); fs
= (struct dn_flow_set
*)next
) {
716 if (fs
->next
!= (struct dn_flow_set
*)DN_IS_QUEUE
)
718 l
= sizeof(*fs
) + fs
->rq_elements
* sizeof(*q
);
719 next
= (void *)fs
+ l
;
721 q
= (struct dn_flow_queue
*)(fs
+1);
722 sprintf(prefix
, "q%05d: weight %d pipe %d ",
723 fs
->fs_nr
, fs
->weight
, fs
->parent_nr
);
724 print_flowset_parms(fs
, prefix
);
730 #endif /* DUMMYNET */
732 rules
= (struct ip_fw
*) data
;
733 /* determine num more accurately */
735 while (rules
[num
].fw_number
< 65535)
737 num
++; /* counting starts from 0 ... */
738 /* if showing stats, figure out column widths ahead of time */
740 for (n
= 0; n
< num
; n
++) {
741 struct ip_fw
*const r
= &rules
[n
];
746 width
= sprintf(temp
, "%qu", r
->fw_pcnt
);
751 width
= sprintf(temp
, "%qu", r
->fw_bcnt
);
757 /* display all rules */
758 for (n
= 0; n
< num
; n
++) {
759 struct ip_fw
*const r
= &rules
[n
];
761 show_ipfw(r
, pcwidth
, bcwidth
);
764 /* display specific rules requested on command line */
772 /* convert command line rule # */
773 rnum
= strtoul(*av
++, &endptr
, 10);
776 warnx("invalid rule number: %s", *(av
- 1));
779 for (seen
= n
= 0; n
< num
; n
++) {
780 struct ip_fw
*const r
= &rules
[n
];
782 if (r
->fw_number
> rnum
)
784 if (r
->fw_number
== rnum
) {
785 show_ipfw(r
, pcwidth
, bcwidth
);
790 /* give precedence to other error(s) */
791 if (exitval
== EX_OK
)
792 exitval
= EX_UNAVAILABLE
;
793 warnx("rule %lu does not exist", rnum
);
796 if (exitval
!= EX_OK
)
802 if (num
* sizeof (rules
[0]) != nbytes
) {
803 struct ipfw_dyn_rule
*d
=
804 (struct ipfw_dyn_rule
*)&rules
[num
];
808 printf("## Dynamic rules:\n");
810 printf("%05d %qu %qu (T %d, # %d) ty %d",
816 pe
= getprotobynumber(d
->id
.proto
);
818 printf(" %s,", pe
->p_name
);
820 printf(" %u,", d
->id
.proto
);
821 a
.s_addr
= htonl(d
->id
.src_ip
);
822 printf(" %s", inet_ntoa(a
));
823 printf(" %d", d
->id
.src_port
);
825 default: /* bidir, no mask */
829 a
.s_addr
= htonl(d
->id
.dst_ip
);
830 printf(" %s", inet_ntoa(a
));
831 printf(" %d", d
->id
.dst_port
);
842 show_usage(const char *fmt
, ...)
849 vsnprintf(buf
, sizeof(buf
), fmt
, args
);
851 warnx("error: %s", buf
);
853 fprintf(stderr
, "usage: ipfw [options]\n"
856 #endif /* DUMMYNET */
857 " add [number] rule\n"
859 " [pipe] delete number ...\n"
860 " [pipe] list [number ...]\n"
861 " [pipe] show [number ...]\n"
862 #endif /* DUMMYNET */
863 " zero [number ...]\n"
864 " resetlog [number ...]\n"
866 " pipe number config [pipeconfig]\n"
867 #endif /* DUMMYNET */
868 " rule: [prob <match_probability>] action proto src dst extras...\n"
870 " {allow|permit|accept|pass|deny|drop|reject|unreach code|\n"
871 " reset|count|skipto num|divert port|tee port|fwd ip|\n"
874 #endif /* DUMMYNET */
875 "} [log [logamount count]]\n"
876 " proto: {ip|tcp|udp|icmp|<number>}\n"
877 " src: from [not] {me|any|ip[{/bits|:mask}]} [{port|port-port},[port],...]\n"
878 " dst: to [not] {me|any|ip[{/bits|:mask}]} [{port|port-port},[port],...]\n"
881 " fragment (may not be used with ports or tcpflags)\n"
884 " {xmit|recv|via} {iface|ip|any}\n"
885 " {established|setup}\n"
886 " tcpflags [!]{syn|fin|rst|ack|psh|urg},...\n"
887 " ipoptions [!]{ssrr|lsrr|rr|ts},...\n"
888 " tcpoptions [!]{mss|window|sack|ts|cc},...\n"
889 " icmptypes {type[,type]}...\n"
892 " {bw|bandwidth} <number>{bit/s|Kbit/s|Mbit/s|Bytes/s|KBytes/s|MBytes/s}\n"
893 " {bw|bandwidth} interface_name\n"
894 " delay <milliseconds>\n"
895 " queue <size>{packets|Bytes|KBytes}\n"
897 " mask {all| [dst-ip|src-ip|dst-port|src-port|proto] <number>}\n"
898 " buckets <number>}\n"
899 " {red|gred} <fraction>/<number>/<number>/<fraction>\n"
901 #endif /* DUMMYNET */
908 lookup_host (host
, ipaddr
)
910 struct in_addr
*ipaddr
;
914 if (!inet_aton(host
, ipaddr
)) {
915 if ((he
= gethostbyname(host
)) == NULL
)
917 *ipaddr
= *(struct in_addr
*)he
->h_addr_list
[0];
923 fill_ip(ipno
, mask
, acp
, avp
)
924 struct in_addr
*ipno
, *mask
;
932 if (ac
&& !strncmp(*av
, "any", strlen(*av
))) {
933 ipno
->s_addr
= mask
->s_addr
= 0; av
++; ac
--;
935 p
= strchr(*av
, '/');
937 p
= strchr(*av
, ':');
943 if (lookup_host(*av
, ipno
) != 0)
944 show_usage("hostname ``%s'' unknown", *av
);
947 if (!inet_aton(p
, mask
))
948 show_usage("bad netmask ``%s''", p
);
953 } else if (atoi(p
) > 32) {
954 show_usage("bad width ``%s''", p
);
957 htonl(~0 << (32 - atoi(p
)));
961 mask
->s_addr
= htonl(~0);
964 ipno
->s_addr
&= mask
->s_addr
;
973 fill_reject_code(u_short
*codep
, char *str
)
979 val
= strtoul(str
, &s
, 0);
980 if (s
!= str
&& *s
== '\0' && val
< 0x100) {
984 for (ic
= icmpcodes
; ic
->str
; ic
++)
985 if (!strcasecmp(str
, ic
->str
)) {
989 show_usage("unknown ICMP unreachable code ``%s''", str
);
993 add_port(cnt
, ptr
, off
, port
)
994 u_short
*cnt
, *ptr
, off
, port
;
996 if (off
+ *cnt
>= IP_FW_MAX_PORTS
)
997 errx(EX_USAGE
, "too many ports (max is %d)", IP_FW_MAX_PORTS
);
998 ptr
[off
+*cnt
] = port
;
1003 lookup_port(const char *arg
, int proto
, int test
, int nodash
)
1006 char *earg
, buf
[32];
1010 snprintf(buf
, sizeof(buf
), "%s", arg
);
1012 for (p
= q
= buf
; *p
; *q
++ = *p
++) {
1017 if (*p
== ',' || (nodash
&& *p
== '-'))
1023 val
= (int) strtoul(buf
, &earg
, 0);
1024 if (!*buf
|| *earg
) {
1025 char *protocol
= NULL
;
1028 struct protoent
*pe
= getprotobynumber(proto
);
1031 protocol
= pe
->p_name
;
1035 if ((s
= getservbyname(buf
, protocol
))) {
1036 val
= htons(s
->s_port
);
1039 errx(EX_DATAERR
, "unknown port ``%s''", buf
);
1044 if (val
< 0 || val
> 0xffff) {
1046 errx(EX_DATAERR
, "port ``%s'' out of range", buf
);
1055 * return: 0 normally, 1 if first pair is a range,
1056 * 2 if first pair is a port+mask
1059 fill_port(u_short
*cnt
, u_short
*ptr
, u_short off
, char *arg
, int proto
)
1062 int initial_range
= 0;
1064 for (s
= arg
; *s
&& *s
!= ',' && *s
!= '-' && *s
!= ':'; s
++) {
1065 if (*s
== '\\' && *(s
+1))
1070 if (strchr(arg
, ','))
1071 errx(EX_USAGE
, "port/mask must be first in list");
1072 add_port(cnt
, ptr
, off
, *arg
? lookup_port(arg
, proto
, 0, 0) : 0x0000);
1074 s
= strchr(arg
,',');
1077 add_port(cnt
, ptr
, off
, *arg
? lookup_port(arg
, proto
, 0, 0) : 0xffff);
1083 if (strchr(arg
, ','))
1084 errx(EX_USAGE
, "port range must be first in list");
1085 add_port(cnt
, ptr
, off
, *arg
? lookup_port(arg
, proto
, 0, 0) : 0x0000);
1087 s
= strchr(arg
,',');
1090 add_port(cnt
, ptr
, off
, *arg
? lookup_port(arg
, proto
, 0, 0) : 0xffff);
1094 while (arg
!= NULL
) {
1095 s
= strchr(arg
,',');
1098 add_port(cnt
, ptr
, off
, lookup_port(arg
, proto
, 0, 0));
1101 return initial_range
;
1105 fill_tcpflag(u_char
*set
, u_char
*reset
, char **vp
)
1115 { "syn", IP_FW_TCPF_SYN
},
1116 { "fin", IP_FW_TCPF_FIN
},
1117 { "ack", IP_FW_TCPF_ACK
},
1118 { "psh", IP_FW_TCPF_PSH
},
1119 { "rst", IP_FW_TCPF_RST
},
1120 { "urg", IP_FW_TCPF_URG
}
1133 for (i
= 0; i
< sizeof(flags
) / sizeof(flags
[0]); ++i
)
1134 if (!strncmp(p
, flags
[i
].name
, strlen(p
))) {
1135 *d
|= flags
[i
].value
;
1138 if (i
== sizeof(flags
) / sizeof(flags
[0]))
1139 show_usage("invalid tcp flag ``%s''", p
);
1145 fill_tcpopts(u_char
*set
, u_char
*reset
, char **vp
)
1155 { "mss", IP_FW_TCPOPT_MSS
},
1156 { "window", IP_FW_TCPOPT_WINDOW
},
1157 { "sack", IP_FW_TCPOPT_SACK
},
1158 { "ts", IP_FW_TCPOPT_TS
},
1159 { "cc", IP_FW_TCPOPT_CC
},
1172 for (i
= 0; i
< sizeof(opts
) / sizeof(opts
[0]); ++i
)
1173 if (!strncmp(p
, opts
[i
].name
, strlen(p
))) {
1174 *d
|= opts
[i
].value
;
1177 if (i
== sizeof(opts
) / sizeof(opts
[0]))
1178 show_usage("invalid tcp option ``%s''", p
);
1184 fill_ipopt(u_char
*set
, u_char
*reset
, char **vp
)
1199 if (!strncmp(p
, "ssrr", strlen(p
))) *d
|= IP_FW_IPOPT_SSRR
;
1200 if (!strncmp(p
, "lsrr", strlen(p
))) *d
|= IP_FW_IPOPT_LSRR
;
1201 if (!strncmp(p
, "rr", strlen(p
))) *d
|= IP_FW_IPOPT_RR
;
1202 if (!strncmp(p
, "ts", strlen(p
))) *d
|= IP_FW_IPOPT_TS
;
1208 fill_icmptypes(types
, vp
, fw_flg
)
1217 unsigned long icmptype
;
1222 icmptype
= strtoul(c
, &c
, 0);
1224 if (*c
!= ',' && *c
!= '\0')
1225 show_usage("invalid ICMP type");
1227 if (icmptype
>= IP_FW_ICMPTYPES_DIM
* sizeof(unsigned) * 8)
1228 show_usage("ICMP type out of range");
1230 types
[icmptype
/ (sizeof(unsigned) * 8)] |=
1231 1 << (icmptype
% (sizeof(unsigned) * 8));
1232 *fw_flg
|= IP_FW_F_ICMPBIT
;
1243 struct dn_pipe pipe
;
1244 #endif /* DUMMYNET */
1246 int exitval
= EX_OK
;
1248 memset(&rule
, 0, sizeof rule
);
1250 memset(&pipe
, 0, sizeof pipe
);
1251 #endif /* DUMMYNET */
1252 rule
.version
= IP_FW_CURRENT_API_VERSION
;
1257 while (ac
&& isdigit(**av
))
1259 i
= atoi(*av
); av
++; ac
--;
1264 if (do_pipe
== 1) pipe
.pipe_nr
= i
;
1265 else pipe
.fs
.fs_nr
= i
;
1267 i
= setsockopt(s
, IPPROTO_IP
, IP_DUMMYNET_DEL
, &pipe
, sizeof pipe
);
1271 warn("rule %u: setsockopt(%s)", do_pipe
== 1 ? pipe
.pipe_nr
: pipe
.fs
.fs_nr
,
1276 #endif /* DUMMYNET */
1279 i
= setsockopt(s
, IPPROTO_IP
, IP_FW_DEL
, &rule
, sizeof rule
);
1282 exitval
= EX_UNAVAILABLE
;
1283 warn("rule %u: setsockopt(%s)", rule
.fw_number
, "IP_FW_DEL");
1288 if (exitval
!= EX_OK
)
1293 verify_interface(union ip_fw_if
*ifu
)
1298 * If a unit was specified, check for that exact interface.
1299 * If a wildcard was specified, check for unit 0.
1301 snprintf(ifr
.ifr_name
, sizeof(ifr
.ifr_name
), "%s%d",
1302 ifu
->fu_via_if
.name
,
1303 ifu
->fu_via_if
.unit
== -1 ? 0 : ifu
->fu_via_if
.unit
);
1305 if (ioctl(s
, SIOCGIFFLAGS
, &ifr
) < 0)
1306 warnx("warning: interface ``%s'' does not exist", ifr
.ifr_name
);
1310 fill_iface(char *which
, union ip_fw_if
*ifu
, int *byname
, int ac
, char *arg
)
1313 show_usage("missing argument for ``%s''", which
);
1315 /* Parse the interface or address */
1316 if (!strcmp(arg
, "any")) {
1317 ifu
->fu_via_ip
.s_addr
= 0;
1319 } else if (!isdigit(*arg
)) {
1323 strncpy(ifu
->fu_via_if
.name
, arg
, sizeof(ifu
->fu_via_if
.name
));
1324 ifu
->fu_via_if
.name
[sizeof(ifu
->fu_via_if
.name
) - 1] = '\0';
1325 for (q
= ifu
->fu_via_if
.name
;
1326 *q
&& !isdigit(*q
) && *q
!= '*'; q
++)
1328 ifu
->fu_via_if
.unit
= (*q
== '*') ? -1 : atoi(q
);
1330 verify_interface(ifu
);
1331 } else if (!inet_aton(arg
, &ifu
->fu_via_ip
)) {
1332 show_usage("bad ip address ``%s''", arg
);
1339 config_pipe(int ac
, char **av
)
1341 struct dn_pipe pipe
;
1345 memset(&pipe
, 0, sizeof pipe
);
1349 if (ac
&& isdigit(**av
)) {
1350 i
= atoi(*av
); av
++; ac
--;
1357 if (!strncmp(*av
, "plr", strlen(*av
))) {
1359 double d
= strtod(av
[1], NULL
);
1364 pipe
.fs
.plr
= (int)(d
*0x7fffffff);
1366 } else if (!strncmp(*av
, "queue", strlen(*av
))) {
1368 pipe
.fs
.qsize
= strtoul(av
[1], &end
, 0);
1369 if (*end
== 'K' || *end
== 'k') {
1370 pipe
.fs
.flags_fs
|= DN_QSIZE_IS_BYTES
;
1371 pipe
.fs
.qsize
*= 1024;
1372 } else if (*end
== 'B' || !strncmp(end
, "by", 2)) {
1373 pipe
.fs
.flags_fs
|= DN_QSIZE_IS_BYTES
;
1376 } else if (!strncmp(*av
, "buckets", strlen(*av
))) {
1377 pipe
.fs
.rq_size
= strtoul(av
[1], NULL
, 0);
1379 } else if (!strncmp(*av
, "mask", strlen(*av
))) {
1380 /* per-flow queue, mask is dst_ip, dst_port,
1381 * src_ip, src_port, proto measured in bits
1384 u_int32_t
*par
= NULL
;
1386 pipe
.fs
.flow_mask
.dst_ip
= 0;
1387 pipe
.fs
.flow_mask
.src_ip
= 0;
1388 pipe
.fs
.flow_mask
.dst_port
= 0;
1389 pipe
.fs
.flow_mask
.src_port
= 0;
1390 pipe
.fs
.flow_mask
.proto
= 0;
1393 if (ac
>= 1 && !strncmp(*av
, "all", strlen(*av
))) {
1394 /* special case -- all bits are significant */
1395 pipe
.fs
.flow_mask
.dst_ip
= ~0;
1396 pipe
.fs
.flow_mask
.src_ip
= ~0;
1397 pipe
.fs
.flow_mask
.dst_port
= ~0;
1398 pipe
.fs
.flow_mask
.src_port
= ~0;
1399 pipe
.fs
.flow_mask
.proto
= ~0;
1400 pipe
.fs
.flags_fs
|= DN_HAVE_FLOW_MASK
;
1406 if (!strncmp(*av
, "dst-ip", strlen(*av
)))
1407 par
= &(pipe
.fs
.flow_mask
.dst_ip
);
1408 else if (!strncmp(*av
, "src-ip", strlen(*av
)))
1409 par
= &(pipe
.fs
.flow_mask
.src_ip
);
1410 else if (!strncmp(*av
, "dst-port", strlen(*av
)))
1411 (u_int16_t
*)par
= &(pipe
.fs
.flow_mask
.dst_port
);
1412 else if (!strncmp(*av
, "src-port", strlen(*av
)))
1413 (u_int16_t
*)par
= &(pipe
.fs
.flow_mask
.src_port
);
1414 else if (!strncmp(*av
, "proto", strlen(*av
)))
1415 (u_int8_t
*)par
= &(pipe
.fs
.flow_mask
.proto
);
1419 show_usage("mask: %s value missing", *av
);
1420 if (*av
[1] == '/') {
1421 a
= strtoul(av
[1]+1, &end
, 0);
1422 if (a
== 32) /* special case... */
1426 fprintf(stderr
, " mask is 0x%08x\n", a
);
1428 a
= strtoul(av
[1], &end
, 0);
1429 if ((u_int16_t
*)par
== &(pipe
.fs
.flow_mask
.src_port
) ||
1430 (u_int16_t
*)par
== &(pipe
.fs
.flow_mask
.dst_port
)) {
1432 show_usage("mask: %s must be 16 bit, not 0x%08x",
1434 *((u_int16_t
*)par
) = (u_int16_t
) a
;
1435 } else if ((u_int8_t
*)par
== &(pipe
.fs
.flow_mask
.proto
)) {
1437 show_usage("mask: %s must be 8 bit, not 0x%08x",
1439 *((u_int8_t
*)par
) = (u_int8_t
) a
;
1443 pipe
.fs
.flags_fs
|= DN_HAVE_FLOW_MASK
;
1447 } else if (!strncmp(*av
, "red", strlen(*av
)) ||
1448 !strncmp(*av
, "gred", strlen(*av
))) { /* RED enabled */
1449 pipe
.fs
.flags_fs
|= DN_IS_RED
;
1451 pipe
.fs
.flags_fs
|= DN_IS_GENTLE_RED
;
1452 if ((end
= strsep(&av
[1],"/"))) {
1453 double w_q
= strtod(end
, NULL
);
1454 if (w_q
> 1 || w_q
<= 0)
1455 show_usage("w_q %f must be 0 < x <= 1", w_q
);
1456 pipe
.fs
.w_q
= (int) (w_q
* (1 << SCALE_RED
));
1458 if ((end
= strsep(&av
[1],"/"))) {
1459 pipe
.fs
.min_th
= strtoul(end
, &end
, 0);
1460 if (*end
== 'K' || *end
== 'k')
1461 pipe
.fs
.min_th
*= 1024;
1463 if ((end
= strsep(&av
[1],"/"))) {
1464 pipe
.fs
.max_th
= strtoul(end
, &end
, 0);
1465 if (*end
== 'K' || *end
== 'k')
1466 pipe
.fs
.max_th
*= 1024;
1468 if ((end
= strsep(&av
[1],"/"))) {
1469 double max_p
= strtod(end
, NULL
);
1470 if (max_p
> 1 || max_p
<= 0)
1471 show_usage("max_p %f must be 0 < x <= 1", max_p
);
1472 pipe
.fs
.max_p
= (int) (max_p
* (1 << SCALE_RED
));
1475 } else if (!strncmp(*av
, "droptail", strlen(*av
))) { /* DROPTAIL */
1476 pipe
.fs
.flags_fs
&= ~(DN_IS_RED
|DN_IS_GENTLE_RED
);
1480 /* some commands are only good for pipes. */
1481 if (!strncmp(*av
, "bw", strlen(*av
)) ||
1482 ! strncmp(*av
, "bandwidth", strlen(*av
))) {
1483 if (av
[1][0] >= 'a' && av
[1][0] <= 'z') {
1484 int l
= sizeof(pipe
.if_name
)-1;
1485 /* interface name */
1486 strncpy(pipe
.if_name
, av
[1], l
);
1487 pipe
.if_name
[l
] = '\0';
1490 pipe
.if_name
[0] = '\0';
1491 pipe
.bandwidth
= strtoul(av
[1], &end
, 0);
1492 if (*end
== 'K' || *end
== 'k')
1493 end
++, pipe
.bandwidth
*= 1000;
1494 else if (*end
== 'M')
1495 end
++, pipe
.bandwidth
*= 1000000;
1496 if (*end
== 'B' || !strncmp(end
, "by", 2))
1497 pipe
.bandwidth
*= 8;
1500 } else if (!strncmp(*av
, "delay", strlen(*av
))) {
1501 pipe
.delay
= strtoul(av
[1], NULL
, 0);
1504 show_usage("unrecognised pipe option ``%s''", *av
);
1505 } else { /* this refers to a queue */
1506 if (!strncmp(*av
, "weight", strlen(*av
))) {
1507 pipe
.fs
.weight
= strtoul(av
[1], &end
, 0);
1510 } else if (!strncmp(*av
, "pipe", strlen(*av
))) {
1511 pipe
.fs
.parent_nr
= strtoul(av
[1], &end
, 0);
1515 show_usage("unrecognised option ``%s''", *av
);
1520 if (pipe
.pipe_nr
== 0)
1521 show_usage("pipe_nr %d must be > 0", pipe
.pipe_nr
);
1522 if (pipe
.delay
> 10000)
1523 show_usage("delay %d must be < 10000", pipe
.delay
);
1524 } else { /* do_pipe == 2, queue */
1525 if (pipe
.fs
.parent_nr
== 0)
1526 show_usage("pipe %d must be > 0", pipe
.fs
.parent_nr
);
1527 if (pipe
.fs
.weight
>100)
1528 show_usage("weight %d must be <= 100", pipe
.fs
.weight
);
1530 if (pipe
.fs
.flags_fs
& DN_QSIZE_IS_BYTES
) {
1531 if (pipe
.fs
.qsize
> 1024*1024)
1532 show_usage("queue size %d, must be < 1MB",
1535 if (pipe
.fs
.qsize
> 100)
1536 show_usage("queue size %d, must be 2 <= x <= 100",
1539 if (pipe
.fs
.flags_fs
& DN_IS_RED
) {
1540 if (pipe
.fs
.min_th
>= pipe
.fs
.max_th
)
1541 show_usage("min_th %d must be < than max_th %d",
1542 pipe
.fs
.min_th
, pipe
.fs
.max_th
);
1543 if (pipe
.fs
.max_th
== 0)
1544 show_usage("max_th must be > 0");
1545 if (pipe
.bandwidth
) {
1547 int lookup_depth
, avg_pkt_size
;
1548 double s
, idle
, weight
, w_q
;
1549 struct clockinfo clock
;
1553 if (sysctlbyname("net.inet.ip.dummynet.red_lookup_depth",
1554 &lookup_depth
, &len
, NULL
, 0) == -1)
1556 errx(1, "sysctlbyname(\"%s\")",
1557 "net.inet.ip.dummynet.red_lookup_depth");
1558 if (lookup_depth
== 0)
1559 show_usage("net.inet.ip.dummynet.red_lookup_depth must"
1560 "greater than zero");
1563 if (sysctlbyname("net.inet.ip.dummynet.red_avg_pkt_size",
1564 &avg_pkt_size
, &len
, NULL
, 0) == -1)
1566 errx(1, "sysctlbyname(\"%s\")",
1567 "net.inet.ip.dummynet.red_avg_pkt_size");
1568 if (avg_pkt_size
== 0)
1569 show_usage("net.inet.ip.dummynet.red_avg_pkt_size must"
1570 "greater than zero");
1572 len
= sizeof(struct clockinfo
);
1573 if (sysctlbyname("kern.clockrate",
1574 &clock
, &len
, NULL
, 0) == -1)
1575 errx(1, "sysctlbyname(\"%s\")", "kern.clockrate");
1577 /* ticks needed for sending a medium-sized packet */
1578 s
= clock
.hz
* avg_pkt_size
* 8 / pipe
.bandwidth
;
1581 * max idle time (in ticks) before avg queue size becomes 0.
1582 * NOTA: (3/w_q) is approx the value x so that
1583 * (1-w_q)^x < 10^-3.
1585 w_q
= ((double) pipe
.fs
.w_q
) / (1 << SCALE_RED
);
1586 idle
= s
* 3. / w_q
;
1587 pipe
.fs
.lookup_step
= (int) idle
/ lookup_depth
;
1588 if (!pipe
.fs
.lookup_step
)
1589 pipe
.fs
.lookup_step
= 1;
1591 for (t
= pipe
.fs
.lookup_step
; t
> 0; --t
)
1593 pipe
.fs
.lookup_weight
= (int) (weight
* (1 << SCALE_RED
));
1597 printf("configuring pipe %d bw %d delay %d size %d\n",
1598 pipe
.pipe_nr
, pipe
.bandwidth
, pipe
.delay
, pipe
.queue_size
);
1600 i
= setsockopt(s
,IPPROTO_IP
, IP_DUMMYNET_CONFIGURE
, &pipe
, sizeof pipe
);
1602 err(1, "setsockopt(%s)", "IP_DUMMYNET_CONFIGURE");
1605 #endif /* DUMMYNET */
1615 struct protoent
*pe
;
1616 int saw_xmrc
= 0, saw_via
= 0;
1618 memset(&rule
, 0, sizeof rule
);
1619 rule
.version
= IP_FW_CURRENT_API_VERSION
;
1624 if (ac
&& isdigit(**av
)) {
1625 rule
.fw_number
= atoi(*av
); av
++; ac
--;
1629 if (ac
> 1 && !strncmp(*av
, "prob", strlen(*av
))) {
1630 double d
= strtod(av
[1], NULL
);
1631 if (d
<= 0 || d
> 1)
1632 show_usage("illegal match prob. %s", av
[1]);
1633 if (d
!= 1) { /* 1 means always match */
1634 rule
.fw_flg
|= IP_FW_F_RND_MATCH
;
1635 /* we really store dont_match probability */
1636 (long)rule
.pipe_ptr
= (long)((1 - d
) * 0x7fffffff);
1642 show_usage("missing action");
1643 if (!strncmp(*av
, "accept", strlen(*av
))
1644 || !strncmp(*av
, "pass" ,strlen(*av
))
1645 || !strncmp(*av
, "allow", strlen(*av
))
1646 || !strncmp(*av
, "permit", strlen(*av
))) {
1647 rule
.fw_flg
|= IP_FW_F_ACCEPT
; av
++; ac
--;
1648 } else if (!strncmp(*av
, "count", strlen(*av
))) {
1649 rule
.fw_flg
|= IP_FW_F_COUNT
; av
++; ac
--;
1652 else if (!strncmp(*av
, "pipe", strlen(*av
))) {
1653 rule
.fw_flg
|= IP_FW_F_PIPE
; av
++; ac
--;
1655 show_usage("missing pipe number");
1656 rule
.fw_divert_port
= strtoul(*av
, NULL
, 0); av
++; ac
--;
1657 } else if (!strncmp(*av
, "queue", strlen(*av
))) {
1658 rule
.fw_flg
|= IP_FW_F_QUEUE
; av
++; ac
--;
1660 show_usage("missing queue number");
1661 rule
.fw_divert_port
= strtoul(*av
, NULL
, 0); av
++; ac
--;
1663 #endif /* DUMMYNET */
1664 else if (!strncmp(*av
, "divert", strlen(*av
))) {
1665 rule
.fw_flg
|= IP_FW_F_DIVERT
; av
++; ac
--;
1667 show_usage("missing %s port", "divert");
1668 rule
.fw_divert_port
= strtoul(*av
, NULL
, 0); av
++; ac
--;
1669 if (rule
.fw_divert_port
== 0) {
1672 s
= getservbyname(av
[-1], "divert");
1674 rule
.fw_divert_port
= ntohs(s
->s_port
);
1676 show_usage("illegal %s port", "divert");
1678 } else if (!strncmp(*av
, "tee", strlen(*av
))) {
1679 rule
.fw_flg
|= IP_FW_F_TEE
; av
++; ac
--;
1681 show_usage("missing %s port", "tee divert");
1682 rule
.fw_divert_port
= strtoul(*av
, NULL
, 0); av
++; ac
--;
1683 if (rule
.fw_divert_port
== 0) {
1686 s
= getservbyname(av
[-1], "divert");
1688 rule
.fw_divert_port
= ntohs(s
->s_port
);
1690 show_usage("illegal %s port", "tee divert");
1692 } else if (!strncmp(*av
, "fwd", strlen(*av
)) ||
1693 !strncmp(*av
, "forward", strlen(*av
))) {
1694 struct in_addr dummyip
;
1696 rule
.fw_flg
|= IP_FW_F_FWD
; av
++; ac
--;
1698 show_usage("missing forwarding IP address");
1699 rule
.fw_fwd_ip
.sin_len
= sizeof(struct sockaddr_in
);
1700 rule
.fw_fwd_ip
.sin_family
= AF_INET
;
1701 rule
.fw_fwd_ip
.sin_port
= 0;
1702 pp
= strchr(*av
, ':');
1704 pp
= strchr(*av
, ',');
1708 i
= lookup_port(pp
, 0, 1, 0);
1710 show_usage("illegal forwarding port ``%s''", pp
);
1712 rule
.fw_fwd_ip
.sin_port
= (u_short
)i
;
1714 fill_ip(&(rule
.fw_fwd_ip
.sin_addr
), &dummyip
, &ac
, &av
);
1715 if (rule
.fw_fwd_ip
.sin_addr
.s_addr
== 0)
1716 show_usage("illegal forwarding IP address");
1718 } else if (!strncmp(*av
, "skipto", strlen(*av
))) {
1719 rule
.fw_flg
|= IP_FW_F_SKIPTO
; av
++; ac
--;
1721 show_usage("missing skipto rule number");
1722 rule
.fw_skipto_rule
= strtoul(*av
, NULL
, 0); av
++; ac
--;
1723 } else if ((!strncmp(*av
, "deny", strlen(*av
))
1724 || !strncmp(*av
, "drop", strlen(*av
)))) {
1725 rule
.fw_flg
|= IP_FW_F_DENY
; av
++; ac
--;
1726 } else if (!strncmp(*av
, "reject", strlen(*av
))) {
1727 rule
.fw_flg
|= IP_FW_F_REJECT
; av
++; ac
--;
1728 rule
.fw_reject_code
= ICMP_UNREACH_HOST
;
1729 } else if (!strncmp(*av
, "reset", strlen(*av
))) {
1730 rule
.fw_flg
|= IP_FW_F_REJECT
; av
++; ac
--;
1731 rule
.fw_reject_code
= IP_FW_REJECT_RST
; /* check TCP later */
1732 } else if (!strncmp(*av
, "unreach", strlen(*av
))) {
1733 rule
.fw_flg
|= IP_FW_F_REJECT
; av
++; ac
--;
1734 fill_reject_code(&rule
.fw_reject_code
, *av
); av
++; ac
--;
1735 } else if (!strncmp(*av
, "check-state", strlen(*av
))) {
1736 rule
.fw_flg
|= IP_FW_F_CHECK_S
; av
++; ac
--;
1739 show_usage("invalid action ``%s''", *av
);
1743 if (ac
&& !strncmp(*av
, "log", strlen(*av
))) {
1744 rule
.fw_flg
|= IP_FW_F_PRN
; av
++; ac
--;
1746 if (ac
&& !strncmp(*av
, "logamount", strlen(*av
))) {
1747 if (!(rule
.fw_flg
& IP_FW_F_PRN
))
1748 show_usage("``logamount'' not valid without ``log''");
1751 show_usage("``logamount'' requires argument");
1752 rule
.fw_logamount
= atoi(*av
);
1753 if (rule
.fw_logamount
< 0)
1754 show_usage("``logamount'' argument must be positive");
1755 if (rule
.fw_logamount
== 0)
1756 rule
.fw_logamount
= -1;
1762 show_usage("missing protocol");
1763 if ((proto
= atoi(*av
)) > 0) {
1764 rule
.fw_prot
= proto
; av
++; ac
--;
1765 } else if (!strncmp(*av
, "all", strlen(*av
))) {
1766 rule
.fw_prot
= IPPROTO_IP
; av
++; ac
--;
1767 } else if ((pe
= getprotobyname(*av
)) != NULL
) {
1768 rule
.fw_prot
= pe
->p_proto
; av
++; ac
--;
1770 show_usage("invalid protocol ``%s''", *av
);
1773 if (rule
.fw_prot
!= IPPROTO_TCP
1774 && (rule
.fw_flg
& IP_FW_F_COMMAND
) == IP_FW_F_REJECT
1775 && rule
.fw_reject_code
== IP_FW_REJECT_RST
)
1776 show_usage("``reset'' is only valid for tcp packets");
1779 if (ac
&& !strncmp(*av
, "from", strlen(*av
))) { av
++; ac
--; }
1781 show_usage("missing ``from''");
1783 if (ac
&& !strncmp(*av
, "not", strlen(*av
))) {
1784 rule
.fw_flg
|= IP_FW_F_INVSRC
;
1788 show_usage("missing arguments");
1790 if (ac
&& !strncmp(*av
, "me", strlen(*av
))) {
1791 rule
.fw_flg
|= IP_FW_F_SME
;
1794 fill_ip(&rule
.fw_src
, &rule
.fw_smsk
, &ac
, &av
);
1797 if (ac
&& (isdigit(**av
) || lookup_port(*av
, rule
.fw_prot
, 1, 1) >= 0)) {
1801 retval
= fill_port(&nports
, rule
.fw_uar
.fw_pts
, 0, *av
, rule
.fw_prot
);
1803 rule
.fw_flg
|= IP_FW_F_SRNG
;
1804 else if (retval
== 2)
1805 rule
.fw_flg
|= IP_FW_F_SMSK
;
1806 IP_FW_SETNSRCP(&rule
, nports
);
1811 if (ac
&& !strncmp(*av
, "to", strlen(*av
))) { av
++; ac
--; }
1813 show_usage("missing ``to''");
1815 if (ac
&& !strncmp(*av
, "not", strlen(*av
))) {
1816 rule
.fw_flg
|= IP_FW_F_INVDST
;
1820 show_usage("missing arguments");
1822 if (ac
&& !strncmp(*av
, "me", strlen(*av
))) {
1823 rule
.fw_flg
|= IP_FW_F_DME
;
1826 fill_ip(&rule
.fw_dst
, &rule
.fw_dmsk
, &ac
, &av
);
1829 if (ac
&& (isdigit(**av
) || lookup_port(*av
, rule
.fw_prot
, 1, 1) >= 0)) {
1833 retval
= fill_port(&nports
,
1834 rule
.fw_uar
.fw_pts
, IP_FW_GETNSRCP(&rule
), *av
, rule
.fw_prot
);
1836 rule
.fw_flg
|= IP_FW_F_DRNG
;
1837 else if (retval
== 2)
1838 rule
.fw_flg
|= IP_FW_F_DMSK
;
1839 IP_FW_SETNDSTP(&rule
, nports
);
1843 if ((rule
.fw_prot
!= IPPROTO_TCP
) && (rule
.fw_prot
!= IPPROTO_UDP
)
1844 && (IP_FW_GETNSRCP(&rule
) || IP_FW_GETNDSTP(&rule
))) {
1845 show_usage("only TCP and UDP protocols are valid"
1846 " with port specifications");
1850 if (!strncmp(*av
, "uid", strlen(*av
))) {
1855 rule
.fw_flg
|= IP_FW_F_UID
;
1858 show_usage("``uid'' requires argument");
1860 uid
= strtoul(*av
, &end
, 0);
1862 pwd
= getpwuid(uid
);
1864 pwd
= getpwnam(*av
);
1866 show_usage("uid \"%s\" is nonexistant", *av
);
1867 rule
.fw_uid
= pwd
->pw_uid
;
1871 if (!strncmp(*av
, "in", strlen(*av
))) {
1872 rule
.fw_flg
|= IP_FW_F_IN
;
1873 av
++; ac
--; continue;
1875 if (!strncmp(*av
, "keep-state", strlen(*av
))) {
1877 rule
.fw_flg
|= IP_FW_F_KEEP_S
;
1880 if (ac
> 0 && (type
= atoi(*av
)) != 0) {
1881 (int)rule
.next_rule_ptr
= type
;
1886 if (!strncmp(*av
, "bridged", strlen(*av
))) {
1887 rule
.fw_flg
|= IP_FW_BRIDGED
;
1888 av
++; ac
--; continue;
1890 if (!strncmp(*av
, "out", strlen(*av
))) {
1891 rule
.fw_flg
|= IP_FW_F_OUT
;
1892 av
++; ac
--; continue;
1894 if (ac
&& !strncmp(*av
, "xmit", strlen(*av
))) {
1900 show_usage("``via'' is incompatible"
1901 " with ``xmit'' and ``recv''");
1905 fill_iface("xmit", &ifu
, &byname
, ac
, *av
);
1906 rule
.fw_out_if
= ifu
;
1907 rule
.fw_flg
|= IP_FW_F_OIFACE
;
1909 rule
.fw_flg
|= IP_FW_F_OIFNAME
;
1910 av
++; ac
--; continue;
1912 if (ac
&& !strncmp(*av
, "recv", strlen(*av
))) {
1920 fill_iface("recv", &ifu
, &byname
, ac
, *av
);
1921 rule
.fw_in_if
= ifu
;
1922 rule
.fw_flg
|= IP_FW_F_IIFACE
;
1924 rule
.fw_flg
|= IP_FW_F_IIFNAME
;
1925 av
++; ac
--; continue;
1927 if (ac
&& !strncmp(*av
, "via", strlen(*av
))) {
1935 fill_iface("via", &ifu
, &byname
, ac
, *av
);
1936 rule
.fw_out_if
= rule
.fw_in_if
= ifu
;
1939 (IP_FW_F_IIFNAME
| IP_FW_F_OIFNAME
);
1940 av
++; ac
--; continue;
1942 if (!strncmp(*av
, "fragment", strlen(*av
))) {
1943 rule
.fw_flg
|= IP_FW_F_FRAG
;
1944 av
++; ac
--; continue;
1946 if (!strncmp(*av
, "ipoptions", strlen(*av
))) {
1949 show_usage("missing argument"
1950 " for ``ipoptions''");
1951 fill_ipopt(&rule
.fw_ipopt
, &rule
.fw_ipnopt
, av
);
1952 av
++; ac
--; continue;
1954 if (rule
.fw_prot
== IPPROTO_TCP
) {
1955 if (!strncmp(*av
, "established", strlen(*av
))) {
1956 rule
.fw_ipflg
|= IP_FW_IF_TCPEST
;
1957 av
++; ac
--; continue;
1959 if (!strncmp(*av
, "setup", strlen(*av
))) {
1960 rule
.fw_tcpf
|= IP_FW_TCPF_SYN
;
1961 rule
.fw_tcpnf
|= IP_FW_TCPF_ACK
;
1962 av
++; ac
--; continue;
1964 if (!strncmp(*av
, "tcpflags", strlen(*av
)) ||
1965 !strncmp(*av
, "tcpflgs", strlen(*av
))) {
1968 show_usage("missing argument"
1969 " for ``tcpflags''");
1970 fill_tcpflag(&rule
.fw_tcpf
, &rule
.fw_tcpnf
, av
);
1971 av
++; ac
--; continue;
1973 if (!strncmp(*av
, "tcpoptions", strlen(*av
)) ||
1974 !strncmp(*av
, "tcpopts", strlen(*av
))) {
1977 show_usage("missing argument"
1978 " for ``tcpoptions''");
1979 fill_tcpopts(&rule
.fw_tcpopt
, &rule
.fw_tcpnopt
, av
);
1980 av
++; ac
--; continue;
1983 if (rule
.fw_prot
== IPPROTO_ICMP
) {
1984 if (!strncmp(*av
, "icmptypes", strlen(*av
))) {
1987 show_usage("missing argument"
1988 " for ``icmptypes''");
1989 fill_icmptypes(rule
.fw_uar
.fw_icmptypes
,
1991 av
++; ac
--; continue;
1994 show_usage("unknown argument ``%s''", *av
);
1997 /* No direction specified -> do both directions */
1998 if (!(rule
.fw_flg
& (IP_FW_F_OUT
|IP_FW_F_IN
)))
1999 rule
.fw_flg
|= (IP_FW_F_OUT
|IP_FW_F_IN
);
2001 /* Sanity check interface check, but handle "via" case separately */
2003 if (rule
.fw_flg
& IP_FW_F_IN
)
2004 rule
.fw_flg
|= IP_FW_F_IIFACE
;
2005 if (rule
.fw_flg
& IP_FW_F_OUT
)
2006 rule
.fw_flg
|= IP_FW_F_OIFACE
;
2007 } else if ((rule
.fw_flg
& IP_FW_F_OIFACE
) && (rule
.fw_flg
& IP_FW_F_IN
))
2008 show_usage("can't check xmit interface of incoming packets");
2010 /* frag may not be used in conjunction with ports or TCP flags */
2011 if (rule
.fw_flg
& IP_FW_F_FRAG
) {
2012 if (rule
.fw_tcpf
|| rule
.fw_tcpnf
)
2013 show_usage("can't mix 'frag' and tcpflags");
2016 show_usage("can't mix 'frag' and port specifications");
2018 if (rule
.fw_flg
& IP_FW_F_PRN
) {
2019 if (!rule
.fw_logamount
) {
2020 size_t len
= sizeof(int);
2022 if (sysctlbyname("net.inet.ip.fw.verbose_limit",
2023 &rule
.fw_logamount
, &len
, NULL
, 0) == -1)
2024 errx(1, "sysctlbyname(\"%s\")",
2025 "net.inet.ip.fw.verbose_limit");
2026 } else if (rule
.fw_logamount
== -1)
2027 rule
.fw_logamount
= 0;
2028 rule
.fw_loghighest
= rule
.fw_logamount
;
2032 if (getsockopt(s
, IPPROTO_IP
, IP_FW_ADD
, &rule
, &i
) == -1)
2033 err(EX_UNAVAILABLE
, "getsockopt(%s)", "IP_FW_ADD");
2035 show_ipfw(&rule
, 10, 10);
2044 memset(&rule
, 0, sizeof rule
);
2045 rule
.version
= IP_FW_CURRENT_API_VERSION
;
2050 /* clear all entries */
2051 if (setsockopt(s
, IPPROTO_IP
, IP_FW_ZERO
, &rule
, sizeof rule
) < 0)
2052 err(EX_UNAVAILABLE
, "setsockopt(%s)", "IP_FW_ZERO");
2054 printf("Accounting cleared.\n");
2060 if (isdigit(**av
)) {
2061 rule
.fw_number
= atoi(*av
); av
++; ac
--;
2062 if (setsockopt(s
, IPPROTO_IP
,
2063 IP_FW_ZERO
, &rule
, sizeof rule
)) {
2064 warn("rule %u: setsockopt(%s)", rule
.fw_number
,
2066 failed
= EX_UNAVAILABLE
;
2069 printf("Entry %d cleared\n",
2072 show_usage("invalid rule number ``%s''", *av
);
2074 if (failed
!= EX_OK
)
2085 memset(&rule
, 0, sizeof rule
);
2086 rule
.version
= IP_FW_CURRENT_API_VERSION
;
2091 /* clear all entries */
2092 if (setsockopt(s
, IPPROTO_IP
, IP_FW_RESETLOG
, &rule
, sizeof rule
) < 0)
2093 err(EX_UNAVAILABLE
, "setsockopt(%s)", "IP_FW_RESETLOG");
2095 printf("Logging counts reset.\n");
2101 if (isdigit(**av
)) {
2102 rule
.fw_number
= atoi(*av
); av
++; ac
--;
2103 if (setsockopt(s
, IPPROTO_IP
,
2104 IP_FW_RESETLOG
, &rule
, sizeof rule
)) {
2105 warn("rule %u: setsockopt(%s)", rule
.fw_number
,
2107 failed
= EX_UNAVAILABLE
;
2110 printf("Entry %d logging count reset\n",
2113 show_usage("invalid rule number ``%s''", *av
);
2115 if (failed
!= EX_OK
)
2132 /* Set the force flag for non-interactive processes */
2133 do_force
= !isatty(STDIN_FILENO
);
2135 optind
= optreset
= 1;
2136 while ((ch
= getopt(ac
, av
, "s:afqtvN")) != -1)
2138 case 's': /* sort */
2139 do_sort
= atoi(optarg
);
2153 case 'v': /* verbose */
2164 if (*(av
+=optind
)==NULL
) {
2165 show_usage("bad arguments");
2169 if (!strncmp(*av
, "pipe", strlen(*av
))) {
2173 } else if (!strncmp(*av
, "queue", strlen(*av
))) {
2179 show_usage("pipe requires arguments");
2181 #endif /* DUMMYNET */
2183 /* allow argument swapping */
2184 if (ac
> 1 && *av
[0] >= '0' && *av
[0] <= '9') {
2189 if (!strncmp(*av
, "add", strlen(*av
))) {
2193 else if (do_pipe
&& !strncmp(*av
, "config", strlen(*av
))) {
2194 config_pipe(ac
, av
);
2196 #endif /* DUMMYNET */
2197 else if (!strncmp(*av
, "delete", strlen(*av
))) {
2199 } else if (!strncmp(*av
, "flush", strlen(*av
))) {
2202 if (do_force
|| do_quiet
)
2208 printf("Are you sure? [yn] ");
2211 c
= toupper(getc(stdin
));
2212 while (c
!= '\n' && getc(stdin
) != '\n')
2215 } while (c
!= 'Y' && c
!= 'N');
2226 error
= setsockopt(s
, IPPROTO_IP
, IP_DUMMYNET_FLUSH
, NULL
, 0);
2229 #endif /* DUMMYNET */
2232 memset(&rule
, 0, sizeof rule
);
2233 rule
.version
= IP_FW_CURRENT_API_VERSION
;
2234 error
= setsockopt(s
, IPPROTO_IP
, IP_FW_FLUSH
, &rule
, sizeof rule
);
2239 err(EX_UNAVAILABLE
, "setsockopt(IP_%s_FLUSH)",
2240 do_pipe
? "DUMMYNET" : "FW");
2241 #else /* DUMMYNET */
2242 err(EX_UNAVAILABLE
, "setsockopt(IP_FW_FLUSH)");
2243 #endif /* DUMMYNET */
2246 printf("Flushed all %s.\n",
2247 do_pipe
? "pipes" : "rules");
2248 #else /* DUMMYNET */
2249 printf("Flushed all rules.\n");
2250 #endif /* DUMMYNET */
2252 } else if (!strncmp(*av
, "zero", strlen(*av
))) {
2254 } else if (!strncmp(*av
, "resetlog", strlen(*av
))) {
2256 } else if (!strncmp(*av
, "print", strlen(*av
))) {
2258 } else if (!strncmp(*av
, "list", strlen(*av
))) {
2260 } else if (!strncmp(*av
, "show", strlen(*av
))) {
2264 show_usage("bad arguments");
2275 #define WHITESP " \t\f\v\n\r"
2277 char *a
, *p
, *args
[MAX_ARGS
], *cmd
= NULL
;
2279 int i
, c
, lineno
, qflag
, pflag
, status
;
2283 s
= socket(AF_INET
, SOCK_RAW
, IPPROTO_RAW
);
2285 err(EX_UNAVAILABLE
, "socket");
2290 * this is a nasty check on the last argument!!!
2291 * If there happens to be a filename matching a keyword in the current
2292 * directory, things will fail miserably.
2295 if (ac
> 1 && av
[ac
- 1][0] == '/' && access(av
[ac
- 1], R_OK
) == 0) {
2296 qflag
= pflag
= i
= 0;
2299 while ((c
= getopt(ac
, av
, "D:U:p:q")) != -1)
2303 errx(EX_USAGE
, "-D requires -p");
2304 if (i
> MAX_ARGS
- 2)
2306 "too many -D or -U options");
2313 errx(EX_USAGE
, "-U requires -p");
2314 if (i
> MAX_ARGS
- 2)
2316 "too many -D or -U options");
2339 show_usage("extraneous filename arguments");
2341 if ((f
= fopen(av
[0], "r")) == NULL
)
2342 err(EX_UNAVAILABLE
, "fopen: %s", av
[0]);
2345 /* pipe through preprocessor (cpp or m4) */
2350 if (pipe(pipedes
) == -1)
2351 err(EX_OSERR
, "cannot create pipe");
2353 switch((preproc
= fork())) {
2355 err(EX_OSERR
, "cannot fork");
2359 if (dup2(fileno(f
), 0) == -1
2360 || dup2(pipedes
[1], 1) == -1)
2361 err(EX_OSERR
, "dup2()");
2366 err(EX_OSERR
, "execvp(%s) failed", cmd
);
2372 if ((f
= fdopen(pipedes
[0], "r")) == NULL
) {
2373 int savederrno
= errno
;
2375 (void)kill(preproc
, SIGTERM
);
2377 err(EX_OSERR
, "fdopen()");
2382 while (fgets(buf
, BUFSIZ
, f
)) {
2384 sprintf(linename
, "Line %d", lineno
);
2389 if ((p
= strchr(buf
, '#')) != NULL
)
2394 for (a
= strtok(buf
, WHITESP
);
2395 a
&& i
< MAX_ARGS
; a
= strtok(NULL
, WHITESP
), i
++)
2397 if (i
== (qflag
? 2: 1))
2400 errx(EX_USAGE
, "%s: too many arguments",
2408 if (waitpid(preproc
, &status
, 0) == -1)
2409 errx(EX_OSERR
, "waitpid()");
2410 if (WIFEXITED(status
) && WEXITSTATUS(status
) != EX_OK
)
2411 errx(EX_UNAVAILABLE
,
2412 "preprocessor exited with status %d",
2413 WEXITSTATUS(status
));
2414 else if (WIFSIGNALED(status
))
2415 errx(EX_UNAVAILABLE
,
2416 "preprocessor exited with signal %d",