2 * Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp
3 * Copyright (c) 1994 Ugen J.S.Antsilevich
5 * Idea and grammar partially left from:
6 * Copyright (c) 1993 Daniel Boulet
8 * Redistribution and use in source forms, with and without modification,
9 * are permitted provided that this entire comment appears intact.
11 * Redistribution in binary form may occur without any restrictions.
12 * Obviously, it would be nice if you gave credit where credit is due
13 * but requiring it would be too onerous.
15 * This software is provided ``AS IS'' without any warranties of any kind.
17 * NEW command line interface for IP firewall facility
19 * $FreeBSD: src/sbin/ipfw/ipfw.c,v 1.80.2.26 2003/01/14 19:15:58 dillon Exp $
20 * $DragonFly: src/sbin/ipfw/ipfw.c,v 1.8 2006/06/25 11:02:37 corecode Exp $
23 #include <sys/param.h>
25 #include <sys/socket.h>
26 #include <sys/sockio.h>
27 #include <sys/sysctl.h>
47 #include <netinet/in.h>
48 #include <netinet/in_systm.h>
49 #include <netinet/ip.h>
50 #include <netinet/ip_icmp.h>
51 #include <net/ipfw/ip_fw.h>
52 #include <net/route.h> /* def. of struct route */
53 #include <net/dummynet/ip_dummynet.h>
54 #include <netinet/tcp.h>
55 #include <arpa/inet.h>
57 int s
, /* main RAW socket */
58 do_resolv
, /* Would try to resolve all */
59 do_acct
, /* Show packet/byte count */
60 do_time
, /* Show time stamps */
61 do_quiet
, /* Be quiet in add and flush */
62 do_force
, /* Don't ask for confirmation */
63 do_pipe
, /* this cmd refers to a pipe */
64 do_sort
, /* field to sort results (0 = no) */
65 do_dynamic
, /* display dynamic rules */
66 do_expired
, /* display expired dynamic rules */
74 static struct icmpcode icmpcodes
[] = {
75 { ICMP_UNREACH_NET
, "net" },
76 { ICMP_UNREACH_HOST
, "host" },
77 { ICMP_UNREACH_PROTOCOL
, "protocol" },
78 { ICMP_UNREACH_PORT
, "port" },
79 { ICMP_UNREACH_NEEDFRAG
, "needfrag" },
80 { ICMP_UNREACH_SRCFAIL
, "srcfail" },
81 { ICMP_UNREACH_NET_UNKNOWN
, "net-unknown" },
82 { ICMP_UNREACH_HOST_UNKNOWN
, "host-unknown" },
83 { ICMP_UNREACH_ISOLATED
, "isolated" },
84 { ICMP_UNREACH_NET_PROHIB
, "net-prohib" },
85 { ICMP_UNREACH_HOST_PROHIB
, "host-prohib" },
86 { ICMP_UNREACH_TOSNET
, "tosnet" },
87 { ICMP_UNREACH_TOSHOST
, "toshost" },
88 { ICMP_UNREACH_FILTER_PROHIB
, "filter-prohib" },
89 { ICMP_UNREACH_HOST_PRECEDENCE
, "host-precedence" },
90 { ICMP_UNREACH_PRECEDENCE_CUTOFF
, "precedence-cutoff" },
94 static void show_usage(void);
97 mask_bits(struct in_addr m_ad
)
99 int h_fnd
= 0, h_num
= 0, i
;
102 mask
= ntohl(m_ad
.s_addr
);
103 for (i
= 0; i
< sizeof(u_long
)*CHAR_BIT
; i
++) {
117 print_port(u_char prot
, u_short port
, const char comma
)
119 struct servent
*se
= NULL
;
123 printf("%c0x%04x", comma
, port
);
127 pe
= getprotobynumber(prot
);
128 se
= getservbyport(htons(port
), pe
? pe
->p_name
: NULL
);
131 printf("%c%s", comma
, se
->s_name
);
133 printf("%c%d", comma
, port
);
137 print_iface(char *key
, union ip_fw_if
*un
, int byname
)
140 printf(" %s %s", key
, un
->fu_via_if
.name
);
141 } else if (un
->fu_via_ip
.s_addr
!= 0) {
142 printf(" %s %s", key
, inet_ntoa(un
->fu_via_ip
));
144 printf(" %s any", key
);
148 print_reject_code(int code
)
152 for (ic
= icmpcodes
; ic
->str
; ic
++)
153 if (ic
->code
== code
) {
154 printf("%s", ic
->str
);
161 * _s_x holds a string-int pair for various lookups.
162 * s=NULL terminates the struct.
164 struct _s_x
{ char *s
; int x
; };
165 static struct _s_x limit_masks
[] = {
166 {"src-addr", DYN_SRC_ADDR
},
167 {"src-port", DYN_SRC_PORT
},
168 {"dst-addr", DYN_DST_ADDR
},
169 {"dst-port", DYN_DST_PORT
},
173 show_ipfw(struct ip_fw
*chain
, int pcwidth
, int bcwidth
)
175 static int twidth
= 0;
181 int nsp
= IP_FW_GETNSRCP(chain
);
182 int ndp
= IP_FW_GETNDSTP(chain
);
185 setservent(1/*stay open*/);
187 printf("%05u ", chain
->fw_number
);
190 printf("%*qu %*qu ", pcwidth
, chain
->fw_pcnt
, bcwidth
, chain
->fw_bcnt
);
198 strcpy(timestr
, ctime(&zerotime
));
199 *strchr(timestr
, '\n') = '\0';
200 twidth
= strlen(timestr
);
202 if (chain
->timestamp
) {
203 strcpy(timestr
, ctime((time_t *)&chain
->timestamp
));
204 *strchr(timestr
, '\n') = '\0';
205 printf("%s ", timestr
);
207 printf("%*s ", twidth
, " ");
210 if (chain
->fw_flg
== IP_FW_F_CHECK_S
) {
211 printf("check-state\n");
215 if (chain
->fw_flg
& IP_FW_F_RND_MATCH
) {
216 double d
= 1.0 * chain
->dont_match_prob
;
217 d
= 1 - (d
/ 0x7fffffff);
218 printf("prob %f ", d
);
221 switch (chain
->fw_flg
& IP_FW_F_COMMAND
) {
232 printf("divert %u", chain
->fw_divert_port
);
235 printf("tee %u", chain
->fw_divert_port
);
238 printf("skipto %u", chain
->fw_skipto_rule
);
241 printf("pipe %u", chain
->fw_skipto_rule
);
244 printf("queue %u", chain
->fw_skipto_rule
);
247 if (chain
->fw_reject_code
== IP_FW_REJECT_RST
)
251 print_reject_code(chain
->fw_reject_code
);
255 printf("fwd %s", inet_ntoa(chain
->fw_fwd_ip
.sin_addr
));
256 if(chain
->fw_fwd_ip
.sin_port
)
257 printf(",%d", chain
->fw_fwd_ip
.sin_port
);
260 errx(EX_OSERR
, "impossible");
263 if (chain
->fw_flg
& IP_FW_F_PRN
) {
265 if (chain
->fw_logamount
)
266 printf(" logamount %d", chain
->fw_logamount
);
269 pe
= getprotobynumber(chain
->fw_prot
);
271 printf(" %s", pe
->p_name
);
273 printf(" %u", chain
->fw_prot
);
275 printf(" from %s", chain
->fw_flg
& IP_FW_F_INVSRC
? "not " : "");
277 if (chain
->fw_flg
& IP_FW_F_SME
) {
281 adrt
= ntohl(chain
->fw_smsk
.s_addr
);
282 if (adrt
== ULONG_MAX
&& do_resolv
) {
283 adrt
= (chain
->fw_src
.s_addr
);
284 he
= gethostbyaddr((char *)&adrt
,
285 sizeof(u_long
), AF_INET
);
287 printf("%s", inet_ntoa(chain
->fw_src
));
289 printf("%s", he
->h_name
);
290 } else if (adrt
!= ULONG_MAX
) {
291 mb
= mask_bits(chain
->fw_smsk
);
295 printf("%s", inet_ntoa(chain
->fw_src
));
298 printf("%s", inet_ntoa(chain
->fw_src
));
300 printf("%s", inet_ntoa(chain
->fw_smsk
));
303 printf("%s", inet_ntoa(chain
->fw_src
));
307 if (chain
->fw_prot
== IPPROTO_TCP
|| chain
->fw_prot
== IPPROTO_UDP
) {
309 for (i
= 0; i
< nsp
; i
++) {
310 print_port(chain
->fw_prot
,
311 chain
->fw_uar
.fw_pts
[i
], comma
);
312 if (i
== 0 && (chain
->fw_flg
& IP_FW_F_SRNG
))
314 else if (i
== 0 && (chain
->fw_flg
& IP_FW_F_SMSK
))
321 printf(" to %s", chain
->fw_flg
& IP_FW_F_INVDST
? "not " : "");
323 if (chain
->fw_flg
& IP_FW_F_DME
) {
326 adrt
= ntohl(chain
->fw_dmsk
.s_addr
);
327 if (adrt
== ULONG_MAX
&& do_resolv
) {
328 adrt
= (chain
->fw_dst
.s_addr
);
329 he
= gethostbyaddr((char *)&adrt
,
330 sizeof(u_long
), AF_INET
);
332 printf("%s", inet_ntoa(chain
->fw_dst
));
334 printf("%s", he
->h_name
);
335 } else if (adrt
!= ULONG_MAX
) {
336 mb
= mask_bits(chain
->fw_dmsk
);
340 printf("%s", inet_ntoa(chain
->fw_dst
));
343 printf("%s", inet_ntoa(chain
->fw_dst
));
345 printf("%s", inet_ntoa(chain
->fw_dmsk
));
348 printf("%s", inet_ntoa(chain
->fw_dst
));
352 if (chain
->fw_prot
== IPPROTO_TCP
|| chain
->fw_prot
== IPPROTO_UDP
) {
354 for (i
= 0; i
< ndp
; i
++) {
355 print_port(chain
->fw_prot
,
356 chain
->fw_uar
.fw_pts
[nsp
+i
], comma
);
357 if (i
== 0 && (chain
->fw_flg
& IP_FW_F_DRNG
))
359 else if (i
== 0 && (chain
->fw_flg
& IP_FW_F_DMSK
))
366 if (chain
->fw_flg
& IP_FW_F_UID
) {
367 struct passwd
*pwd
= getpwuid(chain
->fw_uid
);
370 printf(" uid %s", pwd
->pw_name
);
372 printf(" uid %u", chain
->fw_uid
);
375 if (chain
->fw_flg
& IP_FW_F_GID
) {
376 struct group
*grp
= getgrgid(chain
->fw_gid
);
379 printf(" gid %s", grp
->gr_name
);
381 printf(" gid %u", chain
->fw_gid
);
384 if (chain
->fw_flg
& IP_FW_F_KEEP_S
) {
385 struct _s_x
*p
= limit_masks
;
387 switch(chain
->dyn_type
) {
389 printf(" *** unknown type ***");
392 printf(" keep-state");
396 for ( ; p
->s
!= NULL
; p
++)
397 if (chain
->limit_mask
& p
->x
)
399 printf(" %d", chain
->conn_limit
);
404 if ((chain
->fw_flg
& IP_FW_F_IN
) && !(chain
->fw_flg
& IP_FW_F_OUT
))
406 if (!(chain
->fw_flg
& IP_FW_F_IN
) && (chain
->fw_flg
& IP_FW_F_OUT
))
409 /* Handle hack for "via" backwards compatibility */
410 if ((chain
->fw_flg
& IF_FW_F_VIAHACK
) == IF_FW_F_VIAHACK
) {
412 &chain
->fw_in_if
, chain
->fw_flg
& IP_FW_F_IIFNAME
);
414 /* Receive interface specified */
415 if (chain
->fw_flg
& IP_FW_F_IIFACE
)
416 print_iface("recv", &chain
->fw_in_if
,
417 chain
->fw_flg
& IP_FW_F_IIFNAME
);
418 /* Transmit interface specified */
419 if (chain
->fw_flg
& IP_FW_F_OIFACE
)
420 print_iface("xmit", &chain
->fw_out_if
,
421 chain
->fw_flg
& IP_FW_F_OIFNAME
);
424 if (chain
->fw_flg
& IP_FW_F_FRAG
)
427 if (chain
->fw_ipopt
|| chain
->fw_ipnopt
) {
428 int _opt_printed
= 0;
429 #define PRINTOPT(x) {if (_opt_printed) printf(",");\
430 printf(x); _opt_printed = 1;}
433 if (chain
->fw_ipopt
& IP_FW_IPOPT_SSRR
)
435 if (chain
->fw_ipnopt
& IP_FW_IPOPT_SSRR
)
437 if (chain
->fw_ipopt
& IP_FW_IPOPT_LSRR
)
439 if (chain
->fw_ipnopt
& IP_FW_IPOPT_LSRR
)
441 if (chain
->fw_ipopt
& IP_FW_IPOPT_RR
)
443 if (chain
->fw_ipnopt
& IP_FW_IPOPT_RR
)
445 if (chain
->fw_ipopt
& IP_FW_IPOPT_TS
)
447 if (chain
->fw_ipnopt
& IP_FW_IPOPT_TS
)
451 if (chain
->fw_ipflg
& IP_FW_IF_TCPEST
)
452 printf(" established");
453 else if (chain
->fw_tcpf
== IP_FW_TCPF_SYN
&&
454 chain
->fw_tcpnf
== IP_FW_TCPF_ACK
)
456 else if (chain
->fw_tcpf
|| chain
->fw_tcpnf
) {
457 int _flg_printed
= 0;
458 #define PRINTFLG(x) {if (_flg_printed) printf(",");\
459 printf(x); _flg_printed = 1;}
461 printf(" tcpflags ");
462 if (chain
->fw_tcpf
& IP_FW_TCPF_FIN
)
464 if (chain
->fw_tcpnf
& IP_FW_TCPF_FIN
)
466 if (chain
->fw_tcpf
& IP_FW_TCPF_SYN
)
468 if (chain
->fw_tcpnf
& IP_FW_TCPF_SYN
)
470 if (chain
->fw_tcpf
& IP_FW_TCPF_RST
)
472 if (chain
->fw_tcpnf
& IP_FW_TCPF_RST
)
474 if (chain
->fw_tcpf
& IP_FW_TCPF_PSH
)
476 if (chain
->fw_tcpnf
& IP_FW_TCPF_PSH
)
478 if (chain
->fw_tcpf
& IP_FW_TCPF_ACK
)
480 if (chain
->fw_tcpnf
& IP_FW_TCPF_ACK
)
482 if (chain
->fw_tcpf
& IP_FW_TCPF_URG
)
484 if (chain
->fw_tcpnf
& IP_FW_TCPF_URG
)
487 if (chain
->fw_tcpopt
|| chain
->fw_tcpnopt
) {
488 int _opt_printed
= 0;
489 #define PRINTTOPT(x) {if (_opt_printed) printf(",");\
490 printf(x); _opt_printed = 1;}
492 printf(" tcpoptions ");
493 if (chain
->fw_tcpopt
& IP_FW_TCPOPT_MSS
)
495 if (chain
->fw_tcpnopt
& IP_FW_TCPOPT_MSS
)
497 if (chain
->fw_tcpopt
& IP_FW_TCPOPT_WINDOW
)
499 if (chain
->fw_tcpnopt
& IP_FW_TCPOPT_WINDOW
)
500 PRINTTOPT("!window");
501 if (chain
->fw_tcpopt
& IP_FW_TCPOPT_SACK
)
503 if (chain
->fw_tcpnopt
& IP_FW_TCPOPT_SACK
)
505 if (chain
->fw_tcpopt
& IP_FW_TCPOPT_TS
)
507 if (chain
->fw_tcpnopt
& IP_FW_TCPOPT_TS
)
509 if (chain
->fw_tcpopt
& IP_FW_TCPOPT_CC
)
511 if (chain
->fw_tcpnopt
& IP_FW_TCPOPT_CC
)
515 if (chain
->fw_flg
& IP_FW_F_ICMPBIT
) {
521 for (type_index
= 0; type_index
< IP_FW_ICMPTYPES_DIM
* sizeof(unsigned) * 8; ++type_index
)
522 if (chain
->fw_uar
.fw_icmptypes
[type_index
/ (sizeof(unsigned) * 8)] &
523 (1U << (type_index
% (sizeof(unsigned) * 8)))) {
524 printf("%c%d", first
== 1 ? ' ' : ',', type_index
);
535 sort_q(const void *pa
, const void *pb
)
537 int rev
= (do_sort
< 0);
538 int field
= rev
? -do_sort
: do_sort
;
540 const struct dn_flow_queue
*a
= pa
;
541 const struct dn_flow_queue
*b
= pb
;
545 res
= a
->len
- b
->len
;
548 res
= a
->len_bytes
- b
->len_bytes
;
551 case 3: /* tot pkts */
552 res
= a
->tot_pkts
- b
->tot_pkts
;
555 case 4: /* tot bytes */
556 res
= a
->tot_bytes
- b
->tot_bytes
;
563 return (int)(rev
? res
: -res
);
567 list_queues(struct dn_flow_set
*fs
, struct dn_flow_queue
*q
)
571 printf(" mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n",
573 fs
->flow_mask
.src_ip
, fs
->flow_mask
.src_port
,
574 fs
->flow_mask
.dst_ip
, fs
->flow_mask
.dst_port
);
575 if (fs
->rq_elements
== 0)
578 printf("BKT Prot ___Source IP/port____ "
579 "____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp\n");
581 heapsort(q
, fs
->rq_elements
, sizeof *q
, sort_q
);
582 for (l
= 0; l
< fs
->rq_elements
; l
++) {
586 ina
.s_addr
= htonl(q
[l
].id
.src_ip
);
587 printf("%3d ", q
[l
].hash_slot
);
588 pe
= getprotobynumber(q
[l
].id
.proto
);
590 printf("%-4s ", pe
->p_name
);
592 printf("%4u ", q
[l
].id
.proto
);
594 inet_ntoa(ina
), q
[l
].id
.src_port
);
595 ina
.s_addr
= htonl(q
[l
].id
.dst_ip
);
597 inet_ntoa(ina
), q
[l
].id
.dst_port
);
598 printf("%4qu %8qu %2u %4u %3u\n",
599 q
[l
].tot_pkts
, q
[l
].tot_bytes
,
600 q
[l
].len
, q
[l
].len_bytes
, q
[l
].drops
);
602 printf(" S %20qd F %20qd\n",
608 print_flowset_parms(struct dn_flow_set
*fs
, char *prefix
)
613 char red
[90]; /* Display RED parameters */
616 if (fs
->flags_fs
& DN_QSIZE_IS_BYTES
) {
618 sprintf(qs
, "%d KB", l
/ 1024);
620 sprintf(qs
, "%d B", l
);
622 sprintf(qs
, "%3d sl.", l
);
624 sprintf(plr
, "plr %f", 1.0 * fs
->plr
/ (double)(0x7fffffff));
627 if (fs
->flags_fs
& DN_IS_RED
) /* RED parameters */
629 "\n\t %cRED w_q %f min_th %d max_th %d max_p %f",
630 (fs
->flags_fs
& DN_IS_GENTLE_RED
) ? 'G' : ' ',
631 1.0 * fs
->w_q
/ (double)(1 << SCALE_RED
),
632 SCALE_VAL(fs
->min_th
),
633 SCALE_VAL(fs
->max_th
),
634 1.0 * fs
->max_p
/ (double)(1 << SCALE_RED
));
636 sprintf(red
, "droptail");
638 printf("%s %s%s %d queues (%d buckets) %s\n",
639 prefix
, qs
, plr
, fs
->rq_elements
, fs
->rq_size
, red
);
643 sysctl_handler(int ac
, char *av
[], int which
)
649 warnx("missing keyword to enable/disable\n");
650 } else if (strncmp(*av
, "firewall", strlen(*av
)) == 0) {
651 sysctlbyname("net.inet.ip.fw.enable", NULL
, 0,
652 &which
, sizeof(which
));
653 } else if (strncmp(*av
, "one_pass", strlen(*av
)) == 0) {
654 sysctlbyname("net.inet.ip.fw.one_pass", NULL
, 0,
655 &which
, sizeof(which
));
656 } else if (strncmp(*av
, "debug", strlen(*av
)) == 0) {
657 sysctlbyname("net.inet.ip.fw.debug", NULL
, 0,
658 &which
, sizeof(which
));
659 } else if (strncmp(*av
, "verbose", strlen(*av
)) == 0) {
660 sysctlbyname("net.inet.ip.fw.verbose", NULL
, 0,
661 &which
, sizeof(which
));
663 warnx("unrecognize enable/disable keyword: %s\n", *av
);
668 list(int ac
, char *av
[])
671 struct dn_pipe
*pipes
;
678 /* get rules or pipes from kernel, resizing array as necessary */
680 const int unit
= do_pipe
? sizeof(*pipes
) : sizeof(*rules
);
681 const int ocmd
= do_pipe
? IP_DUMMYNET_GET
: IP_FW_GET
;
685 while (nbytes
>= nalloc
) {
686 nalloc
= nalloc
* 2 + 200;
688 if ((data
= realloc(data
, nbytes
)) == NULL
)
689 err(EX_OSERR
, "realloc");
690 if (getsockopt(s
, IPPROTO_IP
, ocmd
, data
, &nbytes
) < 0)
691 err(EX_OSERR
, "getsockopt(IP_%s_GET)",
692 do_pipe
? "DUMMYNET" : "FW");
696 /* display requested pipes */
700 struct dn_pipe
*p
= (struct dn_pipe
*) data
;
701 struct dn_flow_set
*fs
;
702 struct dn_flow_queue
*q
;
706 rulenum
= strtoul(*av
++, NULL
, 10);
709 for (; nbytes
>= sizeof *p
; p
= (struct dn_pipe
*)next
) {
710 double b
= p
->bandwidth
;
714 if (p
->next
!= (struct dn_pipe
*)DN_IS_PIPE
)
716 l
= sizeof(*p
) + p
->fs
.rq_elements
* sizeof(*q
);
717 next
= (void *)p
+ l
;
719 q
= (struct dn_flow_queue
*)(p
+1);
721 if (rulenum
!= 0 && rulenum
!= p
->pipe_nr
)
723 if (p
->if_name
[0] != '\0')
724 sprintf(buf
, "%s", p
->if_name
);
726 sprintf(buf
, "unlimited");
727 else if (b
>= 1000000)
728 sprintf(buf
, "%7.3f Mbit/s", b
/1000000);
730 sprintf(buf
, "%7.3f Kbit/s", b
/1000);
732 sprintf(buf
, "%7.3f bit/s ", b
);
734 sprintf(prefix
, "%05d: %s %4d ms ",
735 p
->pipe_nr
, buf
, p
->delay
);
736 print_flowset_parms(&(p
->fs
), prefix
);
738 printf(" V %20qd\n", p
->V
>> MY_M
);
739 list_queues(&(p
->fs
), q
);
741 fs
= (struct dn_flow_set
*) next
;
742 for (; nbytes
>= sizeof *fs
; fs
= (struct dn_flow_set
*)next
) {
745 if (fs
->next
!= (struct dn_flow_set
*)DN_IS_QUEUE
)
747 l
= sizeof(*fs
) + fs
->rq_elements
* sizeof(*q
);
748 next
= (void *)fs
+ l
;
750 q
= (struct dn_flow_queue
*)(fs
+1);
751 sprintf(prefix
, "q%05d: weight %d pipe %d ",
752 fs
->fs_nr
, fs
->weight
, fs
->parent_nr
);
753 print_flowset_parms(fs
, prefix
);
760 rules
= (struct ip_fw
*)data
;
761 /* determine num more accurately */
763 while (rules
[num
].fw_number
< 65535)
765 num
++; /* counting starts from 0 ... */
766 /* if showing stats, figure out column widths ahead of time */
768 for (n
= 0; n
< num
; n
++) {
769 struct ip_fw
*const r
= &rules
[n
];
774 width
= sprintf(temp
, "%qu", r
->fw_pcnt
);
779 width
= sprintf(temp
, "%qu", r
->fw_bcnt
);
785 /* display all rules */
786 for (n
= 0; n
< num
; n
++) {
787 struct ip_fw
*const r
= &rules
[n
];
789 show_ipfw(r
, pcwidth
, bcwidth
);
792 /* display specific rules requested on command line */
800 /* convert command line rule # */
801 rnum
= strtoul(*av
++, &endptr
, 10);
804 warnx("invalid rule number: %s", *(av
- 1));
808 for (seen
= n
= 0; n
< num
; n
++) {
809 struct ip_fw
*const r
= &rules
[n
];
811 if (r
->fw_number
> rnum
)
813 if (r
->fw_number
== rnum
) {
814 show_ipfw(r
, pcwidth
, bcwidth
);
819 /* give precedence to other error(s) */
820 if (exitval
== EX_OK
)
821 exitval
= EX_UNAVAILABLE
;
822 warnx("rule %lu does not exist", rnum
);
825 if (exitval
!= EX_OK
)
831 if (do_dynamic
&& num
* sizeof (rules
[0]) != nbytes
) {
832 struct ipfw_dyn_rule
*d
=
833 (struct ipfw_dyn_rule
*)&rules
[num
];
837 printf("## Dynamic rules:\n");
839 if (d
->expire
== 0 && !do_expired
) {
845 printf("%05d %qu %qu (T %d, slot %d)",
850 switch (d
->dyn_type
) {
851 case DYN_LIMIT_PARENT
:
852 printf(" PARENT %d", d
->count
);
857 case DYN_KEEP_STATE
: /* bidir, no mask */
862 pe
= getprotobynumber(d
->id
.proto
);
864 printf(" %s,", pe
->p_name
);
866 printf(" %u,", d
->id
.proto
);
867 a
.s_addr
= htonl(d
->id
.src_ip
);
868 printf(" %s %d", inet_ntoa(a
), d
->id
.src_port
);
869 a
.s_addr
= htonl(d
->id
.dst_ip
);
870 printf("<-> %s %d", inet_ntoa(a
), d
->id
.dst_port
);
883 fprintf(stderr
, "usage: ipfw [options]\n"
885 " add [number] rule\n"
886 " [pipe] delete number ...\n"
887 " [pipe] list [number ...]\n"
888 " [pipe] show [number ...]\n"
889 " zero [number ...]\n"
890 " resetlog [number ...]\n"
891 " pipe number config [pipeconfig]\n"
892 " rule: [prob <match_probability>] action proto src dst extras...\n"
894 " {allow|permit|accept|pass|deny|drop|reject|unreach code|\n"
895 " reset|count|skipto num|divert port|tee port|fwd ip|\n"
896 " pipe num} [log [logamount count]]\n"
897 " proto: {ip|tcp|udp|icmp|<number>}\n"
898 " src: from [not] {me|any|ip[{/bits|:mask}]} [{port[-port]}, [port], ...]\n"
899 " dst: to [not] {me|any|ip[{/bits|:mask}]} [{port[-port]}, [port], ...]\n"
903 " fragment (may not be used with ports or tcpflags)\n"
906 " {xmit|recv|via} {iface|ip|any}\n"
907 " {established|setup}\n"
908 " tcpflags [!]{syn|fin|rst|ack|psh|urg}, ...\n"
909 " ipoptions [!]{ssrr|lsrr|rr|ts}, ...\n"
910 " tcpoptions [!]{mss|window|sack|ts|cc}, ...\n"
911 " icmptypes {type[, type]}...\n"
912 " keep-state [method]\n"
914 " {bw|bandwidth} <number>{bit/s|Kbit/s|Mbit/s|Bytes/s|KBytes/s|MBytes/s}\n"
915 " {bw|bandwidth} interface_name\n"
916 " delay <milliseconds>\n"
917 " queue <size>{packets|Bytes|KBytes}\n"
919 " mask {all| [dst-ip|src-ip|dst-port|src-port|proto] <number>}\n"
920 " buckets <number>}\n"
921 " {red|gred} <fraction>/<number>/<number>/<fraction>\n"
929 lookup_host (char *host
, struct in_addr
*ipaddr
)
933 if (!inet_aton(host
, ipaddr
)) {
934 if ((he
= gethostbyname(host
)) == NULL
)
936 *ipaddr
= *(struct in_addr
*)he
->h_addr_list
[0];
942 fill_ip(struct in_addr
*ipno
, struct in_addr
*mask
, int *acp
, char ***avp
)
948 if (ac
&& !strncmp(*av
, "any", strlen(*av
))) {
949 ipno
->s_addr
= mask
->s_addr
= 0; av
++; ac
--;
951 p
= strchr(*av
, '/');
953 p
= strchr(*av
, ':');
959 if (lookup_host(*av
, ipno
) != 0)
960 errx(EX_NOHOST
, "hostname ``%s'' unknown", *av
);
963 if (!inet_aton(p
, mask
))
964 errx(EX_DATAERR
, "bad netmask ``%s''", p
);
969 } else if (atoi(p
) > 32) {
970 errx(EX_DATAERR
, "bad width ``%s''", p
);
973 htonl(~0 << (32 - atoi(p
)));
977 mask
->s_addr
= htonl(~0);
980 ipno
->s_addr
&= mask
->s_addr
;
989 fill_reject_code(u_short
*codep
, char *str
)
996 errx(EX_DATAERR
, "missing unreachable code");
997 val
= strtoul(str
, &s
, 0);
998 if (s
!= str
&& *s
== '\0' && val
< 0x100) {
1002 for (ic
= icmpcodes
; ic
->str
; ic
++)
1003 if (!strcasecmp(str
, ic
->str
)) {
1007 errx(EX_DATAERR
, "unknown ICMP unreachable code ``%s''", str
);
1011 add_port(u_short
*cnt
, u_short
*ptr
, u_short off
, u_short port
)
1013 if (off
+ *cnt
>= IP_FW_MAX_PORTS
)
1014 errx(EX_USAGE
, "too many ports (max is %d)", IP_FW_MAX_PORTS
);
1015 ptr
[off
+*cnt
] = port
;
1020 lookup_port(const char *arg
, int proto
, int test
, int nodash
)
1023 char *earg
, buf
[32];
1027 snprintf(buf
, sizeof(buf
), "%s", arg
);
1029 for (p
= q
= buf
; *p
; *q
++ = *p
++) {
1034 if (*p
== ',' || (nodash
&& *p
== '-'))
1040 val
= (int) strtoul(buf
, &earg
, 0);
1041 if (!*buf
|| *earg
) {
1042 char *protocol
= NULL
;
1045 struct protoent
*pe
= getprotobynumber(proto
);
1048 protocol
= pe
->p_name
;
1052 if ((s
= getservbyname(buf
, protocol
))) {
1053 val
= htons(s
->s_port
);
1056 errx(EX_DATAERR
, "unknown port ``%s''", buf
);
1060 if (val
< 0 || val
> 0xffff) {
1063 "port ``%s'' out of range", buf
);
1071 * return: 0 normally, 1 if first pair is a range,
1072 * 2 if first pair is a port+mask
1075 fill_port(u_short
*cnt
, u_short
*ptr
, u_short off
, char *arg
, int proto
)
1078 int initial_range
= 0;
1080 for (s
= arg
; *s
&& *s
!= ',' && *s
!= '-' && *s
!= ':'; s
++) {
1081 if (*s
== '\\' && *(s
+1))
1086 if (strchr(arg
, ','))
1087 errx(EX_USAGE
, "port/mask must be first in list");
1088 add_port(cnt
, ptr
, off
,
1089 *arg
? lookup_port(arg
, proto
, 0, 0) : 0x0000);
1091 s
= strchr(arg
, ',');
1094 add_port(cnt
, ptr
, off
,
1095 *arg
? lookup_port(arg
, proto
, 0, 0) : 0xffff);
1101 if (strchr(arg
, ','))
1102 errx(EX_USAGE
, "port range must be first in list");
1103 add_port(cnt
, ptr
, off
,
1104 *arg
? lookup_port(arg
, proto
, 0, 0) : 0x0000);
1106 s
= strchr(arg
, ',');
1109 add_port(cnt
, ptr
, off
,
1110 *arg
? lookup_port(arg
, proto
, 0, 0) : 0xffff);
1114 while (arg
!= NULL
) {
1115 s
= strchr(arg
, ',');
1118 add_port(cnt
, ptr
, off
, lookup_port(arg
, proto
, 0, 0));
1121 return initial_range
;
1125 fill_tcpflag(u_char
*set
, u_char
*reset
, char **vp
)
1135 { "syn", IP_FW_TCPF_SYN
},
1136 { "fin", IP_FW_TCPF_FIN
},
1137 { "ack", IP_FW_TCPF_ACK
},
1138 { "psh", IP_FW_TCPF_PSH
},
1139 { "rst", IP_FW_TCPF_RST
},
1140 { "urg", IP_FW_TCPF_URG
}
1153 for (i
= 0; i
< sizeof(flags
) / sizeof(flags
[0]); ++i
)
1154 if (!strncmp(p
, flags
[i
].name
, strlen(p
))) {
1155 *d
|= flags
[i
].value
;
1158 if (i
== sizeof(flags
) / sizeof(flags
[0]))
1159 errx(EX_DATAERR
, "invalid tcp flag ``%s''", p
);
1165 fill_tcpopts(u_char
*set
, u_char
*reset
, char **vp
)
1175 { "mss", IP_FW_TCPOPT_MSS
},
1176 { "window", IP_FW_TCPOPT_WINDOW
},
1177 { "sack", IP_FW_TCPOPT_SACK
},
1178 { "ts", IP_FW_TCPOPT_TS
},
1179 { "cc", IP_FW_TCPOPT_CC
},
1192 for (i
= 0; i
< sizeof(opts
) / sizeof(opts
[0]); ++i
)
1193 if (!strncmp(p
, opts
[i
].name
, strlen(p
))) {
1194 *d
|= opts
[i
].value
;
1197 if (i
== sizeof(opts
) / sizeof(opts
[0]))
1198 errx(EX_DATAERR
, "invalid tcp option ``%s''", p
);
1204 fill_ipopt(u_char
*set
, u_char
*reset
, char **vp
)
1219 if (!strncmp(p
, "ssrr", strlen(p
))) *d
|= IP_FW_IPOPT_SSRR
;
1220 if (!strncmp(p
, "lsrr", strlen(p
))) *d
|= IP_FW_IPOPT_LSRR
;
1221 if (!strncmp(p
, "rr", strlen(p
))) *d
|= IP_FW_IPOPT_RR
;
1222 if (!strncmp(p
, "ts", strlen(p
))) *d
|= IP_FW_IPOPT_TS
;
1228 fill_icmptypes(unsigned *types
, char **vp
, u_int
*fw_flg
)
1230 unsigned long icmptype
;
1237 icmptype
= strtoul(c
, &c
, 0);
1239 if (*c
!= ',' && *c
!= '\0')
1240 errx(EX_DATAERR
, "invalid ICMP type");
1242 if (icmptype
>= IP_FW_ICMPTYPES_DIM
* sizeof(unsigned) * 8)
1243 errx(EX_DATAERR
, "ICMP type out of range");
1245 types
[icmptype
/ (sizeof(unsigned) * 8)] |=
1246 1 << (icmptype
% (sizeof(unsigned) * 8));
1247 *fw_flg
|= IP_FW_F_ICMPBIT
;
1252 delete(int ac
, char *av
[])
1255 struct dn_pipe pipe
;
1257 int exitval
= EX_OK
;
1259 memset(&rule
, 0, sizeof rule
);
1260 memset(&pipe
, 0, sizeof pipe
);
1265 while (ac
&& isdigit(**av
)) {
1266 i
= atoi(*av
); av
++; ac
--;
1272 i
= setsockopt(s
, IPPROTO_IP
, IP_DUMMYNET_DEL
,
1273 &pipe
, sizeof pipe
);
1276 warn("rule %u: setsockopt(IP_DUMMYNET_DEL)",
1277 do_pipe
== 1 ? pipe
.pipe_nr
:
1282 i
= setsockopt(s
, IPPROTO_IP
, IP_FW_DEL
, &rule
,
1285 exitval
= EX_UNAVAILABLE
;
1286 warn("rule %u: setsockopt(IP_FW_DEL)",
1291 if (exitval
!= EX_OK
)
1296 verify_interface(union ip_fw_if
*ifu
)
1300 strlcpy(ifr
.ifr_name
, ifu
->fu_via_if
.name
, sizeof(ifr
.ifr_name
));
1302 if (ioctl(s
, SIOCGIFFLAGS
, &ifr
) < 0)
1303 warnx("warning: interface ``%s'' does not exist",
1308 fill_iface(char *which
, union ip_fw_if
*ifu
, int *byname
, int ac
, char *arg
)
1311 errx(EX_USAGE
, "missing argument for ``%s''", which
);
1313 /* Parse the interface or address */
1314 if (!strcmp(arg
, "any")) {
1315 ifu
->fu_via_ip
.s_addr
= 0;
1317 } else if (!isdigit(*arg
)) {
1319 strlcpy(ifu
->fu_via_if
.name
, arg
, sizeof(ifu
->fu_via_if
.name
));
1321 * We assume that strings containing '*', '?', or '['
1322 * are meant to be shell pattern.
1324 if (strpbrk(arg
, "*?[") != NULL
) {
1325 ifu
->fu_via_if
.glob
= 1;
1327 ifu
->fu_via_if
.glob
= 0;
1328 verify_interface(ifu
);
1330 } else if (!inet_aton(arg
, &ifu
->fu_via_ip
)) {
1331 errx(EX_DATAERR
, "bad ip address ``%s''", arg
);
1336 static unsigned long
1337 getbw(const char *str
, u_short
*flags
, int kb
)
1343 val
= strtoul(str
, &end
, 0);
1344 if (*end
== 'k' || *end
== 'K') {
1347 } else if (*end
== 'm' || *end
== 'M') {
1353 * Deal with bits or bytes or b(bits) or B(bytes). If there is no
1354 * trailer assume bits.
1356 if (strncasecmp(end
, "bit", 3) == 0) {
1358 } else if (strncasecmp(end
, "byte", 4) == 0) {
1360 } else if (*end
== 'b') {
1362 } else if (*end
== 'B') {
1367 * Return in bits if flags is NULL, else flag bits
1368 * or bytes in flags and return the unconverted value.
1370 if (inbytes
&& flags
)
1371 *flags
|= DN_QSIZE_IS_BYTES
;
1372 else if (inbytes
&& flags
== NULL
)
1378 config_pipe(int ac
, char **av
)
1380 struct dn_pipe pipe
;
1384 memset(&pipe
, 0, sizeof pipe
);
1388 if (ac
&& isdigit(**av
)) {
1389 i
= atoi(*av
); av
++; ac
--;
1396 if (!strncmp(*av
, "plr", strlen(*av
))) {
1398 double d
= strtod(av
[1], NULL
);
1403 pipe
.fs
.plr
= (int)(d
*0x7fffffff);
1406 } else if (!strncmp(*av
, "queue", strlen(*av
))) {
1407 pipe
.fs
.qsize
= getbw(av
[1], &pipe
.fs
.flags_fs
, 1024);
1410 } else if (!strncmp(*av
, "buckets", strlen(*av
))) {
1411 pipe
.fs
.rq_size
= strtoul(av
[1], NULL
, 0);
1414 } else if (!strncmp(*av
, "mask", strlen(*av
))) {
1415 /* per-flow queue, mask is dst_ip, dst_port,
1416 * src_ip, src_port, proto measured in bits
1421 pipe
.fs
.flow_mask
.dst_ip
= 0;
1422 pipe
.fs
.flow_mask
.src_ip
= 0;
1423 pipe
.fs
.flow_mask
.dst_port
= 0;
1424 pipe
.fs
.flow_mask
.src_port
= 0;
1425 pipe
.fs
.flow_mask
.proto
= 0;
1428 if (ac
>= 1 && !strncmp(*av
, "all", strlen(*av
))) {
1429 /* special case -- all bits are significant */
1430 pipe
.fs
.flow_mask
.dst_ip
= ~0;
1431 pipe
.fs
.flow_mask
.src_ip
= ~0;
1432 pipe
.fs
.flow_mask
.dst_port
= ~0;
1433 pipe
.fs
.flow_mask
.src_port
= ~0;
1434 pipe
.fs
.flow_mask
.proto
= ~0;
1435 pipe
.fs
.flags_fs
|= DN_HAVE_FLOW_MASK
;
1441 int len
= strlen(*av
);
1443 if (!strncmp(*av
, "dst-ip", len
))
1444 par
= &pipe
.fs
.flow_mask
.dst_ip
;
1445 else if (!strncmp(*av
, "src-ip", len
))
1446 par
= &pipe
.fs
.flow_mask
.src_ip
;
1447 else if (!strncmp(*av
, "dst-port", len
))
1448 par
= &pipe
.fs
.flow_mask
.dst_port
;
1449 else if (!strncmp(*av
, "src-port", len
))
1450 par
= &pipe
.fs
.flow_mask
.src_port
;
1451 else if (!strncmp(*av
, "proto", len
))
1452 par
= &pipe
.fs
.flow_mask
.proto
;
1456 errx(EX_USAGE
, "mask: %s value"
1458 if (*av
[1] == '/') {
1459 a
= strtoul(av
[1]+1, &end
, 0);
1460 if (a
== 32) /* special case... */
1464 fprintf(stderr
, " mask is 0x%08x\n", a
);
1466 a
= strtoul(av
[1], &end
, 0);
1468 if (par
== &pipe
.fs
.flow_mask
.src_port
1469 || par
== &pipe
.fs
.flow_mask
.dst_port
) {
1471 errx(EX_DATAERR
, "mask: %s"
1472 " must be 16 bit, not"
1474 *((u_int16_t
*)par
) = (u_int16_t
)a
;
1475 } else if (par
== &pipe
.fs
.flow_mask
.proto
) {
1477 errx(EX_DATAERR
, "mask: %s"
1479 " 8 bit, not 0x%08x",
1481 *((u_int8_t
*)par
) = (u_int8_t
)a
;
1483 *((u_int32_t
*)par
) = a
;
1485 pipe
.fs
.flags_fs
|= DN_HAVE_FLOW_MASK
;
1489 } else if (!strncmp(*av
, "red", strlen(*av
))
1490 || !strncmp(*av
, "gred", strlen(*av
))) {
1492 pipe
.fs
.flags_fs
|= DN_IS_RED
;
1494 pipe
.fs
.flags_fs
|= DN_IS_GENTLE_RED
;
1495 if ((end
= strsep(&av
[1], "/"))) {
1496 double w_q
= strtod(end
, NULL
);
1497 if (w_q
> 1 || w_q
<= 0)
1498 errx(EX_DATAERR
, "w_q %f must be "
1500 pipe
.fs
.w_q
= (int) (w_q
* (1 << SCALE_RED
));
1502 if ((end
= strsep(&av
[1], "/"))) {
1503 pipe
.fs
.min_th
= strtoul(end
, &end
, 0);
1504 if (*end
== 'K' || *end
== 'k')
1505 pipe
.fs
.min_th
*= 1024;
1507 if ((end
= strsep(&av
[1], "/"))) {
1508 pipe
.fs
.max_th
= strtoul(end
, &end
, 0);
1509 if (*end
== 'K' || *end
== 'k')
1510 pipe
.fs
.max_th
*= 1024;
1512 if ((end
= strsep(&av
[1], "/"))) {
1513 double max_p
= strtod(end
, NULL
);
1514 if (max_p
> 1 || max_p
<= 0)
1515 errx(EX_DATAERR
, "max_p %f must be "
1516 "0 < x <= 1", max_p
);
1518 (int)(max_p
* (1 << SCALE_RED
));
1522 } else if (!strncmp(*av
, "droptail", strlen(*av
))) {
1524 pipe
.fs
.flags_fs
&= ~(DN_IS_RED
|DN_IS_GENTLE_RED
);
1528 int len
= strlen(*av
);
1530 /* some commands are only good for pipes. */
1531 if (!strncmp(*av
, "bw", len
)
1532 || !strncmp(*av
, "bandwidth", len
)) {
1534 && av
[1][0] <= 'z') {
1535 int l
= sizeof(pipe
.if_name
)-1;
1536 /* interface name */
1537 strncpy(pipe
.if_name
, av
[1], l
);
1538 pipe
.if_name
[l
] = '\0';
1541 pipe
.if_name
[0] = '\0';
1543 getbw(av
[1], NULL
, 1000);
1545 if (pipe
.bandwidth
< 0)
1547 "bandwidth too large");
1550 } else if (!strncmp(*av
, "delay", len
)) {
1551 pipe
.delay
= strtoul(av
[1], NULL
, 0);
1555 errx(EX_DATAERR
, "unrecognised pipe"
1556 " option ``%s''", *av
);
1558 } else { /* this refers to a queue */
1559 if (!strncmp(*av
, "weight", len
)) {
1561 strtoul(av
[1], &end
, 0);
1564 } else if (!strncmp(*av
, "pipe", len
)) {
1566 strtoul(av
[1], &end
, 0);
1570 errx(EX_DATAERR
, "unrecognised option "
1577 if (pipe
.pipe_nr
== 0)
1578 errx(EX_DATAERR
, "pipe_nr %d must be > 0",
1580 if (pipe
.delay
> 10000)
1581 errx(EX_DATAERR
, "delay %d must be < 10000",
1583 } else { /* do_pipe == 2, queue */
1584 if (pipe
.fs
.parent_nr
== 0)
1585 errx(EX_DATAERR
, "pipe %d must be > 0",
1587 if (pipe
.fs
.weight
>100)
1588 errx(EX_DATAERR
, "weight %d must be <= 100",
1591 if (pipe
.fs
.flags_fs
& DN_QSIZE_IS_BYTES
) {
1592 if (pipe
.fs
.qsize
> 1024*1024)
1593 errx(EX_DATAERR
, "queue size %d, must be < 1MB",
1596 if (pipe
.fs
.qsize
> 100)
1597 errx(EX_DATAERR
, "queue size %d, must be"
1598 " 2 <= x <= 100", pipe
.fs
.qsize
);
1600 if (pipe
.fs
.flags_fs
& DN_IS_RED
) {
1602 int lookup_depth
, avg_pkt_size
;
1603 double s
, idle
, weight
, w_q
;
1604 struct clockinfo clock
;
1607 if (pipe
.fs
.min_th
>= pipe
.fs
.max_th
)
1608 errx(EX_DATAERR
, "min_th %d must be < than max_th %d",
1609 pipe
.fs
.min_th
, pipe
.fs
.max_th
);
1610 if (pipe
.fs
.max_th
== 0)
1611 errx(EX_DATAERR
, "max_th must be > 0");
1614 if (sysctlbyname("net.inet.ip.dummynet.red_lookup_depth",
1615 &lookup_depth
, &len
, NULL
, 0) == -1)
1617 errx(1, "sysctlbyname(\"%s\")",
1618 "net.inet.ip.dummynet.red_lookup_depth");
1619 if (lookup_depth
== 0)
1620 errx(EX_DATAERR
, "net.inet.ip.dummynet.red_lookup_depth"
1621 " must be greater than zero");
1624 if (sysctlbyname("net.inet.ip.dummynet.red_avg_pkt_size",
1625 &avg_pkt_size
, &len
, NULL
, 0) == -1)
1627 errx(1, "sysctlbyname(\"%s\")",
1628 "net.inet.ip.dummynet.red_avg_pkt_size");
1629 if (avg_pkt_size
== 0)
1631 "net.inet.ip.dummynet.red_avg_pkt_size must"
1632 " be greater than zero");
1634 len
= sizeof(struct clockinfo
);
1635 if (sysctlbyname("kern.clockrate", &clock
, &len
, NULL
, 0) == -1)
1636 errx(1, "sysctlbyname(\"%s\")",
1640 * Ticks needed for sending a medium-sized packet.
1641 * Unfortunately, when we are configuring a WF2Q+ queue, we
1642 * do not have bandwidth information, because that is stored
1643 * in the parent pipe, and also we have multiple queues
1644 * competing for it. So we set s=0, which is not very
1645 * correct. But on the other hand, why do we want RED with
1648 if (pipe
.bandwidth
==0) /* this is a WF2Q+ queue */
1651 s
= clock
.hz
* avg_pkt_size
* 8 / pipe
.bandwidth
;
1654 * max idle time (in ticks) before avg queue size
1656 * NOTA: (3/w_q) is approx the value x so that
1657 * (1-w_q)^x < 10^-3.
1659 w_q
= ((double)pipe
.fs
.w_q
) / (1 << SCALE_RED
);
1660 idle
= s
* 3. / w_q
;
1661 pipe
.fs
.lookup_step
= (int)idle
/ lookup_depth
;
1662 if (!pipe
.fs
.lookup_step
)
1663 pipe
.fs
.lookup_step
= 1;
1665 for (t
= pipe
.fs
.lookup_step
; t
> 0; --t
)
1667 pipe
.fs
.lookup_weight
= (int)(weight
* (1 << SCALE_RED
));
1669 i
= setsockopt(s
, IPPROTO_IP
, IP_DUMMYNET_CONFIGURE
, &pipe
,
1672 err(1, "setsockopt(%s)", "IP_DUMMYNET_CONFIGURE");
1676 add(int ac
, char *av
[])
1681 struct protoent
*pe
;
1682 int saw_xmrc
= 0, saw_via
= 0;
1684 memset(&rule
, 0, sizeof rule
);
1689 if (ac
&& isdigit(**av
)) {
1690 rule
.fw_number
= atoi(*av
); av
++; ac
--;
1694 if (ac
> 1 && !strncmp(*av
, "prob", strlen(*av
))) {
1695 double d
= strtod(av
[1], NULL
);
1696 if (d
<= 0 || d
> 1)
1697 errx(EX_DATAERR
, "illegal match prob. %s", av
[1]);
1698 if (d
!= 1) { /* 1 means always match */
1699 rule
.fw_flg
|= IP_FW_F_RND_MATCH
;
1700 rule
.dont_match_prob
= (long)((1 - d
) * 0x7fffffff);
1706 errx(EX_USAGE
, "missing action");
1707 if (!strncmp(*av
, "accept", strlen(*av
))
1708 || !strncmp(*av
, "pass", strlen(*av
))
1709 || !strncmp(*av
, "allow", strlen(*av
))
1710 || !strncmp(*av
, "permit", strlen(*av
))) {
1711 rule
.fw_flg
|= IP_FW_F_ACCEPT
; av
++; ac
--;
1712 } else if (!strncmp(*av
, "count", strlen(*av
))) {
1713 rule
.fw_flg
|= IP_FW_F_COUNT
; av
++; ac
--;
1714 } else if (!strncmp(*av
, "pipe", strlen(*av
))) {
1715 rule
.fw_flg
|= IP_FW_F_PIPE
; av
++; ac
--;
1717 errx(EX_USAGE
, "missing pipe number");
1718 rule
.fw_divert_port
= strtoul(*av
, NULL
, 0); av
++; ac
--;
1719 } else if (!strncmp(*av
, "queue", strlen(*av
))) {
1720 rule
.fw_flg
|= IP_FW_F_QUEUE
; av
++; ac
--;
1722 errx(EX_USAGE
, "missing queue number");
1723 rule
.fw_divert_port
= strtoul(*av
, NULL
, 0); av
++; ac
--;
1724 } else if (!strncmp(*av
, "divert", strlen(*av
))) {
1725 rule
.fw_flg
|= IP_FW_F_DIVERT
; av
++; ac
--;
1727 errx(EX_USAGE
, "missing %s port", "divert");
1728 rule
.fw_divert_port
= strtoul(*av
, NULL
, 0); av
++; ac
--;
1729 if (rule
.fw_divert_port
== 0) {
1732 s
= getservbyname(av
[-1], "divert");
1734 rule
.fw_divert_port
= ntohs(s
->s_port
);
1736 errx(EX_DATAERR
, "illegal %s port", "divert");
1738 } else if (!strncmp(*av
, "tee", strlen(*av
))) {
1739 rule
.fw_flg
|= IP_FW_F_TEE
; av
++; ac
--;
1741 errx(EX_USAGE
, "missing %s port", "tee divert");
1742 rule
.fw_divert_port
= strtoul(*av
, NULL
, 0); av
++; ac
--;
1743 if (rule
.fw_divert_port
== 0) {
1746 s
= getservbyname(av
[-1], "divert");
1748 rule
.fw_divert_port
= ntohs(s
->s_port
);
1750 errx(EX_DATAERR
, "illegal %s port",
1753 } else if (!strncmp(*av
, "fwd", strlen(*av
))
1754 || !strncmp(*av
, "forward", strlen(*av
))) {
1755 struct in_addr dummyip
;
1757 rule
.fw_flg
|= IP_FW_F_FWD
; av
++; ac
--;
1759 errx(EX_USAGE
, "missing forwarding IP address");
1760 rule
.fw_fwd_ip
.sin_len
= sizeof(struct sockaddr_in
);
1761 rule
.fw_fwd_ip
.sin_family
= AF_INET
;
1762 rule
.fw_fwd_ip
.sin_port
= 0;
1763 pp
= strchr(*av
, ':');
1765 pp
= strchr(*av
, ',');
1769 i
= lookup_port(pp
, 0, 1, 0);
1771 errx(EX_DATAERR
, "illegal forwarding"
1772 " port ``%s''", pp
);
1774 rule
.fw_fwd_ip
.sin_port
= (u_short
)i
;
1776 fill_ip(&(rule
.fw_fwd_ip
.sin_addr
), &dummyip
, &ac
, &av
);
1777 if (rule
.fw_fwd_ip
.sin_addr
.s_addr
== 0)
1778 errx(EX_DATAERR
, "illegal forwarding IP address");
1780 } else if (!strncmp(*av
, "skipto", strlen(*av
))) {
1781 rule
.fw_flg
|= IP_FW_F_SKIPTO
; av
++; ac
--;
1783 errx(EX_USAGE
, "missing skipto rule number");
1784 rule
.fw_skipto_rule
= strtoul(*av
, NULL
, 10); av
++; ac
--;
1785 } else if ((!strncmp(*av
, "deny", strlen(*av
))
1786 || !strncmp(*av
, "drop", strlen(*av
)))) {
1787 rule
.fw_flg
|= IP_FW_F_DENY
; av
++; ac
--;
1788 } else if (!strncmp(*av
, "reject", strlen(*av
))) {
1789 rule
.fw_flg
|= IP_FW_F_REJECT
; av
++; ac
--;
1790 rule
.fw_reject_code
= ICMP_UNREACH_HOST
;
1791 } else if (!strncmp(*av
, "reset", strlen(*av
))) {
1792 rule
.fw_flg
|= IP_FW_F_REJECT
; av
++; ac
--;
1793 rule
.fw_reject_code
= IP_FW_REJECT_RST
; /* check TCP later */
1794 } else if (!strncmp(*av
, "unreach", strlen(*av
))) {
1795 rule
.fw_flg
|= IP_FW_F_REJECT
; av
++; ac
--;
1796 fill_reject_code(&rule
.fw_reject_code
, *av
); av
++; ac
--;
1797 } else if (!strncmp(*av
, "check-state", strlen(*av
))) {
1798 rule
.fw_flg
|= IP_FW_F_CHECK_S
; av
++; ac
--;
1801 errx(EX_DATAERR
, "invalid action ``%s''", *av
);
1805 if (ac
&& !strncmp(*av
, "log", strlen(*av
))) {
1806 rule
.fw_flg
|= IP_FW_F_PRN
; av
++; ac
--;
1808 if (ac
&& !strncmp(*av
, "logamount", strlen(*av
))) {
1809 if (!(rule
.fw_flg
& IP_FW_F_PRN
))
1810 errx(EX_USAGE
, "``logamount'' not valid without"
1814 errx(EX_USAGE
, "``logamount'' requires argument");
1815 rule
.fw_logamount
= atoi(*av
);
1816 if (rule
.fw_logamount
< 0)
1817 errx(EX_DATAERR
, "``logamount'' argument must be"
1819 if (rule
.fw_logamount
== 0)
1820 rule
.fw_logamount
= -1;
1826 errx(EX_USAGE
, "missing protocol");
1827 if ((proto
= atoi(*av
)) > 0) {
1828 rule
.fw_prot
= proto
; av
++; ac
--;
1829 } else if (!strncmp(*av
, "all", strlen(*av
))) {
1830 rule
.fw_prot
= IPPROTO_IP
; av
++; ac
--;
1831 } else if ((pe
= getprotobyname(*av
)) != NULL
) {
1832 rule
.fw_prot
= pe
->p_proto
; av
++; ac
--;
1834 errx(EX_DATAERR
, "invalid protocol ``%s''", *av
);
1837 if (rule
.fw_prot
!= IPPROTO_TCP
1838 && (rule
.fw_flg
& IP_FW_F_COMMAND
) == IP_FW_F_REJECT
1839 && rule
.fw_reject_code
== IP_FW_REJECT_RST
)
1840 errx(EX_DATAERR
, "``reset'' is only valid for tcp packets");
1843 if (ac
&& !strncmp(*av
, "from", strlen(*av
))) { av
++; ac
--; }
1845 errx(EX_USAGE
, "missing ``from''");
1847 if (ac
&& !strncmp(*av
, "not", strlen(*av
))) {
1848 rule
.fw_flg
|= IP_FW_F_INVSRC
;
1852 errx(EX_USAGE
, "missing arguments");
1854 if (ac
&& !strncmp(*av
, "me", strlen(*av
))) {
1855 rule
.fw_flg
|= IP_FW_F_SME
;
1858 fill_ip(&rule
.fw_src
, &rule
.fw_smsk
, &ac
, &av
);
1861 if (ac
&& (isdigit(**av
)
1862 || lookup_port(*av
, rule
.fw_prot
, 1, 1) >= 0)) {
1866 retval
= fill_port(&nports
, rule
.fw_uar
.fw_pts
,
1867 0, *av
, rule
.fw_prot
);
1869 rule
.fw_flg
|= IP_FW_F_SRNG
;
1870 else if (retval
== 2)
1871 rule
.fw_flg
|= IP_FW_F_SMSK
;
1872 IP_FW_SETNSRCP(&rule
, nports
);
1877 if (ac
&& !strncmp(*av
, "to", strlen(*av
))) { av
++; ac
--; }
1879 errx(EX_USAGE
, "missing ``to''");
1881 if (ac
&& !strncmp(*av
, "not", strlen(*av
))) {
1882 rule
.fw_flg
|= IP_FW_F_INVDST
;
1886 errx(EX_USAGE
, "missing arguments");
1889 if (ac
&& !strncmp(*av
, "me", strlen(*av
))) {
1890 rule
.fw_flg
|= IP_FW_F_DME
;
1893 fill_ip(&rule
.fw_dst
, &rule
.fw_dmsk
, &ac
, &av
);
1896 if (ac
&& (isdigit(**av
)
1897 || lookup_port(*av
, rule
.fw_prot
, 1, 1) >= 0)) {
1901 retval
= fill_port(&nports
, rule
.fw_uar
.fw_pts
,
1902 IP_FW_GETNSRCP(&rule
), *av
, rule
.fw_prot
);
1904 rule
.fw_flg
|= IP_FW_F_DRNG
;
1905 else if (retval
== 2)
1906 rule
.fw_flg
|= IP_FW_F_DMSK
;
1907 IP_FW_SETNDSTP(&rule
, nports
);
1911 if ((rule
.fw_prot
!= IPPROTO_TCP
) && (rule
.fw_prot
!= IPPROTO_UDP
)
1912 && (IP_FW_GETNSRCP(&rule
) || IP_FW_GETNDSTP(&rule
))) {
1913 errx(EX_USAGE
, "only TCP and UDP protocols are valid"
1914 " with port specifications");
1918 if (!strncmp(*av
, "uid", strlen(*av
))) {
1923 rule
.fw_flg
|= IP_FW_F_UID
;
1926 errx(EX_USAGE
, "``uid'' requires argument");
1928 uid
= strtoul(*av
, &end
, 0);
1930 pwd
= getpwuid(uid
);
1932 pwd
= getpwnam(*av
);
1934 errx(EX_DATAERR
, "uid \"%s\" is"
1935 " nonexistent", *av
);
1936 rule
.fw_uid
= pwd
->pw_uid
;
1938 } else if (!strncmp(*av
, "gid", strlen(*av
))) {
1943 rule
.fw_flg
|= IP_FW_F_GID
;
1946 errx(EX_USAGE
, "``gid'' requires argument");
1948 gid
= strtoul(*av
, &end
, 0);
1950 grp
= getgrgid(gid
);
1952 grp
= getgrnam(*av
);
1954 errx(EX_DATAERR
, "gid \"%s\" is"
1955 " nonexistent", *av
);
1956 rule
.fw_gid
= grp
->gr_gid
;
1958 } else if (!strncmp(*av
, "in", strlen(*av
))) {
1959 rule
.fw_flg
|= IP_FW_F_IN
;
1961 } else if (!strncmp(*av
,"limit",strlen(*av
))) {
1962 /* dyn. rule used to limit number of connections. */
1963 rule
.fw_flg
|= IP_FW_F_KEEP_S
;
1964 rule
.dyn_type
= DYN_LIMIT
;
1965 rule
.limit_mask
= 0 ;
1968 struct _s_x
*p
= limit_masks
;
1969 for ( ; p
->s
!= NULL
; p
++)
1970 if (!strncmp(*av
, p
->s
, strlen(*av
))) {
1971 rule
.limit_mask
|= p
->x
;
1980 "limit needs mask and # of connections");
1981 rule
.conn_limit
= atoi(*av
);
1982 if (rule
.conn_limit
== 0)
1983 errx(EX_USAGE
, "limit: limit must be >0");
1984 if (rule
.limit_mask
== 0)
1985 errx(EX_USAGE
, "missing limit mask");
1987 } else if (!strncmp(*av
, "keep-state", strlen(*av
))) {
1989 rule
.fw_flg
|= IP_FW_F_KEEP_S
;
1992 if (ac
> 0 && (type
= atoi(*av
)) != 0) {
1993 rule
.dyn_type
= type
;
1996 } else if (!strncmp(*av
, "out", strlen(*av
))) {
1997 rule
.fw_flg
|= IP_FW_F_OUT
;
1999 } else if (ac
&& !strncmp(*av
, "xmit", strlen(*av
))) {
2005 errx(EX_USAGE
, "``via'' is incompatible"
2006 " with ``xmit'' and ``recv''");
2010 fill_iface("xmit", &ifu
, &byname
, ac
, *av
);
2011 rule
.fw_out_if
= ifu
;
2012 rule
.fw_flg
|= IP_FW_F_OIFACE
;
2014 rule
.fw_flg
|= IP_FW_F_OIFNAME
;
2016 } else if (ac
&& !strncmp(*av
, "recv", strlen(*av
))) {
2024 fill_iface("recv", &ifu
, &byname
, ac
, *av
);
2025 rule
.fw_in_if
= ifu
;
2026 rule
.fw_flg
|= IP_FW_F_IIFACE
;
2028 rule
.fw_flg
|= IP_FW_F_IIFNAME
;
2030 } else if (ac
&& !strncmp(*av
, "via", strlen(*av
))) {
2038 fill_iface("via", &ifu
, &byname
, ac
, *av
);
2039 rule
.fw_out_if
= rule
.fw_in_if
= ifu
;
2042 (IP_FW_F_IIFNAME
| IP_FW_F_OIFNAME
);
2044 } else if (!strncmp(*av
, "fragment", strlen(*av
))) {
2045 rule
.fw_flg
|= IP_FW_F_FRAG
;
2047 } else if (!strncmp(*av
, "ipoptions", strlen(*av
))) {
2050 errx(EX_USAGE
, "missing argument"
2051 " for ``ipoptions''");
2052 fill_ipopt(&rule
.fw_ipopt
, &rule
.fw_ipnopt
, av
);
2054 } else if (rule
.fw_prot
== IPPROTO_TCP
) {
2055 if (!strncmp(*av
, "established", strlen(*av
))) {
2056 rule
.fw_ipflg
|= IP_FW_IF_TCPEST
;
2058 } else if (!strncmp(*av
, "setup", strlen(*av
))) {
2059 rule
.fw_tcpf
|= IP_FW_TCPF_SYN
;
2060 rule
.fw_tcpnf
|= IP_FW_TCPF_ACK
;
2062 } else if (!strncmp(*av
, "tcpflags", strlen(*av
))
2063 || !strncmp(*av
, "tcpflgs", strlen(*av
))) {
2066 errx(EX_USAGE
, "missing argument"
2067 " for ``tcpflags''");
2068 fill_tcpflag(&rule
.fw_tcpf
,
2069 &rule
.fw_tcpnf
, av
);
2071 } else if (!strncmp(*av
, "tcpoptions", strlen(*av
))
2072 || !strncmp(*av
, "tcpopts", strlen(*av
))) {
2075 errx(EX_USAGE
, "missing argument"
2076 " for ``tcpoptions''");
2077 fill_tcpopts(&rule
.fw_tcpopt
,
2078 &rule
.fw_tcpnopt
, av
);
2081 errx(EX_USAGE
, "unknown or out of order"
2082 " argument ``%s''", *av
);
2084 } else if (rule
.fw_prot
== IPPROTO_ICMP
) {
2085 if (!strncmp(*av
, "icmptypes", strlen(*av
))) {
2088 errx(EX_USAGE
, "missing argument"
2089 " for ``icmptypes''");
2090 fill_icmptypes(rule
.fw_uar
.fw_icmptypes
,
2094 errx(EX_USAGE
, "unknown or out of order"
2095 " argument ``%s''", *av
);
2098 errx(EX_USAGE
, "unknown argument ``%s''", *av
);
2102 /* No direction specified -> do both directions */
2103 if (!(rule
.fw_flg
& (IP_FW_F_OUT
|IP_FW_F_IN
)))
2104 rule
.fw_flg
|= (IP_FW_F_OUT
|IP_FW_F_IN
);
2106 /* Sanity check interface check, but handle "via" case separately */
2108 if (rule
.fw_flg
& IP_FW_F_IN
)
2109 rule
.fw_flg
|= IP_FW_F_IIFACE
;
2110 if (rule
.fw_flg
& IP_FW_F_OUT
)
2111 rule
.fw_flg
|= IP_FW_F_OIFACE
;
2112 } else if ((rule
.fw_flg
& IP_FW_F_OIFACE
)
2113 && (rule
.fw_flg
& IP_FW_F_IN
)) {
2114 errx(EX_DATAERR
, "can't check xmit interface of incoming"
2118 /* frag may not be used in conjunction with ports or TCP flags */
2119 if (rule
.fw_flg
& IP_FW_F_FRAG
) {
2120 if (rule
.fw_tcpf
|| rule
.fw_tcpnf
)
2121 errx(EX_DATAERR
, "can't mix 'frag' and tcpflags");
2124 errx(EX_DATAERR
, "can't mix 'frag' and port"
2127 if (rule
.fw_flg
& IP_FW_F_PRN
) {
2128 if (!rule
.fw_logamount
) {
2129 size_t len
= sizeof(int);
2131 if (sysctlbyname("net.inet.ip.fw.verbose_limit",
2132 &rule
.fw_logamount
, &len
, NULL
, 0) == -1)
2133 errx(1, "sysctlbyname(\"%s\")",
2134 "net.inet.ip.fw.verbose_limit");
2135 } else if (rule
.fw_logamount
== -1)
2136 rule
.fw_logamount
= 0;
2137 rule
.fw_loghighest
= rule
.fw_logamount
;
2141 if (getsockopt(s
, IPPROTO_IP
, IP_FW_ADD
, &rule
, &i
) == -1)
2142 err(EX_UNAVAILABLE
, "getsockopt(%s)", "IP_FW_ADD");
2144 show_ipfw(&rule
, 10, 10);
2148 zero (int ac
, char *av
[])
2156 /* clear all entries */
2157 if (setsockopt(s
, IPPROTO_IP
, IP_FW_ZERO
, NULL
, 0) < 0)
2158 err(EX_UNAVAILABLE
, "setsockopt(%s)", "IP_FW_ZERO");
2160 printf("Accounting cleared.\n");
2165 memset(&rule
, 0, sizeof rule
);
2168 if (isdigit(**av
)) {
2169 rule
.fw_number
= atoi(*av
); av
++; ac
--;
2170 if (setsockopt(s
, IPPROTO_IP
,
2171 IP_FW_ZERO
, &rule
, sizeof rule
)) {
2172 warn("rule %u: setsockopt(IP_FW_ZERO)",
2174 failed
= EX_UNAVAILABLE
;
2175 } else if (!do_quiet
)
2176 printf("Entry %d cleared\n",
2179 errx(EX_USAGE
, "invalid rule number ``%s''", *av
);
2182 if (failed
!= EX_OK
)
2187 resetlog (int ac
, char *av
[])
2195 /* clear all entries */
2196 if (setsockopt(s
, IPPROTO_IP
, IP_FW_RESETLOG
, NULL
, 0) < 0)
2197 err(EX_UNAVAILABLE
, "setsockopt(IP_FW_RESETLOG)");
2199 printf("Logging counts reset.\n");
2204 memset(&rule
, 0, sizeof rule
);
2207 if (isdigit(**av
)) {
2208 rule
.fw_number
= atoi(*av
); av
++; ac
--;
2209 if (setsockopt(s
, IPPROTO_IP
,
2210 IP_FW_RESETLOG
, &rule
, sizeof rule
)) {
2211 warn("rule %u: setsockopt(IP_FW_RESETLOG)",
2213 failed
= EX_UNAVAILABLE
;
2214 } else if (!do_quiet
)
2215 printf("Entry %d logging count reset\n",
2218 errx(EX_DATAERR
, "invalid rule number ``%s''", *av
);
2221 if (failed
!= EX_OK
)
2226 ipfw_main(int ac
, char **av
)
2233 /* Initialize globals. */
2234 do_resolv
= do_acct
= do_time
= do_quiet
=
2235 do_pipe
= do_sort
= verbose
= 0;
2237 /* Set the force flag for non-interactive processes */
2238 do_force
= !isatty(STDIN_FILENO
);
2240 optind
= optreset
= 1;
2241 while ((ch
= getopt(ac
, av
, "s:adefNqtv")) != -1)
2243 case 's': /* sort */
2244 do_sort
= atoi(optarg
);
2267 case 'v': /* verbose */
2275 if (*(av
+= optind
) == NULL
)
2276 errx(EX_USAGE
, "bad arguments, for usage summary ``ipfw''");
2278 if (!strncmp(*av
, "pipe", strlen(*av
))) {
2282 } else if (!strncmp(*av
, "queue", strlen(*av
))) {
2288 errx(EX_USAGE
, "pipe requires arguments");
2290 /* allow argument swapping */
2291 if (ac
> 1 && *av
[0] >= '0' && *av
[0] <= '9') {
2296 if (!strncmp(*av
, "add", strlen(*av
))) {
2298 } else if (do_pipe
&& !strncmp(*av
, "config", strlen(*av
))) {
2299 config_pipe(ac
, av
);
2300 } else if (!strncmp(*av
, "delete", strlen(*av
))) {
2302 } else if (!strncmp(*av
, "flush", strlen(*av
))) {
2305 if (do_force
|| do_quiet
)
2311 printf("Are you sure? [yn] ");
2314 c
= toupper(getc(stdin
));
2315 while (c
!= '\n' && getc(stdin
) != '\n')
2318 } while (c
!= 'Y' && c
!= 'N');
2324 if (setsockopt(s
, IPPROTO_IP
,
2325 do_pipe
? IP_DUMMYNET_FLUSH
: IP_FW_FLUSH
,
2327 err(EX_UNAVAILABLE
, "setsockopt(IP_%s_FLUSH)",
2328 do_pipe
? "DUMMYNET" : "FW");
2330 printf("Flushed all %s.\n",
2331 do_pipe
? "pipes" : "rules");
2333 } else if (!strncmp(*av
, "zero", strlen(*av
))) {
2335 } else if (!strncmp(*av
, "resetlog", strlen(*av
))) {
2337 } else if (!strncmp(*av
, "print", strlen(*av
))) {
2339 } else if (!strncmp(*av
, "enable", strlen(*av
))) {
2340 sysctl_handler(ac
, av
, 1);
2341 } else if (!strncmp(*av
, "disable", strlen(*av
))) {
2342 sysctl_handler(ac
, av
, 0);
2343 } else if (!strncmp(*av
, "list", strlen(*av
))) {
2345 } else if (!strncmp(*av
, "show", strlen(*av
))) {
2349 errx(EX_USAGE
, "bad arguments, for usage summary ``ipfw''");
2355 main(int ac
, char *av
[])
2358 #define WHITESP " \t\f\v\n\r"
2360 char *a
, *p
, *args
[MAX_ARGS
], *cmd
= NULL
;
2362 int i
, c
, lineno
, qflag
, pflag
, status
;
2366 s
= socket(AF_INET
, SOCK_RAW
, IPPROTO_RAW
);
2368 err(EX_UNAVAILABLE
, "socket");
2373 * Only interpret the last command line argument as a file to
2374 * be preprocessed if it is specified as an absolute pathname.
2377 if (ac
> 1 && av
[ac
- 1][0] == '/' && access(av
[ac
- 1], R_OK
) == 0) {
2378 qflag
= pflag
= i
= 0;
2381 while ((c
= getopt(ac
, av
, "D:U:p:q")) != -1)
2385 errx(EX_USAGE
, "-D requires -p");
2386 if (i
> MAX_ARGS
- 2)
2388 "too many -D or -U options");
2395 errx(EX_USAGE
, "-U requires -p");
2396 if (i
> MAX_ARGS
- 2)
2398 "too many -D or -U options");
2415 errx(EX_USAGE
, "bad arguments, for usage"
2416 " summary ``ipfw''");
2422 errx(EX_USAGE
, "extraneous filename arguments");
2424 if ((f
= fopen(av
[0], "r")) == NULL
)
2425 err(EX_UNAVAILABLE
, "fopen: %s", av
[0]);
2428 /* pipe through preprocessor (cpp or m4) */
2433 if (pipe(pipedes
) == -1)
2434 err(EX_OSERR
, "cannot create pipe");
2436 switch((preproc
= fork())) {
2438 err(EX_OSERR
, "cannot fork");
2442 if (dup2(fileno(f
), 0) == -1
2443 || dup2(pipedes
[1], 1) == -1)
2444 err(EX_OSERR
, "dup2()");
2449 err(EX_OSERR
, "execvp(%s) failed", cmd
);
2455 if ((f
= fdopen(pipedes
[0], "r")) == NULL
) {
2456 int savederrno
= errno
;
2458 kill(preproc
, SIGTERM
);
2460 err(EX_OSERR
, "fdopen()");
2465 while (fgets(buf
, BUFSIZ
, f
)) {
2467 sprintf(linename
, "Line %d", lineno
);
2472 if ((p
= strchr(buf
, '#')) != NULL
)
2477 for (a
= strtok(buf
, WHITESP
);
2478 a
&& i
< MAX_ARGS
; a
= strtok(NULL
, WHITESP
), i
++)
2480 if (i
== (qflag
? 2: 1))
2483 errx(EX_USAGE
, "%s: too many arguments",
2491 if (waitpid(preproc
, &status
, 0) == -1)
2492 errx(EX_OSERR
, "waitpid()");
2493 if (WIFEXITED(status
) && WEXITSTATUS(status
) != EX_OK
)
2494 errx(EX_UNAVAILABLE
,
2495 "preprocessor exited with status %d",
2496 WEXITSTATUS(status
));
2497 else if (WIFSIGNALED(status
))
2498 errx(EX_UNAVAILABLE
,
2499 "preprocessor exited with signal %d",