]> git.saurik.com Git - apple/network_cmds.git/blame - ipfw.tproj/ipfw.c
network_cmds-115.tar.gz
[apple/network_cmds.git] / ipfw.tproj / ipfw.c
CommitLineData
7ba0088d
A
1/*
2 * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
b7080c8e
A
22/*
23 * Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp
24 * Copyright (c) 1994 Ugen J.S.Antsilevich
25 *
26 * Idea and grammar partially left from:
27 * Copyright (c) 1993 Daniel Boulet
28 *
29 * Redistribution and use in source forms, with and without modification,
30 * are permitted provided that this entire comment appears intact.
31 *
32 * Redistribution in binary form may occur without any restrictions.
33 * Obviously, it would be nice if you gave credit where credit is due
34 * but requiring it would be too onerous.
35 *
36 * This software is provided ``AS IS'' without any warranties of any kind.
37 *
38 * NEW command line interface for IP firewall facility
39 *
b7080c8e
A
40 */
41
7ba0088d
A
42
43
44#include <sys/param.h>
45#include <sys/mbuf.h>
b7080c8e
A
46#include <sys/socket.h>
47#include <sys/sockio.h>
7ba0088d 48#include <sys/sysctl.h>
b7080c8e
A
49#include <sys/time.h>
50#include <sys/wait.h>
7ba0088d 51#include <sys/ioctl.h>
b7080c8e
A
52
53#include <ctype.h>
54#include <err.h>
55#include <errno.h>
7ba0088d 56#include <grp.h>
b7080c8e
A
57#include <limits.h>
58#include <netdb.h>
7ba0088d 59#include <pwd.h>
b7080c8e
A
60#include <signal.h>
61#include <stdio.h>
62#include <stdlib.h>
63#include <stdarg.h>
64#include <string.h>
b7080c8e 65#include <unistd.h>
7ba0088d 66#include <sysexits.h>
b7080c8e
A
67
68#include <net/if.h>
69#include <netinet/in.h>
70#include <netinet/in_systm.h>
b7080c8e
A
71#include <netinet/ip.h>
72#include <netinet/ip_icmp.h>
73#include <netinet/ip_fw.h>
74#include <net/route.h> /* def. of struct route */
7ba0088d 75#ifdef DUMMYNET
b7080c8e 76#include <netinet/ip_dummynet.h>
7ba0088d 77#endif /* DUMMYNET */
b7080c8e
A
78#include <netinet/tcp.h>
79#include <arpa/inet.h>
80
7ba0088d
A
81int s, /* main RAW socket */
82 do_resolv, /* Would try to resolve all */
83 do_acct, /* Show packet/byte count */
84 do_time, /* Show time stamps */
85 do_quiet, /* Be quiet in add and flush */
86 do_force, /* Don't ask for confirmation */
87 #ifdef DUMMYNET
88 do_pipe, /* this cmd refers to a pipe */
89 #endif /* DUMMYNET */
90 do_sort, /* field to sort results (0 = no) */
91 verbose;
b7080c8e
A
92
93struct icmpcode {
94 int code;
95 char *str;
96};
97
98static struct icmpcode icmpcodes[] = {
99 { ICMP_UNREACH_NET, "net" },
100 { ICMP_UNREACH_HOST, "host" },
101 { ICMP_UNREACH_PROTOCOL, "protocol" },
102 { ICMP_UNREACH_PORT, "port" },
103 { ICMP_UNREACH_NEEDFRAG, "needfrag" },
104 { ICMP_UNREACH_SRCFAIL, "srcfail" },
105 { ICMP_UNREACH_NET_UNKNOWN, "net-unknown" },
106 { ICMP_UNREACH_HOST_UNKNOWN, "host-unknown" },
107 { ICMP_UNREACH_ISOLATED, "isolated" },
108 { ICMP_UNREACH_NET_PROHIB, "net-prohib" },
109 { ICMP_UNREACH_HOST_PROHIB, "host-prohib" },
110 { ICMP_UNREACH_TOSNET, "tosnet" },
111 { ICMP_UNREACH_TOSHOST, "toshost" },
112 { ICMP_UNREACH_FILTER_PROHIB, "filter-prohib" },
113 { ICMP_UNREACH_HOST_PRECEDENCE, "host-precedence" },
7ba0088d 114 { ICMP_UNREACH_PRECEDENCE_CUTOFF, "precedence-cutoff" },
b7080c8e
A
115 { 0, NULL }
116};
117
118static void show_usage(const char *fmt, ...);
119
120static int
121mask_bits(struct in_addr m_ad)
122{
7ba0088d 123 int h_fnd = 0, h_num = 0, i;
b7080c8e
A
124 u_long mask;
125
7ba0088d
A
126 mask = ntohl(m_ad.s_addr);
127 for (i = 0; i < sizeof(u_long) * CHAR_BIT; i++) {
b7080c8e 128 if (mask & 1L) {
7ba0088d 129 h_fnd = 1;
b7080c8e
A
130 h_num++;
131 } else {
132 if (h_fnd)
133 return -1;
134 }
7ba0088d 135 mask = mask >> 1;
b7080c8e
A
136 }
137 return h_num;
7ba0088d 138}
b7080c8e
A
139
140static void
141print_port(prot, port, comma)
142 u_char prot;
143 u_short port;
144 const char *comma;
145{
146 struct servent *se;
147 struct protoent *pe;
148 const char *protocol;
149 int printed = 0;
150
7ba0088d
A
151 if (!strcmp(comma, ":")) {
152 printf("%s0x%04x", comma, port);
153 return;
154 }
b7080c8e
A
155 if (do_resolv) {
156 pe = getprotobynumber(prot);
157 if (pe)
158 protocol = pe->p_name;
159 else
160 protocol = NULL;
161
162 se = getservbyport(htons(port), protocol);
163 if (se) {
164 printf("%s%s", comma, se->s_name);
165 printed = 1;
166 }
7ba0088d 167 }
b7080c8e 168 if (!printed)
7ba0088d 169 printf("%s%d", comma, port);
b7080c8e
A
170}
171
172static void
173print_iface(char *key, union ip_fw_if *un, int byname)
174{
175 char ifnb[FW_IFNLEN+1];
176
177 if (byname) {
178 strncpy(ifnb, un->fu_via_if.name, FW_IFNLEN);
7ba0088d 179 ifnb[FW_IFNLEN] = '\0';
b7080c8e
A
180 if (un->fu_via_if.unit == -1)
181 printf(" %s %s*", key, ifnb);
7ba0088d 182 else
b7080c8e
A
183 printf(" %s %s%d", key, ifnb, un->fu_via_if.unit);
184 } else if (un->fu_via_ip.s_addr != 0) {
185 printf(" %s %s", key, inet_ntoa(un->fu_via_ip));
186 } else
187 printf(" %s any", key);
188}
189
190static void
191print_reject_code(int code)
192{
193 struct icmpcode *ic;
194
195 for (ic = icmpcodes; ic->str; ic++)
196 if (ic->code == code) {
197 printf("%s", ic->str);
198 return;
199 }
200 printf("%u", code);
201}
202
203static void
204show_ipfw(struct ip_fw *chain, int pcwidth, int bcwidth)
205{
206 char *comma;
207 u_long adrt;
208 struct hostent *he;
209 struct protoent *pe;
210 int i, mb;
211 int nsp = IP_FW_GETNSRCP(chain);
212 int ndp = IP_FW_GETNDSTP(chain);
213
214 if (do_resolv)
7ba0088d 215 setservent(1/*stay open*/);
b7080c8e
A
216
217 printf("%05u ", chain->fw_number);
218
7ba0088d
A
219 if (do_acct)
220 printf("%*qu %*qu ", pcwidth, chain->fw_pcnt, bcwidth, chain->fw_bcnt);
b7080c8e 221
7ba0088d
A
222 if (do_time) {
223 if (chain->timestamp) {
b7080c8e
A
224 char timestr[30];
225
226 strcpy(timestr, ctime((time_t *)&chain->timestamp));
227 *strchr(timestr, '\n') = '\0';
228 printf("%s ", timestr);
7ba0088d
A
229 } else {
230 printf(" ");
b7080c8e 231 }
7ba0088d
A
232 }
233 if (chain->fw_flg == IP_FW_F_CHECK_S) {
234 printf("check-state\n");
235 goto done;
b7080c8e
A
236 }
237
7ba0088d
A
238 if (chain->fw_flg & IP_FW_F_RND_MATCH) {
239 double d = 1.0 * (int)(chain->pipe_ptr);
240 d = 1 - (d / 0x7fffffff);
241 printf("prob %f ", d);
242 }
243
244 switch (chain->fw_flg & IP_FW_F_COMMAND) {
b7080c8e
A
245 case IP_FW_F_ACCEPT:
246 printf("allow");
247 break;
248 case IP_FW_F_DENY:
249 printf("deny");
250 break;
251 case IP_FW_F_COUNT:
252 printf("count");
253 break;
254 case IP_FW_F_DIVERT:
255 printf("divert %u", chain->fw_divert_port);
256 break;
257 case IP_FW_F_TEE:
258 printf("tee %u", chain->fw_divert_port);
259 break;
260 case IP_FW_F_SKIPTO:
261 printf("skipto %u", chain->fw_skipto_rule);
262 break;
7ba0088d
A
263
264 case IP_FW_F_PIPE:
265 printf("pipe %u", chain->fw_skipto_rule);
266 break;
267 case IP_FW_F_QUEUE:
268 printf("queue %u", chain->fw_skipto_rule);
269 break;
b7080c8e
A
270 case IP_FW_F_REJECT:
271 if (chain->fw_reject_code == IP_FW_REJECT_RST)
272 printf("reset");
273 else {
274 printf("unreach ");
275 print_reject_code(chain->fw_reject_code);
276 }
277 break;
278 case IP_FW_F_FWD:
279 printf("fwd %s", inet_ntoa(chain->fw_fwd_ip.sin_addr));
280 if(chain->fw_fwd_ip.sin_port)
281 printf(",%d", chain->fw_fwd_ip.sin_port);
282 break;
283 default:
284 errx(EX_OSERR, "impossible");
285 }
7ba0088d
A
286
287 if (chain->fw_flg & IP_FW_F_PRN) {
b7080c8e 288 printf(" log");
7ba0088d
A
289 if (chain->fw_logamount)
290 printf(" logamount %d", chain->fw_logamount);
291 }
b7080c8e
A
292
293 pe = getprotobynumber(chain->fw_prot);
294 if (pe)
295 printf(" %s", pe->p_name);
296 else
297 printf(" %u", chain->fw_prot);
298
7ba0088d
A
299 if (chain->fw_flg & IP_FW_F_SME) {
300 printf(" from me");
b7080c8e 301 } else {
7ba0088d
A
302 printf(" from %s", chain->fw_flg & IP_FW_F_INVSRC ? "not " : "");
303
304 adrt = ntohl(chain->fw_smsk.s_addr);
305 if (adrt == ULONG_MAX && do_resolv) {
306 adrt = (chain->fw_src.s_addr);
307 he = gethostbyaddr((char *)&adrt,
308 sizeof(u_long), AF_INET);
309 if (he == NULL) {
310 printf("%s", inet_ntoa(chain->fw_src));
311 } else
312 printf("%s", he->h_name);
313 } else {
314 if (adrt != ULONG_MAX) {
315 mb = mask_bits(chain->fw_smsk);
316 if (mb == 0) {
317 printf("any");
b7080c8e 318 } else {
7ba0088d
A
319 if (mb > 0) {
320 printf("%s", inet_ntoa(chain->fw_src));
321 printf("/%d", mb);
322 } else {
323 printf("%s", inet_ntoa(chain->fw_src));
324 printf(":");
325 printf("%s", inet_ntoa(chain->fw_smsk));
326 }
b7080c8e 327 }
7ba0088d
A
328 } else
329 printf("%s", inet_ntoa(chain->fw_src));
330 }
b7080c8e
A
331 }
332
333 if (chain->fw_prot == IPPROTO_TCP || chain->fw_prot == IPPROTO_UDP) {
334 comma = " ";
335 for (i = 0; i < nsp; i++) {
336 print_port(chain->fw_prot, chain->fw_uar.fw_pts[i], comma);
7ba0088d 337 if (i == 0 && (chain->fw_flg & IP_FW_F_SRNG))
b7080c8e 338 comma = "-";
7ba0088d
A
339 else if (i == 0 && (chain->fw_flg & IP_FW_F_SMSK))
340 comma = ":";
b7080c8e
A
341 else
342 comma = ",";
343 }
344 }
345
7ba0088d
A
346 if (chain->fw_flg & IP_FW_F_DME) {
347 printf(" to me");
b7080c8e 348 } else {
7ba0088d
A
349 printf(" to %s", chain->fw_flg & IP_FW_F_INVDST ? "not " : "");
350
351 adrt = ntohl(chain->fw_dmsk.s_addr);
352 if (adrt == ULONG_MAX && do_resolv) {
353 adrt = (chain->fw_dst.s_addr);
354 he = gethostbyaddr((char *)&adrt,
355 sizeof(u_long), AF_INET);
356 if (he == NULL) {
357 printf("%s", inet_ntoa(chain->fw_dst));
358 } else
359 printf("%s", he->h_name);
360 } else {
361 if (adrt != ULONG_MAX) {
362 mb = mask_bits(chain->fw_dmsk);
363 if (mb == 0) {
364 printf("any");
b7080c8e 365 } else {
7ba0088d
A
366 if (mb > 0) {
367 printf("%s", inet_ntoa(chain->fw_dst));
368 printf("/%d", mb);
369 } else {
370 printf("%s", inet_ntoa(chain->fw_dst));
371 printf(":");
372 printf("%s", inet_ntoa(chain->fw_dmsk));
373 }
b7080c8e 374 }
7ba0088d
A
375 } else
376 printf("%s", inet_ntoa(chain->fw_dst));
377 }
b7080c8e
A
378 }
379
380 if (chain->fw_prot == IPPROTO_TCP || chain->fw_prot == IPPROTO_UDP) {
381 comma = " ";
382 for (i = 0; i < ndp; i++) {
383 print_port(chain->fw_prot, chain->fw_uar.fw_pts[nsp+i], comma);
7ba0088d 384 if (i == 0 && (chain->fw_flg & IP_FW_F_DRNG))
b7080c8e 385 comma = "-";
7ba0088d
A
386 else if (i == 0 && (chain->fw_flg & IP_FW_F_DMSK))
387 comma = ":";
b7080c8e
A
388 else
389 comma = ",";
390 }
391 }
392
7ba0088d
A
393 if (chain->fw_flg & IP_FW_F_UID) {
394 struct passwd *pwd = getpwuid(chain->fw_uid);
395
396 if (pwd)
397 printf(" uid %s", pwd->pw_name);
398 else
399 printf(" uid %u", chain->fw_uid);
400 }
401
402 if (chain->fw_flg & IP_FW_F_KEEP_S) {
403 if (chain->next_rule_ptr)
404 printf(" keep-state %d", (int)chain->next_rule_ptr);
405 else
406 printf(" keep-state");
407 }
b7080c8e 408 /* Direction */
7ba0088d
A
409 if (chain->fw_flg & IP_FW_BRIDGED)
410 printf(" bridged");
b7080c8e
A
411 if ((chain->fw_flg & IP_FW_F_IN) && !(chain->fw_flg & IP_FW_F_OUT))
412 printf(" in");
413 if (!(chain->fw_flg & IP_FW_F_IN) && (chain->fw_flg & IP_FW_F_OUT))
414 printf(" out");
415
416 /* Handle hack for "via" backwards compatibility */
417 if ((chain->fw_flg & IF_FW_F_VIAHACK) == IF_FW_F_VIAHACK) {
418 print_iface("via",
419 &chain->fw_in_if, chain->fw_flg & IP_FW_F_IIFNAME);
420 } else {
421 /* Receive interface specified */
422 if (chain->fw_flg & IP_FW_F_IIFACE)
423 print_iface("recv", &chain->fw_in_if,
424 chain->fw_flg & IP_FW_F_IIFNAME);
425 /* Transmit interface specified */
426 if (chain->fw_flg & IP_FW_F_OIFACE)
427 print_iface("xmit", &chain->fw_out_if,
428 chain->fw_flg & IP_FW_F_OIFNAME);
429 }
430
431 if (chain->fw_flg & IP_FW_F_FRAG)
432 printf(" frag");
433
434 if (chain->fw_ipopt || chain->fw_ipnopt) {
435 int _opt_printed = 0;
436#define PRINTOPT(x) {if (_opt_printed) printf(",");\
437 printf(x); _opt_printed = 1;}
438
439 printf(" ipopt ");
440 if (chain->fw_ipopt & IP_FW_IPOPT_SSRR) PRINTOPT("ssrr");
441 if (chain->fw_ipnopt & IP_FW_IPOPT_SSRR) PRINTOPT("!ssrr");
442 if (chain->fw_ipopt & IP_FW_IPOPT_LSRR) PRINTOPT("lsrr");
443 if (chain->fw_ipnopt & IP_FW_IPOPT_LSRR) PRINTOPT("!lsrr");
444 if (chain->fw_ipopt & IP_FW_IPOPT_RR) PRINTOPT("rr");
445 if (chain->fw_ipnopt & IP_FW_IPOPT_RR) PRINTOPT("!rr");
446 if (chain->fw_ipopt & IP_FW_IPOPT_TS) PRINTOPT("ts");
447 if (chain->fw_ipnopt & IP_FW_IPOPT_TS) PRINTOPT("!ts");
7ba0088d 448 }
b7080c8e 449
7ba0088d 450 if (chain->fw_ipflg & IP_FW_IF_TCPEST)
b7080c8e
A
451 printf(" established");
452 else if (chain->fw_tcpf == IP_FW_TCPF_SYN &&
453 chain->fw_tcpnf == IP_FW_TCPF_ACK)
454 printf(" setup");
455 else if (chain->fw_tcpf || chain->fw_tcpnf) {
456 int _flg_printed = 0;
457#define PRINTFLG(x) {if (_flg_printed) printf(",");\
458 printf(x); _flg_printed = 1;}
459
7ba0088d 460 printf(" tcpflags ");
b7080c8e
A
461 if (chain->fw_tcpf & IP_FW_TCPF_FIN) PRINTFLG("fin");
462 if (chain->fw_tcpnf & IP_FW_TCPF_FIN) PRINTFLG("!fin");
463 if (chain->fw_tcpf & IP_FW_TCPF_SYN) PRINTFLG("syn");
464 if (chain->fw_tcpnf & IP_FW_TCPF_SYN) PRINTFLG("!syn");
465 if (chain->fw_tcpf & IP_FW_TCPF_RST) PRINTFLG("rst");
466 if (chain->fw_tcpnf & IP_FW_TCPF_RST) PRINTFLG("!rst");
467 if (chain->fw_tcpf & IP_FW_TCPF_PSH) PRINTFLG("psh");
468 if (chain->fw_tcpnf & IP_FW_TCPF_PSH) PRINTFLG("!psh");
469 if (chain->fw_tcpf & IP_FW_TCPF_ACK) PRINTFLG("ack");
470 if (chain->fw_tcpnf & IP_FW_TCPF_ACK) PRINTFLG("!ack");
471 if (chain->fw_tcpf & IP_FW_TCPF_URG) PRINTFLG("urg");
472 if (chain->fw_tcpnf & IP_FW_TCPF_URG) PRINTFLG("!urg");
7ba0088d
A
473 }
474 if (chain->fw_tcpopt || chain->fw_tcpnopt) {
475 int _opt_printed = 0;
476#define PRINTTOPT(x) {if (_opt_printed) printf(",");\
477 printf(x); _opt_printed = 1;}
478
479 printf(" tcpoptions ");
480 if (chain->fw_tcpopt & IP_FW_TCPOPT_MSS) PRINTTOPT("mss");
481 if (chain->fw_tcpnopt & IP_FW_TCPOPT_MSS) PRINTTOPT("!mss");
482 if (chain->fw_tcpopt & IP_FW_TCPOPT_WINDOW) PRINTTOPT("window");
483 if (chain->fw_tcpnopt & IP_FW_TCPOPT_WINDOW) PRINTTOPT("!window");
484 if (chain->fw_tcpopt & IP_FW_TCPOPT_SACK) PRINTTOPT("sack");
485 if (chain->fw_tcpnopt & IP_FW_TCPOPT_SACK) PRINTTOPT("!sack");
486 if (chain->fw_tcpopt & IP_FW_TCPOPT_TS) PRINTTOPT("ts");
487 if (chain->fw_tcpnopt & IP_FW_TCPOPT_TS) PRINTTOPT("!ts");
488 if (chain->fw_tcpopt & IP_FW_TCPOPT_CC) PRINTTOPT("cc");
489 if (chain->fw_tcpnopt & IP_FW_TCPOPT_CC) PRINTTOPT("!cc");
490 }
491
b7080c8e
A
492 if (chain->fw_flg & IP_FW_F_ICMPBIT) {
493 int type_index;
494 int first = 1;
495
496 printf(" icmptype");
497
498 for (type_index = 0; type_index < IP_FW_ICMPTYPES_DIM * sizeof(unsigned) * 8; ++type_index)
7ba0088d 499 if (chain->fw_uar.fw_icmptypes[type_index / (sizeof(unsigned) * 8)] &
b7080c8e
A
500 (1U << (type_index % (sizeof(unsigned) * 8)))) {
501 printf("%c%d", first == 1 ? ' ' : ',', type_index);
502 first = 0;
503 }
504 }
505 printf("\n");
7ba0088d 506done:
b7080c8e
A
507 if (do_resolv)
508 endservent();
509}
510
7ba0088d
A
511#ifdef DUMMYNET
512int
513sort_q(const void *pa, const void *pb)
514{
515 int rev = (do_sort < 0);
516 int field = rev ? -do_sort : do_sort;
517 long long res = 0;
518 const struct dn_flow_queue *a = pa;
519 const struct dn_flow_queue *b = pb;
520
521 switch (field) {
522 case 1: /* pkts */
523 res = a->len - b->len;
524 break;
525 case 2 : /* bytes */
526 res = a->len_bytes - b->len_bytes;
527 break;
528
529 case 3 : /* tot pkts */
530 res = a->tot_pkts - b->tot_pkts;
531 break;
532
533 case 4 : /* tot bytes */
534 res = a->tot_bytes - b->tot_bytes;
535 break;
536 }
537 if (res < 0)
538 res = -1;
539 if (res > 0)
540 res = 1;
541 return (int)(rev ? res : -res);
542}
543
544static void
545list_queues(struct dn_flow_set *fs, struct dn_flow_queue *q)
546{
547 int l;
548
549 printf(" mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n",
550 fs->flow_mask.proto,
551 fs->flow_mask.src_ip, fs->flow_mask.src_port,
552 fs->flow_mask.dst_ip, fs->flow_mask.dst_port);
553 if (fs->rq_elements == 0)
554 return;
555
556 printf("BKT Prot ___Source IP/port____ "
557 "____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp\n");
558 if (do_sort != 0)
559 heapsort(q, fs->rq_elements, sizeof(*q), sort_q);
560 for (l = 0; l < fs->rq_elements; l++) {
561 struct in_addr ina;
562 struct protoent *pe;
563
564 ina.s_addr = htonl(q[l].id.src_ip);
565 printf("%3d ", q[l].hash_slot);
566 pe = getprotobynumber(q[l].id.proto);
567 if (pe)
568 printf("%-4s ", pe->p_name);
569 else
570 printf("%4u ", q[l].id.proto);
571 printf("%15s/%-5d ", inet_ntoa(ina), q[l].id.src_port);
572 ina.s_addr = htonl(q[l].id.dst_ip);
573 printf("%15s/%-5d ",
574 inet_ntoa(ina), q[l].id.dst_port);
575 printf("%4qu %8qu %2u %4u %3u\n",
576 q[l].tot_pkts, q[l].tot_bytes,
577 q[l].len, q[l].len_bytes, q[l].drops);
578 if (verbose)
579 printf(" S %20qd F %20qd\n", q[l].S, q[l].F);
580 }
581}
582
583static void
584print_flowset_parms(struct dn_flow_set *fs, char *prefix)
585{
586 int l;
587 char qs[30];
588 char plr[30];
589 char red[90]; /* Display RED parameters */
590
591 l = fs->qsize;
592 if (fs->flags_fs & DN_QSIZE_IS_BYTES) {
593 if (l >= 8192)
594 sprintf(qs, "%d KB", l / 1024);
595 else
596 sprintf(qs, "%d B", l);
597 } else
598 sprintf(qs, "%3d sl.", l);
599 if (fs->plr)
600 sprintf(plr, "plr %f", 1.0*fs->plr/(double)(0x7fffffff));
601 else
602 plr[0]='\0';
603 if (fs->flags_fs & DN_IS_RED) /* RED parameters */
604 sprintf(red,
605 "\n %cRED w_q %f min_th %d max_th %d max_p %f",
606 (fs->flags_fs & DN_IS_GENTLE_RED)? 'G' : ' ',
607 1.0 * fs->w_q / (double)(1 << SCALE_RED),
608 SCALE_VAL(fs->min_th),
609 SCALE_VAL(fs->max_th),
610 1.0 * fs->max_p / (double)(1 << SCALE_RED) ) ;
611 else
612 sprintf(red, "droptail");
613
614 printf("%s %s%s %d queues (%d buckets) %s\n", prefix, qs, plr,
615 fs->rq_elements, fs->rq_size, red);
616}
617#endif /* DUMMYNET */
618
b7080c8e
A
619static void
620list(ac, av)
621 int ac;
622 char **av;
623{
624 struct ip_fw *rules;
7ba0088d 625 #ifdef DUMMYNET
b7080c8e 626 struct dn_pipe *pipes;
7ba0088d 627 #endif /* DUMMYNET */
b7080c8e
A
628 void *data = NULL;
629 int pcwidth = 0;
630 int bcwidth = 0;
631 int n, num = 0;
7ba0088d 632 int nbytes;
b7080c8e
A
633
634 /* get rules or pipes from kernel, resizing array as necessary */
635 {
7ba0088d 636 #ifdef DUMMYNET
b7080c8e
A
637 const int unit = do_pipe ? sizeof(*pipes) : sizeof(*rules);
638 const int ocmd = do_pipe ? IP_DUMMYNET_GET : IP_FW_GET;
7ba0088d
A
639 #else /* DUMMYNET */
640 const int unit = sizeof(*rules);
641 const int ocmd = IP_FW_GET;
642 #endif /* DUMMYNET */
643 int nalloc = unit;
644 nbytes = nalloc;
645
646 while (nbytes >= nalloc) {
b7080c8e 647 nalloc = nalloc * 2 + 200;
7ba0088d 648 nbytes = nalloc;
b7080c8e
A
649 if ((data = realloc(data, nbytes)) == NULL)
650 err(EX_OSERR, "realloc");
7ba0088d
A
651 rules = data;
652 rules->version = IP_FW_CURRENT_API_VERSION;
b7080c8e 653 if (getsockopt(s, IPPROTO_IP, ocmd, data, &nbytes) < 0)
7ba0088d 654 #ifdef DUMMYNET
b7080c8e
A
655 err(EX_OSERR, "getsockopt(IP_%s_GET)",
656 do_pipe ? "DUMMYNET" : "FW");
7ba0088d
A
657 #else /* DUMMYNET */
658 err(EX_OSERR, "getsockopt(IP_FW_GET)");
659 #endif /* DUMMYNET */
b7080c8e
A
660 }
661 }
662
663 /* display requested pipes */
7ba0088d 664 #ifdef DUMMYNET
b7080c8e 665 if (do_pipe) {
7ba0088d
A
666 u_long rulenum;
667 void *next = data;
668 struct dn_pipe *p = (struct dn_pipe *) data;
669 struct dn_flow_set *fs;
670 struct dn_flow_queue *q;
671 int l;
672
673 if (ac > 0)
674 rulenum = strtoul(*av++, NULL, 10);
b7080c8e 675 else
7ba0088d
A
676 rulenum = 0;
677 for (; nbytes >= sizeof(*p); p = (struct dn_pipe *)next) {
678 double b = p->bandwidth;
679 char buf[30];
680 char prefix[80];
b7080c8e 681
7ba0088d
A
682 if (p->next != (struct dn_pipe *)DN_IS_PIPE)
683 break;
684 l = sizeof(*p) + p->fs.rq_elements * sizeof(*q);
685 next = (void *)p + l;
686 nbytes -= l;
687 q = (struct dn_flow_queue *)(p+1);
688
689 if (rulenum != 0 && rulenum != p->pipe_nr)
690 continue;
691 if (p->if_name[0] != '\0')
692 sprintf(buf, "%s", p->if_name);
693 else if (b == 0)
694 sprintf(buf, "unlimited");
695 else if (b >= 1000000)
696 sprintf(buf, "%7.3f Mbit/s", b/1000000);
697 else if (b >= 1000)
698 sprintf(buf, "%7.3f Kbit/s", b/1000);
699 else
700 sprintf(buf, "%7.3f bit/s ", b);
701
702 sprintf(prefix, "%05d: %s %4d ms ",
703 p->pipe_nr, buf, p->delay);
704 print_flowset_parms(&(p->fs), prefix);
705 if (verbose)
706 printf(" V %20qd\n", p->V >> MY_M);
707 list_queues(&(p->fs), q);
708 }
709 fs = (struct dn_flow_set *) next;
710 for (; nbytes >= sizeof(*fs); fs = (struct dn_flow_set *)next) {
711 char prefix[80];
712
713 if (fs->next != (struct dn_flow_set *)DN_IS_QUEUE)
714 break;
715 l = sizeof(*fs) + fs->rq_elements * sizeof(*q);
716 next = (void *)fs + l;
717 nbytes -= l;
718 q = (struct dn_flow_queue *)(fs+1);
719 sprintf(prefix, "q%05d: weight %d pipe %d ",
720 fs->fs_nr, fs->weight, fs->parent_nr);
721 print_flowset_parms(fs, prefix);
722 list_queues(fs, q);
723 }
724 free(data);
725 return;
b7080c8e 726 }
7ba0088d 727 #endif /* DUMMYNET */
b7080c8e 728
b7080c8e 729 rules = (struct ip_fw *) data;
7ba0088d
A
730 /* determine num more accurately */
731 num = 0;
732 while (rules[num].fw_number < 65535)
733 num++;
734 num++; /* counting starts from 0 ... */
735 /* if showing stats, figure out column widths ahead of time */
b7080c8e
A
736 if (do_acct) {
737 for (n = 0; n < num; n++) {
738 struct ip_fw *const r = &rules[n];
739 char temp[32];
740 int width;
741
742 /* packet counter */
743 width = sprintf(temp, "%qu", r->fw_pcnt);
744 if (width > pcwidth)
745 pcwidth = width;
746
747 /* byte counter */
748 width = sprintf(temp, "%qu", r->fw_bcnt);
749 if (width > bcwidth)
750 bcwidth = width;
751 }
752 }
753 if (ac == 0) {
754 /* display all rules */
755 for (n = 0; n < num; n++) {
756 struct ip_fw *const r = &rules[n];
757
758 show_ipfw(r, pcwidth, bcwidth);
759 }
760 } else {
761 /* display specific rules requested on command line */
762 int exitval = EX_OK;
763
764 while (ac--) {
765 u_long rnum;
766 char *endptr;
767 int seen;
768
769 /* convert command line rule # */
770 rnum = strtoul(*av++, &endptr, 10);
771 if (*endptr) {
772 exitval = EX_USAGE;
773 warnx("invalid rule number: %s", *(av - 1));
774 continue;
775 }
776 for (seen = n = 0; n < num; n++) {
777 struct ip_fw *const r = &rules[n];
778
779 if (r->fw_number > rnum)
780 break;
781 if (r->fw_number == rnum) {
782 show_ipfw(r, pcwidth, bcwidth);
783 seen = 1;
784 }
785 }
786 if (!seen) {
787 /* give precedence to other error(s) */
788 if (exitval == EX_OK)
789 exitval = EX_UNAVAILABLE;
790 warnx("rule %lu does not exist", rnum);
791 }
792 }
793 if (exitval != EX_OK)
794 exit(exitval);
795 }
7ba0088d
A
796 /*
797 * show dynamic rules
798 */
799 if (num * sizeof (rules[0]) != nbytes) {
800 struct ipfw_dyn_rule *d =
801 (struct ipfw_dyn_rule *)&rules[num];
802 struct in_addr a;
803 struct protoent *pe;
804
805 printf("## Dynamic rules:\n");
806 for (;; d++) {
807 printf("%05d %qu %qu (T %d, # %d) ty %d",
808 (int)(d->chain),
809 d->pcnt, d->bcnt,
810 d->expire,
811 d->bucket,
812 d->type);
813 pe = getprotobynumber(d->id.proto);
814 if (pe)
815 printf(" %s,", pe->p_name);
816 else
817 printf(" %u,", d->id.proto);
818 a.s_addr = htonl(d->id.src_ip);
819 printf(" %s", inet_ntoa(a));
820 printf(" %d", d->id.src_port);
821 switch (d->type) {
822 default: /* bidir, no mask */
823 printf(" <->");
824 break;
825 }
826 a.s_addr = htonl(d->id.dst_ip);
827 printf(" %s", inet_ntoa(a));
828 printf(" %d", d->id.dst_port);
829 printf("\n");
830 if (d->next == NULL)
831 break;
832 }
833 }
834
b7080c8e
A
835 free(data);
836}
837
838static void
839show_usage(const char *fmt, ...)
840{
841 if (fmt) {
842 char buf[100];
843 va_list args;
844
845 va_start(args, fmt);
846 vsnprintf(buf, sizeof(buf), fmt, args);
847 va_end(args);
848 warnx("error: %s", buf);
849 }
850 fprintf(stderr, "usage: ipfw [options]\n"
7ba0088d
A
851#ifdef DUMMYNET
852" [pipe] flush\n"
853#endif /* DUMMYNET */
b7080c8e 854" add [number] rule\n"
7ba0088d
A
855#ifdef DUMMYNET
856" [pipe] delete number ...\n"
857" [pipe] list [number ...]\n"
858" [pipe] show [number ...]\n"
859#endif /* DUMMYNET */
b7080c8e 860" zero [number ...]\n"
7ba0088d
A
861" resetlog [number ...]\n"
862#ifdef DUMMYNET
863" pipe number config [pipeconfig]\n"
864#endif /* DUMMYNET */
865" rule: [prob <match_probability>] action proto src dst extras...\n"
b7080c8e
A
866" action:\n"
867" {allow|permit|accept|pass|deny|drop|reject|unreach code|\n"
7ba0088d
A
868" reset|count|skipto num|divert port|tee port|fwd ip|\n"
869#ifdef DUMMYNET
870" pipe num"
871#endif /* DUMMYNET */
872"} [log [logamount count]]\n"
b7080c8e 873" proto: {ip|tcp|udp|icmp|<number>}\n"
7ba0088d
A
874" src: from [not] {me|any|ip[{/bits|:mask}]} [{port|port-port},[port],...]\n"
875" dst: to [not] {me|any|ip[{/bits|:mask}]} [{port|port-port},[port],...]\n"
b7080c8e 876" extras:\n"
7ba0088d 877" uid {user id}\n"
b7080c8e
A
878" fragment (may not be used with ports or tcpflags)\n"
879" in\n"
880" out\n"
881" {xmit|recv|via} {iface|ip|any}\n"
882" {established|setup}\n"
883" tcpflags [!]{syn|fin|rst|ack|psh|urg},...\n"
884" ipoptions [!]{ssrr|lsrr|rr|ts},...\n"
7ba0088d
A
885" tcpoptions [!]{mss|window|sack|ts|cc},...\n"
886" icmptypes {type[,type]}...\n"
887#ifdef DUMMYNET
888" pipeconfig:\n"
889" {bw|bandwidth} <number>{bit/s|Kbit/s|Mbit/s|Bytes/s|KBytes/s|MBytes/s}\n"
890" {bw|bandwidth} interface_name\n"
891" delay <milliseconds>\n"
892" queue <size>{packets|Bytes|KBytes}\n"
893" plr <fraction>\n"
894" mask {all| [dst-ip|src-ip|dst-port|src-port|proto] <number>}\n"
895" buckets <number>}\n"
896" {red|gred} <fraction>/<number>/<number>/<fraction>\n"
897" droptail\n"
898#endif /* DUMMYNET */
899);
b7080c8e
A
900
901 exit(EX_USAGE);
902}
903
904static int
905lookup_host (host, ipaddr)
906 char *host;
907 struct in_addr *ipaddr;
908{
7ba0088d 909 struct hostent *he;
b7080c8e 910
7ba0088d
A
911 if (!inet_aton(host, ipaddr)) {
912 if ((he = gethostbyname(host)) == NULL)
913 return(-1);
914 *ipaddr = *(struct in_addr *)he->h_addr_list[0];
915 }
b7080c8e
A
916 return(0);
917}
918
919static void
920fill_ip(ipno, mask, acp, avp)
921 struct in_addr *ipno, *mask;
922 int *acp;
923 char ***avp;
924{
925 int ac = *acp;
926 char **av = *avp;
927 char *p = 0, md = 0;
928
7ba0088d 929 if (ac && !strncmp(*av, "any", strlen(*av))) {
b7080c8e
A
930 ipno->s_addr = mask->s_addr = 0; av++; ac--;
931 } else {
932 p = strchr(*av, '/');
7ba0088d 933 if (!p)
b7080c8e
A
934 p = strchr(*av, ':');
935 if (p) {
936 md = *p;
7ba0088d 937 *p++ = '\0';
b7080c8e
A
938 }
939
940 if (lookup_host(*av, ipno) != 0)
941 show_usage("hostname ``%s'' unknown", *av);
942 switch (md) {
943 case ':':
7ba0088d 944 if (!inet_aton(p, mask))
b7080c8e
A
945 show_usage("bad netmask ``%s''", p);
946 break;
947 case '/':
948 if (atoi(p) == 0) {
949 mask->s_addr = 0;
950 } else if (atoi(p) > 32) {
951 show_usage("bad width ``%s''", p);
952 } else {
953 mask->s_addr =
954 htonl(~0 << (32 - atoi(p)));
955 }
956 break;
957 default:
958 mask->s_addr = htonl(~0);
959 break;
960 }
961 ipno->s_addr &= mask->s_addr;
962 av++;
963 ac--;
964 }
965 *acp = ac;
966 *avp = av;
967}
968
969static void
970fill_reject_code(u_short *codep, char *str)
971{
972 struct icmpcode *ic;
973 u_long val;
974 char *s;
975
976 val = strtoul(str, &s, 0);
977 if (s != str && *s == '\0' && val < 0x100) {
978 *codep = val;
979 return;
980 }
981 for (ic = icmpcodes; ic->str; ic++)
982 if (!strcasecmp(str, ic->str)) {
983 *codep = ic->code;
984 return;
985 }
986 show_usage("unknown ICMP unreachable code ``%s''", str);
987}
988
989static void
990add_port(cnt, ptr, off, port)
991 u_short *cnt, *ptr, off, port;
992{
993 if (off + *cnt >= IP_FW_MAX_PORTS)
994 errx(EX_USAGE, "too many ports (max is %d)", IP_FW_MAX_PORTS);
995 ptr[off+*cnt] = port;
996 (*cnt)++;
997}
998
999static int
7ba0088d 1000lookup_port(const char *arg, int proto, int test, int nodash)
b7080c8e
A
1001{
1002 int val;
1003 char *earg, buf[32];
1004 struct servent *s;
7ba0088d 1005 char *p, *q;
b7080c8e
A
1006
1007 snprintf(buf, sizeof(buf), "%s", arg);
7ba0088d
A
1008
1009 for (p = q = buf; *p; *q++ = *p++) {
1010 if (*p == '\\') {
1011 if (*(p+1))
1012 p++;
1013 } else {
1014 if (*p == ',' || (nodash && *p == '-'))
1015 break;
1016 }
1017 }
1018 *q = '\0';
1019
b7080c8e
A
1020 val = (int) strtoul(buf, &earg, 0);
1021 if (!*buf || *earg) {
7ba0088d
A
1022 char *protocol = NULL;
1023
1024 if (proto != 0) {
1025 struct protoent *pe = getprotobynumber(proto);
1026
1027 if (pe)
1028 protocol = pe->p_name;
1029 }
1030
b7080c8e 1031 setservent(1);
7ba0088d 1032 if ((s = getservbyname(buf, protocol))) {
b7080c8e
A
1033 val = htons(s->s_port);
1034 } else {
1035 if (!test) {
7ba0088d 1036 errx(EX_DATAERR, "unknown port ``%s''", buf);
b7080c8e
A
1037 }
1038 val = -1;
1039 }
1040 } else {
1041 if (val < 0 || val > 0xffff) {
1042 if (!test) {
7ba0088d 1043 errx(EX_DATAERR, "port ``%s'' out of range", buf);
b7080c8e
A
1044 }
1045 val = -1;
1046 }
1047 }
1048 return(val);
1049}
1050
7ba0088d
A
1051/*
1052 * return: 0 normally, 1 if first pair is a range,
1053 * 2 if first pair is a port+mask
1054 */
b7080c8e 1055static int
7ba0088d 1056fill_port(u_short *cnt, u_short *ptr, u_short off, char *arg, int proto)
b7080c8e
A
1057{
1058 char *s;
1059 int initial_range = 0;
1060
7ba0088d
A
1061 for (s = arg; *s && *s != ',' && *s != '-' && *s != ':'; s++) {
1062 if (*s == '\\' && *(s+1))
1063 s++;
1064 }
1065 if (*s == ':') {
1066 *s++ = '\0';
1067 if (strchr(arg, ','))
1068 errx(EX_USAGE, "port/mask must be first in list");
1069 add_port(cnt, ptr, off, *arg ? lookup_port(arg, proto, 0, 0) : 0x0000);
1070 arg = s;
1071 s = strchr(arg,',');
1072 if (s)
1073 *s++ = '\0';
1074 add_port(cnt, ptr, off, *arg ? lookup_port(arg, proto, 0, 0) : 0xffff);
1075 arg = s;
1076 initial_range = 2;
1077 } else
b7080c8e
A
1078 if (*s == '-') {
1079 *s++ = '\0';
1080 if (strchr(arg, ','))
1081 errx(EX_USAGE, "port range must be first in list");
7ba0088d 1082 add_port(cnt, ptr, off, *arg ? lookup_port(arg, proto, 0, 0) : 0x0000);
b7080c8e
A
1083 arg = s;
1084 s = strchr(arg,',');
1085 if (s)
1086 *s++ = '\0';
7ba0088d 1087 add_port(cnt, ptr, off, *arg ? lookup_port(arg, proto, 0, 0) : 0xffff);
b7080c8e
A
1088 arg = s;
1089 initial_range = 1;
1090 }
1091 while (arg != NULL) {
1092 s = strchr(arg,',');
1093 if (s)
1094 *s++ = '\0';
7ba0088d 1095 add_port(cnt, ptr, off, lookup_port(arg, proto, 0, 0));
b7080c8e
A
1096 arg = s;
1097 }
1098 return initial_range;
1099}
1100
1101static void
7ba0088d 1102fill_tcpflag(u_char *set, u_char *reset, char **vp)
b7080c8e
A
1103{
1104 char *p = *vp,*q;
1105 u_char *d;
1106
1107 while (p && *p) {
1108 struct tpcflags {
1109 char * name;
1110 u_char value;
1111 } flags[] = {
1112 { "syn", IP_FW_TCPF_SYN },
1113 { "fin", IP_FW_TCPF_FIN },
1114 { "ack", IP_FW_TCPF_ACK },
1115 { "psh", IP_FW_TCPF_PSH },
1116 { "rst", IP_FW_TCPF_RST },
1117 { "urg", IP_FW_TCPF_URG }
1118 };
1119 int i;
1120
1121 if (*p == '!') {
1122 p++;
1123 d = reset;
1124 } else {
1125 d = set;
1126 }
1127 q = strchr(p, ',');
7ba0088d 1128 if (q)
b7080c8e
A
1129 *q++ = '\0';
1130 for (i = 0; i < sizeof(flags) / sizeof(flags[0]); ++i)
1131 if (!strncmp(p, flags[i].name, strlen(p))) {
1132 *d |= flags[i].value;
1133 break;
1134 }
1135 if (i == sizeof(flags) / sizeof(flags[0]))
1136 show_usage("invalid tcp flag ``%s''", p);
1137 p = q;
1138 }
1139}
1140
7ba0088d
A
1141static void
1142fill_tcpopts(u_char *set, u_char *reset, char **vp)
1143{
1144 char *p = *vp,*q;
1145 u_char *d;
1146
1147 while (p && *p) {
1148 struct tpcopts {
1149 char * name;
1150 u_char value;
1151 } opts[] = {
1152 { "mss", IP_FW_TCPOPT_MSS },
1153 { "window", IP_FW_TCPOPT_WINDOW },
1154 { "sack", IP_FW_TCPOPT_SACK },
1155 { "ts", IP_FW_TCPOPT_TS },
1156 { "cc", IP_FW_TCPOPT_CC },
1157 };
1158 int i;
1159
1160 if (*p == '!') {
1161 p++;
1162 d = reset;
1163 } else {
1164 d = set;
1165 }
1166 q = strchr(p, ',');
1167 if (q)
1168 *q++ = '\0';
1169 for (i = 0; i < sizeof(opts) / sizeof(opts[0]); ++i)
1170 if (!strncmp(p, opts[i].name, strlen(p))) {
1171 *d |= opts[i].value;
1172 break;
1173 }
1174 if (i == sizeof(opts) / sizeof(opts[0]))
1175 show_usage("invalid tcp option ``%s''", p);
1176 p = q;
1177 }
1178}
1179
b7080c8e
A
1180static void
1181fill_ipopt(u_char *set, u_char *reset, char **vp)
1182{
1183 char *p = *vp,*q;
1184 u_char *d;
1185
1186 while (p && *p) {
1187 if (*p == '!') {
1188 p++;
1189 d = reset;
1190 } else {
1191 d = set;
1192 }
1193 q = strchr(p, ',');
7ba0088d 1194 if (q)
b7080c8e 1195 *q++ = '\0';
7ba0088d
A
1196 if (!strncmp(p, "ssrr", strlen(p))) *d |= IP_FW_IPOPT_SSRR;
1197 if (!strncmp(p, "lsrr", strlen(p))) *d |= IP_FW_IPOPT_LSRR;
1198 if (!strncmp(p, "rr", strlen(p))) *d |= IP_FW_IPOPT_RR;
1199 if (!strncmp(p, "ts", strlen(p))) *d |= IP_FW_IPOPT_TS;
b7080c8e
A
1200 p = q;
1201 }
1202}
1203
1204static void
1205fill_icmptypes(types, vp, fw_flg)
1206 u_long *types;
1207 char **vp;
1208 u_int *fw_flg;
1209{
1210 char *c = *vp;
1211
1212 while (*c)
1213 {
1214 unsigned long icmptype;
1215
7ba0088d 1216 if (*c == ',')
b7080c8e
A
1217 ++c;
1218
1219 icmptype = strtoul(c, &c, 0);
1220
7ba0088d 1221 if (*c != ',' && *c != '\0')
b7080c8e
A
1222 show_usage("invalid ICMP type");
1223
1224 if (icmptype >= IP_FW_ICMPTYPES_DIM * sizeof(unsigned) * 8)
1225 show_usage("ICMP type out of range");
1226
7ba0088d 1227 types[icmptype / (sizeof(unsigned) * 8)] |=
b7080c8e
A
1228 1 << (icmptype % (sizeof(unsigned) * 8));
1229 *fw_flg |= IP_FW_F_ICMPBIT;
1230 }
1231}
1232
1233static void
7ba0088d 1234delete(ac, av)
b7080c8e
A
1235 int ac;
1236 char **av;
1237{
1238 struct ip_fw rule;
7ba0088d 1239 #ifdef DUMMYNET
b7080c8e 1240 struct dn_pipe pipe;
7ba0088d 1241 #endif /* DUMMYNET */
b7080c8e
A
1242 int i;
1243 int exitval = EX_OK;
1244
1245 memset(&rule, 0, sizeof rule);
7ba0088d 1246 #ifdef DUMMYNET
b7080c8e 1247 memset(&pipe, 0, sizeof pipe);
7ba0088d
A
1248 #endif /* DUMMYNET */
1249 rule.version = IP_FW_CURRENT_API_VERSION;
b7080c8e
A
1250
1251 av++; ac--;
1252
1253 /* Rule number */
7ba0088d
A
1254 while (ac && isdigit(**av))
1255 {
1256 i = atoi(*av); av++; ac--;
1257
1258 #ifdef DUMMYNET
1259 if (do_pipe)
1260 {
1261 if (do_pipe == 1) pipe.pipe_nr = i;
1262 else pipe.fs.fs_nr = i;
1263
1264 i = setsockopt(s, IPPROTO_IP, IP_DUMMYNET_DEL, &pipe, sizeof pipe);
1265 if (i)
1266 {
1267 exitval = 1;
1268 warn("rule %u: setsockopt(%s)", do_pipe == 1 ? pipe.pipe_nr : pipe.fs.fs_nr,
1269 "IP_DUMMYNET_DEL");
1270 }
1271 }
1272 else
1273 #endif /* DUMMYNET */
1274 {
1275 rule.fw_number = i;
1276 i = setsockopt(s, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule);
1277 if (i)
1278 {
1279 exitval = EX_UNAVAILABLE;
1280 warn("rule %u: setsockopt(%s)", rule.fw_number, "IP_FW_DEL");
1281 }
b7080c8e
A
1282 }
1283 }
7ba0088d 1284
b7080c8e
A
1285 if (exitval != EX_OK)
1286 exit(exitval);
1287}
1288
1289static void
1290verify_interface(union ip_fw_if *ifu)
1291{
1292 struct ifreq ifr;
1293
1294 /*
1295 * If a unit was specified, check for that exact interface.
1296 * If a wildcard was specified, check for unit 0.
1297 */
7ba0088d 1298 snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d",
b7080c8e
A
1299 ifu->fu_via_if.name,
1300 ifu->fu_via_if.unit == -1 ? 0 : ifu->fu_via_if.unit);
1301
1302 if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0)
1303 warnx("warning: interface ``%s'' does not exist", ifr.ifr_name);
1304}
1305
1306static void
1307fill_iface(char *which, union ip_fw_if *ifu, int *byname, int ac, char *arg)
1308{
1309 if (!ac)
1310 show_usage("missing argument for ``%s''", which);
1311
1312 /* Parse the interface or address */
1313 if (!strcmp(arg, "any")) {
1314 ifu->fu_via_ip.s_addr = 0;
1315 *byname = 0;
1316 } else if (!isdigit(*arg)) {
1317 char *q;
1318
1319 *byname = 1;
1320 strncpy(ifu->fu_via_if.name, arg, sizeof(ifu->fu_via_if.name));
1321 ifu->fu_via_if.name[sizeof(ifu->fu_via_if.name) - 1] = '\0';
1322 for (q = ifu->fu_via_if.name;
1323 *q && !isdigit(*q) && *q != '*'; q++)
1324 continue;
1325 ifu->fu_via_if.unit = (*q == '*') ? -1 : atoi(q);
1326 *q = '\0';
1327 verify_interface(ifu);
1328 } else if (!inet_aton(arg, &ifu->fu_via_ip)) {
1329 show_usage("bad ip address ``%s''", arg);
1330 } else
1331 *byname = 0;
1332}
1333
7ba0088d 1334#ifdef DUMMYNET
b7080c8e
A
1335static void
1336config_pipe(int ac, char **av)
1337{
1338 struct dn_pipe pipe;
7ba0088d
A
1339 int i;
1340 char *end;
1341
b7080c8e 1342 memset(&pipe, 0, sizeof pipe);
7ba0088d 1343
b7080c8e
A
1344 av++; ac--;
1345 /* Pipe number */
1346 if (ac && isdigit(**av)) {
7ba0088d
A
1347 i = atoi(*av); av++; ac--;
1348 if (do_pipe == 1)
1349 pipe.pipe_nr = i;
1350 else
1351 pipe.fs.fs_nr = i;
b7080c8e
A
1352 }
1353 while (ac > 1) {
7ba0088d
A
1354 if (!strncmp(*av, "plr", strlen(*av))) {
1355
b7080c8e 1356 double d = strtod(av[1], NULL);
7ba0088d
A
1357 if (d > 1)
1358 d = 1;
1359 else if (d < 0)
1360 d = 0;
1361 pipe.fs.plr = (int)(d*0x7fffffff);
b7080c8e 1362 av+=2; ac-=2;
7ba0088d
A
1363 } else if (!strncmp(*av, "queue", strlen(*av))) {
1364 end = NULL;
1365 pipe.fs.qsize = strtoul(av[1], &end, 0);
1366 if (*end == 'K' || *end == 'k') {
1367 pipe.fs.flags_fs |= DN_QSIZE_IS_BYTES;
1368 pipe.fs.qsize *= 1024;
1369 } else if (*end == 'B' || !strncmp(end, "by", 2)) {
1370 pipe.fs.flags_fs |= DN_QSIZE_IS_BYTES;
b7080c8e
A
1371 }
1372 av+=2; ac-=2;
7ba0088d
A
1373 } else if (!strncmp(*av, "buckets", strlen(*av))) {
1374 pipe.fs.rq_size = strtoul(av[1], NULL, 0);
1375 av+=2; ac-=2;
1376 } else if (!strncmp(*av, "mask", strlen(*av))) {
1377 /* per-flow queue, mask is dst_ip, dst_port,
1378 * src_ip, src_port, proto measured in bits
1379 */
1380 u_int32_t a;
1381 u_int32_t *par = NULL;
1382
1383 pipe.fs.flow_mask.dst_ip = 0;
1384 pipe.fs.flow_mask.src_ip = 0;
1385 pipe.fs.flow_mask.dst_port = 0;
1386 pipe.fs.flow_mask.src_port = 0;
1387 pipe.fs.flow_mask.proto = 0;
1388 end = NULL;
1389 av++; ac--;
1390 if (ac >= 1 && !strncmp(*av, "all", strlen(*av))) {
1391 /* special case -- all bits are significant */
1392 pipe.fs.flow_mask.dst_ip = ~0;
1393 pipe.fs.flow_mask.src_ip = ~0;
1394 pipe.fs.flow_mask.dst_port = ~0;
1395 pipe.fs.flow_mask.src_port = ~0;
1396 pipe.fs.flow_mask.proto = ~0;
1397 pipe.fs.flags_fs |= DN_HAVE_FLOW_MASK;
1398 av++; ac--;
1399 } else {
1400 for (;;) {
1401 if (ac < 1)
1402 break;
1403 if (!strncmp(*av, "dst-ip", strlen(*av)))
1404 par = &(pipe.fs.flow_mask.dst_ip);
1405 else if (!strncmp(*av, "src-ip", strlen(*av)))
1406 par = &(pipe.fs.flow_mask.src_ip);
1407 else if (!strncmp(*av, "dst-port", strlen(*av)))
1408 (u_int16_t *)par = &(pipe.fs.flow_mask.dst_port);
1409 else if (!strncmp(*av, "src-port", strlen(*av)))
1410 (u_int16_t *)par = &(pipe.fs.flow_mask.src_port);
1411 else if (!strncmp(*av, "proto", strlen(*av)))
1412 (u_int8_t *)par = &(pipe.fs.flow_mask.proto);
1413 else
1414 break;
1415 if (ac < 2)
1416 show_usage("mask: %s value missing", *av);
1417 if (*av[1] == '/') {
1418 a = strtoul(av[1]+1, &end, 0);
1419 if (a == 32) /* special case... */
1420 a = ~0;
1421 else
1422 a = (1 << a) - 1;
1423 fprintf(stderr, " mask is 0x%08x\n", a);
1424 } else
1425 a = strtoul(av[1], &end, 0);
1426 if ((u_int16_t *)par == &(pipe.fs.flow_mask.src_port) ||
1427 (u_int16_t *)par == &(pipe.fs.flow_mask.dst_port)) {
1428 if (a >= (1<<16))
1429 show_usage("mask: %s must be 16 bit, not 0x%08x",
1430 *av, a);
1431 *((u_int16_t *)par) = (u_int16_t) a;
1432 } else if ((u_int8_t *)par == &(pipe.fs.flow_mask.proto)) {
1433 if (a >= (1<<8))
1434 show_usage("mask: %s must be 8 bit, not 0x%08x",
1435 *av, a);
1436 *((u_int8_t *)par) = (u_int8_t) a;
1437 } else
1438 *par = a;
1439 if (a != 0)
1440 pipe.fs.flags_fs |= DN_HAVE_FLOW_MASK;
1441 av += 2; ac -= 2;
1442 } /* end for */
1443 }
1444 } else if (!strncmp(*av, "red", strlen(*av)) ||
1445 !strncmp(*av, "gred", strlen(*av))) { /* RED enabled */
1446 pipe.fs.flags_fs |= DN_IS_RED;
1447 if (*av[0] == 'g')
1448 pipe.fs.flags_fs |= DN_IS_GENTLE_RED;
1449 if ((end = strsep(&av[1],"/"))) {
1450 double w_q = strtod(end, NULL);
1451 if (w_q > 1 || w_q <= 0)
1452 show_usage("w_q %f must be 0 < x <= 1", w_q);
1453 pipe.fs.w_q = (int) (w_q * (1 << SCALE_RED));
1454 }
1455 if ((end = strsep(&av[1],"/"))) {
1456 pipe.fs.min_th = strtoul(end, &end, 0);
1457 if (*end == 'K' || *end == 'k')
1458 pipe.fs.min_th *= 1024;
1459 }
1460 if ((end = strsep(&av[1],"/"))) {
1461 pipe.fs.max_th = strtoul(end, &end, 0);
1462 if (*end == 'K' || *end == 'k')
1463 pipe.fs.max_th *= 1024;
1464 }
1465 if ((end = strsep(&av[1],"/"))) {
1466 double max_p = strtod(end, NULL);
1467 if (max_p > 1 || max_p <= 0)
1468 show_usage("max_p %f must be 0 < x <= 1", max_p);
1469 pipe.fs.max_p = (int) (max_p * (1 << SCALE_RED));
1470 }
1471 av+=2; ac-=2;
1472 } else if (!strncmp(*av, "droptail", strlen(*av))) { /* DROPTAIL */
1473 pipe.fs.flags_fs &= ~(DN_IS_RED|DN_IS_GENTLE_RED);
1474 av+=1; ac-=1;
1475 } else {
1476 if (do_pipe == 1) {
1477 /* some commands are only good for pipes. */
1478 if (!strncmp(*av, "bw", strlen(*av)) ||
1479 ! strncmp(*av, "bandwidth", strlen(*av))) {
1480 if (av[1][0] >= 'a' && av[1][0] <= 'z') {
1481 int l = sizeof(pipe.if_name)-1;
1482 /* interface name */
1483 strncpy(pipe.if_name, av[1], l);
1484 pipe.if_name[l] = '\0';
1485 pipe.bandwidth = 0;
1486 } else {
1487 pipe.if_name[0] = '\0';
1488 pipe.bandwidth = strtoul(av[1], &end, 0);
1489 if (*end == 'K' || *end == 'k')
1490 end++, pipe.bandwidth *= 1000;
1491 else if (*end == 'M')
1492 end++, pipe.bandwidth *= 1000000;
1493 if (*end == 'B' || !strncmp(end, "by", 2))
1494 pipe.bandwidth *= 8;
1495 }
1496 av+=2; ac-=2;
1497 } else if (!strncmp(*av, "delay", strlen(*av))) {
1498 pipe.delay = strtoul(av[1], NULL, 0);
1499 av+=2; ac-=2;
1500 } else
1501 show_usage("unrecognised pipe option ``%s''", *av);
1502 } else { /* this refers to a queue */
1503 if (!strncmp(*av, "weight", strlen(*av))) {
1504 pipe.fs.weight = strtoul(av[1], &end, 0);
1505 av += 2;
1506 ac -= 2;
1507 } else if (!strncmp(*av, "pipe", strlen(*av))) {
1508 pipe.fs.parent_nr = strtoul(av[1], &end, 0);
1509 av += 2;
1510 ac -= 2;
b7080c8e
A
1511 } else
1512 show_usage("unrecognised option ``%s''", *av);
1513 }
7ba0088d
A
1514 }
1515 }
1516 if (do_pipe == 1) {
1517 if (pipe.pipe_nr == 0)
1518 show_usage("pipe_nr %d must be > 0", pipe.pipe_nr);
1519 if (pipe.delay > 10000)
b7080c8e 1520 show_usage("delay %d must be < 10000", pipe.delay);
7ba0088d
A
1521 } else { /* do_pipe == 2, queue */
1522 if (pipe.fs.parent_nr == 0)
1523 show_usage("pipe %d must be > 0", pipe.fs.parent_nr);
1524 if (pipe.fs.weight >100)
1525 show_usage("weight %d must be <= 100", pipe.fs.weight);
1526 }
1527 if (pipe.fs.flags_fs & DN_QSIZE_IS_BYTES) {
1528 if (pipe.fs.qsize > 1024*1024)
1529 show_usage("queue size %d, must be < 1MB",
1530 pipe.fs.qsize);
1531 } else {
1532 if (pipe.fs.qsize > 100)
1533 show_usage("queue size %d, must be 2 <= x <= 100",
1534 pipe.fs.qsize);
1535 }
1536 if (pipe.fs.flags_fs & DN_IS_RED) {
1537 if (pipe.fs.min_th >= pipe.fs.max_th)
1538 show_usage("min_th %d must be < than max_th %d",
1539 pipe.fs.min_th, pipe.fs.max_th);
1540 if (pipe.fs.max_th == 0)
1541 show_usage("max_th must be > 0");
1542 if (pipe.bandwidth) {
1543 size_t len;
1544 int lookup_depth, avg_pkt_size;
1545 double s, idle, weight, w_q;
1546 struct clockinfo clock;
1547 int t;
1548
1549 len = sizeof(int);
1550 if (sysctlbyname("net.inet.ip.dummynet.red_lookup_depth",
1551 &lookup_depth, &len, NULL, 0) == -1)
1552
1553 errx(1, "sysctlbyname(\"%s\")",
1554 "net.inet.ip.dummynet.red_lookup_depth");
1555 if (lookup_depth == 0)
1556 show_usage("net.inet.ip.dummynet.red_lookup_depth must"
1557 "greater than zero");
1558
1559 len = sizeof(int);
1560 if (sysctlbyname("net.inet.ip.dummynet.red_avg_pkt_size",
1561 &avg_pkt_size, &len, NULL, 0) == -1)
1562
1563 errx(1, "sysctlbyname(\"%s\")",
1564 "net.inet.ip.dummynet.red_avg_pkt_size");
1565 if (avg_pkt_size == 0)
1566 show_usage("net.inet.ip.dummynet.red_avg_pkt_size must"
1567 "greater than zero");
1568
1569 len = sizeof(struct clockinfo);
1570 if (sysctlbyname("kern.clockrate",
1571 &clock, &len, NULL, 0) == -1)
1572 errx(1, "sysctlbyname(\"%s\")", "kern.clockrate");
1573
1574 /* ticks needed for sending a medium-sized packet */
1575 s = clock.hz * avg_pkt_size * 8 / pipe.bandwidth;
1576
1577 /*
1578 * max idle time (in ticks) before avg queue size becomes 0.
1579 * NOTA: (3/w_q) is approx the value x so that
1580 * (1-w_q)^x < 10^-3.
1581 */
1582 w_q = ((double) pipe.fs.w_q) / (1 << SCALE_RED);
1583 idle = s * 3. / w_q;
1584 pipe.fs.lookup_step = (int) idle / lookup_depth;
1585 if (!pipe.fs.lookup_step)
1586 pipe.fs.lookup_step = 1;
1587 weight = 1 - w_q;
1588 for (t = pipe.fs.lookup_step; t > 0; --t)
1589 weight *= weight;
1590 pipe.fs.lookup_weight = (int) (weight * (1 << SCALE_RED));
1591 }
1592 }
b7080c8e
A
1593#if 0
1594 printf("configuring pipe %d bw %d delay %d size %d\n",
1595 pipe.pipe_nr, pipe.bandwidth, pipe.delay, pipe.queue_size);
1596#endif
7ba0088d 1597 i = setsockopt(s,IPPROTO_IP, IP_DUMMYNET_CONFIGURE, &pipe, sizeof pipe);
b7080c8e
A
1598 if (i)
1599 err(1, "setsockopt(%s)", "IP_DUMMYNET_CONFIGURE");
7ba0088d 1600
b7080c8e 1601}
7ba0088d 1602#endif /* DUMMYNET */
b7080c8e
A
1603
1604static void
7ba0088d 1605add(ac, av)
b7080c8e
A
1606 int ac;
1607 char **av;
1608{
1609 struct ip_fw rule;
1610 int i;
1611 u_char proto;
1612 struct protoent *pe;
1613 int saw_xmrc = 0, saw_via = 0;
7ba0088d 1614
b7080c8e 1615 memset(&rule, 0, sizeof rule);
7ba0088d 1616 rule.version = IP_FW_CURRENT_API_VERSION;
b7080c8e
A
1617
1618 av++; ac--;
1619
1620 /* Rule number */
1621 if (ac && isdigit(**av)) {
1622 rule.fw_number = atoi(*av); av++; ac--;
1623 }
1624
1625 /* Action */
7ba0088d
A
1626 if (ac > 1 && !strncmp(*av, "prob", strlen(*av))) {
1627 double d = strtod(av[1], NULL);
1628 if (d <= 0 || d > 1)
1629 show_usage("illegal match prob. %s", av[1]);
1630 if (d != 1) { /* 1 means always match */
1631 rule.fw_flg |= IP_FW_F_RND_MATCH;
1632 /* we really store dont_match probability */
1633 (long)rule.pipe_ptr = (long)((1 - d) * 0x7fffffff);
1634 }
1635 av += 2; ac -= 2;
1636 }
1637
b7080c8e
A
1638 if (ac == 0)
1639 show_usage("missing action");
7ba0088d
A
1640 if (!strncmp(*av, "accept", strlen(*av))
1641 || !strncmp(*av, "pass" ,strlen(*av))
1642 || !strncmp(*av, "allow", strlen(*av))
1643 || !strncmp(*av, "permit", strlen(*av))) {
b7080c8e 1644 rule.fw_flg |= IP_FW_F_ACCEPT; av++; ac--;
7ba0088d 1645 } else if (!strncmp(*av, "count", strlen(*av))) {
b7080c8e 1646 rule.fw_flg |= IP_FW_F_COUNT; av++; ac--;
7ba0088d
A
1647 }
1648 #ifdef DUMMYNET
1649 else if (!strncmp(*av, "pipe", strlen(*av))) {
b7080c8e
A
1650 rule.fw_flg |= IP_FW_F_PIPE; av++; ac--;
1651 if (!ac)
1652 show_usage("missing pipe number");
1653 rule.fw_divert_port = strtoul(*av, NULL, 0); av++; ac--;
7ba0088d
A
1654 } else if (!strncmp(*av, "queue", strlen(*av))) {
1655 rule.fw_flg |= IP_FW_F_QUEUE; av++; ac--;
1656 if (!ac)
1657 show_usage("missing queue number");
1658 rule.fw_divert_port = strtoul(*av, NULL, 0); av++; ac--;
1659 }
1660 #endif /* DUMMYNET */
1661 else if (!strncmp(*av, "divert", strlen(*av))) {
b7080c8e
A
1662 rule.fw_flg |= IP_FW_F_DIVERT; av++; ac--;
1663 if (!ac)
1664 show_usage("missing %s port", "divert");
1665 rule.fw_divert_port = strtoul(*av, NULL, 0); av++; ac--;
1666 if (rule.fw_divert_port == 0) {
1667 struct servent *s;
1668 setservent(1);
1669 s = getservbyname(av[-1], "divert");
1670 if (s != NULL)
1671 rule.fw_divert_port = ntohs(s->s_port);
1672 else
1673 show_usage("illegal %s port", "divert");
1674 }
7ba0088d 1675 } else if (!strncmp(*av, "tee", strlen(*av))) {
b7080c8e
A
1676 rule.fw_flg |= IP_FW_F_TEE; av++; ac--;
1677 if (!ac)
1678 show_usage("missing %s port", "tee divert");
1679 rule.fw_divert_port = strtoul(*av, NULL, 0); av++; ac--;
1680 if (rule.fw_divert_port == 0) {
1681 struct servent *s;
1682 setservent(1);
1683 s = getservbyname(av[-1], "divert");
1684 if (s != NULL)
1685 rule.fw_divert_port = ntohs(s->s_port);
1686 else
1687 show_usage("illegal %s port", "tee divert");
1688 }
7ba0088d
A
1689 } else if (!strncmp(*av, "fwd", strlen(*av)) ||
1690 !strncmp(*av, "forward", strlen(*av))) {
b7080c8e
A
1691 struct in_addr dummyip;
1692 char *pp;
1693 rule.fw_flg |= IP_FW_F_FWD; av++; ac--;
1694 if (!ac)
1695 show_usage("missing forwarding IP address");
1696 rule.fw_fwd_ip.sin_len = sizeof(struct sockaddr_in);
1697 rule.fw_fwd_ip.sin_family = AF_INET;
1698 rule.fw_fwd_ip.sin_port = 0;
1699 pp = strchr(*av, ':');
1700 if(pp == NULL)
1701 pp = strchr(*av, ',');
1702 if(pp != NULL)
1703 {
1704 *(pp++) = '\0';
7ba0088d
A
1705 i = lookup_port(pp, 0, 1, 0);
1706 if (i == -1)
1707 show_usage("illegal forwarding port ``%s''", pp);
1708 else
1709 rule.fw_fwd_ip.sin_port = (u_short)i;
b7080c8e
A
1710 }
1711 fill_ip(&(rule.fw_fwd_ip.sin_addr), &dummyip, &ac, &av);
1712 if (rule.fw_fwd_ip.sin_addr.s_addr == 0)
1713 show_usage("illegal forwarding IP address");
1714
7ba0088d 1715 } else if (!strncmp(*av, "skipto", strlen(*av))) {
b7080c8e
A
1716 rule.fw_flg |= IP_FW_F_SKIPTO; av++; ac--;
1717 if (!ac)
1718 show_usage("missing skipto rule number");
1719 rule.fw_skipto_rule = strtoul(*av, NULL, 0); av++; ac--;
7ba0088d
A
1720 } else if ((!strncmp(*av, "deny", strlen(*av))
1721 || !strncmp(*av, "drop", strlen(*av)))) {
b7080c8e 1722 rule.fw_flg |= IP_FW_F_DENY; av++; ac--;
7ba0088d 1723 } else if (!strncmp(*av, "reject", strlen(*av))) {
b7080c8e
A
1724 rule.fw_flg |= IP_FW_F_REJECT; av++; ac--;
1725 rule.fw_reject_code = ICMP_UNREACH_HOST;
7ba0088d 1726 } else if (!strncmp(*av, "reset", strlen(*av))) {
b7080c8e
A
1727 rule.fw_flg |= IP_FW_F_REJECT; av++; ac--;
1728 rule.fw_reject_code = IP_FW_REJECT_RST; /* check TCP later */
7ba0088d 1729 } else if (!strncmp(*av, "unreach", strlen(*av))) {
b7080c8e
A
1730 rule.fw_flg |= IP_FW_F_REJECT; av++; ac--;
1731 fill_reject_code(&rule.fw_reject_code, *av); av++; ac--;
7ba0088d
A
1732 } else if (!strncmp(*av, "check-state", strlen(*av))) {
1733 rule.fw_flg |= IP_FW_F_CHECK_S; av++; ac--;
1734 goto done;
b7080c8e
A
1735 } else {
1736 show_usage("invalid action ``%s''", *av);
1737 }
1738
1739 /* [log] */
7ba0088d 1740 if (ac && !strncmp(*av, "log", strlen(*av))) {
b7080c8e
A
1741 rule.fw_flg |= IP_FW_F_PRN; av++; ac--;
1742 }
7ba0088d
A
1743 if (ac && !strncmp(*av, "logamount", strlen(*av))) {
1744 if (!(rule.fw_flg & IP_FW_F_PRN))
1745 show_usage("``logamount'' not valid without ``log''");
1746 ac--; av++;
1747 if (!ac)
1748 show_usage("``logamount'' requires argument");
1749 rule.fw_logamount = atoi(*av);
1750 if (rule.fw_logamount < 0)
1751 show_usage("``logamount'' argument must be positive");
1752 if (rule.fw_logamount == 0)
1753 rule.fw_logamount = -1;
1754 ac--; av++;
1755 }
b7080c8e
A
1756
1757 /* protocol */
1758 if (ac == 0)
1759 show_usage("missing protocol");
1760 if ((proto = atoi(*av)) > 0) {
1761 rule.fw_prot = proto; av++; ac--;
7ba0088d 1762 } else if (!strncmp(*av, "all", strlen(*av))) {
b7080c8e
A
1763 rule.fw_prot = IPPROTO_IP; av++; ac--;
1764 } else if ((pe = getprotobyname(*av)) != NULL) {
1765 rule.fw_prot = pe->p_proto; av++; ac--;
1766 } else {
1767 show_usage("invalid protocol ``%s''", *av);
1768 }
1769
1770 if (rule.fw_prot != IPPROTO_TCP
1771 && (rule.fw_flg & IP_FW_F_COMMAND) == IP_FW_F_REJECT
1772 && rule.fw_reject_code == IP_FW_REJECT_RST)
1773 show_usage("``reset'' is only valid for tcp packets");
1774
1775 /* from */
7ba0088d 1776 if (ac && !strncmp(*av, "from", strlen(*av))) { av++; ac--; }
b7080c8e
A
1777 else
1778 show_usage("missing ``from''");
1779
7ba0088d 1780 if (ac && !strncmp(*av, "not", strlen(*av))) {
b7080c8e
A
1781 rule.fw_flg |= IP_FW_F_INVSRC;
1782 av++; ac--;
1783 }
1784 if (!ac)
1785 show_usage("missing arguments");
1786
7ba0088d
A
1787 if (ac && !strncmp(*av, "me", strlen(*av))) {
1788 rule.fw_flg |= IP_FW_F_SME;
1789 av++; ac--;
1790 } else {
1791 fill_ip(&rule.fw_src, &rule.fw_smsk, &ac, &av);
1792 }
b7080c8e 1793
7ba0088d 1794 if (ac && (isdigit(**av) || lookup_port(*av, rule.fw_prot, 1, 1) >= 0)) {
b7080c8e 1795 u_short nports = 0;
7ba0088d 1796 int retval;
b7080c8e 1797
7ba0088d
A
1798 retval = fill_port(&nports, rule.fw_uar.fw_pts, 0, *av, rule.fw_prot);
1799 if (retval == 1)
b7080c8e 1800 rule.fw_flg |= IP_FW_F_SRNG;
7ba0088d
A
1801 else if (retval == 2)
1802 rule.fw_flg |= IP_FW_F_SMSK;
b7080c8e
A
1803 IP_FW_SETNSRCP(&rule, nports);
1804 av++; ac--;
1805 }
1806
1807 /* to */
7ba0088d 1808 if (ac && !strncmp(*av, "to", strlen(*av))) { av++; ac--; }
b7080c8e
A
1809 else
1810 show_usage("missing ``to''");
1811
7ba0088d 1812 if (ac && !strncmp(*av, "not", strlen(*av))) {
b7080c8e
A
1813 rule.fw_flg |= IP_FW_F_INVDST;
1814 av++; ac--;
1815 }
1816 if (!ac)
1817 show_usage("missing arguments");
1818
7ba0088d
A
1819 if (ac && !strncmp(*av, "me", strlen(*av))) {
1820 rule.fw_flg |= IP_FW_F_DME;
1821 av++; ac--;
1822 } else {
1823 fill_ip(&rule.fw_dst, &rule.fw_dmsk, &ac, &av);
1824 }
b7080c8e 1825
7ba0088d 1826 if (ac && (isdigit(**av) || lookup_port(*av, rule.fw_prot, 1, 1) >= 0)) {
b7080c8e 1827 u_short nports = 0;
7ba0088d 1828 int retval;
b7080c8e 1829
7ba0088d
A
1830 retval = fill_port(&nports,
1831 rule.fw_uar.fw_pts, IP_FW_GETNSRCP(&rule), *av, rule.fw_prot);
1832 if (retval == 1)
b7080c8e 1833 rule.fw_flg |= IP_FW_F_DRNG;
7ba0088d
A
1834 else if (retval == 2)
1835 rule.fw_flg |= IP_FW_F_DMSK;
b7080c8e
A
1836 IP_FW_SETNDSTP(&rule, nports);
1837 av++; ac--;
1838 }
1839
1840 if ((rule.fw_prot != IPPROTO_TCP) && (rule.fw_prot != IPPROTO_UDP)
1841 && (IP_FW_GETNSRCP(&rule) || IP_FW_GETNDSTP(&rule))) {
1842 show_usage("only TCP and UDP protocols are valid"
1843 " with port specifications");
1844 }
1845
1846 while (ac) {
7ba0088d
A
1847 if (!strncmp(*av, "uid", strlen(*av))) {
1848 struct passwd *pwd;
1849 char *end;
1850 uid_t uid;
1851
1852 rule.fw_flg |= IP_FW_F_UID;
1853 ac--; av++;
1854 if (!ac)
1855 show_usage("``uid'' requires argument");
1856
1857 uid = strtoul(*av, &end, 0);
1858 if (*end == '\0')
1859 pwd = getpwuid(uid);
1860 else
1861 pwd = getpwnam(*av);
1862 if (pwd == NULL)
1863 show_usage("uid \"%s\" is nonexistant", *av);
1864 rule.fw_uid = pwd->pw_uid;
1865 ac--; av++;
1866 continue;
1867 }
1868 if (!strncmp(*av, "in", strlen(*av))) {
b7080c8e
A
1869 rule.fw_flg |= IP_FW_F_IN;
1870 av++; ac--; continue;
1871 }
7ba0088d
A
1872 if (!strncmp(*av, "keep-state", strlen(*av))) {
1873 u_long type;
1874 rule.fw_flg |= IP_FW_F_KEEP_S;
1875
1876 av++; ac--;
1877 if (ac > 0 && (type = atoi(*av)) != 0) {
1878 (int)rule.next_rule_ptr = type;
1879 av++; ac--;
1880 }
1881 continue;
1882 }
1883 if (!strncmp(*av, "bridged", strlen(*av))) {
1884 rule.fw_flg |= IP_FW_BRIDGED;
1885 av++; ac--; continue;
1886 }
1887 if (!strncmp(*av, "out", strlen(*av))) {
b7080c8e
A
1888 rule.fw_flg |= IP_FW_F_OUT;
1889 av++; ac--; continue;
1890 }
7ba0088d 1891 if (ac && !strncmp(*av, "xmit", strlen(*av))) {
b7080c8e
A
1892 union ip_fw_if ifu;
1893 int byname;
1894
1895 if (saw_via) {
1896badviacombo:
1897 show_usage("``via'' is incompatible"
1898 " with ``xmit'' and ``recv''");
1899 }
1900 saw_xmrc = 1;
7ba0088d 1901 av++; ac--;
b7080c8e
A
1902 fill_iface("xmit", &ifu, &byname, ac, *av);
1903 rule.fw_out_if = ifu;
1904 rule.fw_flg |= IP_FW_F_OIFACE;
1905 if (byname)
1906 rule.fw_flg |= IP_FW_F_OIFNAME;
1907 av++; ac--; continue;
1908 }
7ba0088d 1909 if (ac && !strncmp(*av, "recv", strlen(*av))) {
b7080c8e
A
1910 union ip_fw_if ifu;
1911 int byname;
1912
1913 if (saw_via)
1914 goto badviacombo;
1915 saw_xmrc = 1;
7ba0088d 1916 av++; ac--;
b7080c8e
A
1917 fill_iface("recv", &ifu, &byname, ac, *av);
1918 rule.fw_in_if = ifu;
1919 rule.fw_flg |= IP_FW_F_IIFACE;
1920 if (byname)
1921 rule.fw_flg |= IP_FW_F_IIFNAME;
1922 av++; ac--; continue;
1923 }
7ba0088d 1924 if (ac && !strncmp(*av, "via", strlen(*av))) {
b7080c8e
A
1925 union ip_fw_if ifu;
1926 int byname = 0;
1927
1928 if (saw_xmrc)
1929 goto badviacombo;
1930 saw_via = 1;
7ba0088d 1931 av++; ac--;
b7080c8e
A
1932 fill_iface("via", &ifu, &byname, ac, *av);
1933 rule.fw_out_if = rule.fw_in_if = ifu;
1934 if (byname)
1935 rule.fw_flg |=
1936 (IP_FW_F_IIFNAME | IP_FW_F_OIFNAME);
1937 av++; ac--; continue;
1938 }
7ba0088d 1939 if (!strncmp(*av, "fragment", strlen(*av))) {
b7080c8e
A
1940 rule.fw_flg |= IP_FW_F_FRAG;
1941 av++; ac--; continue;
1942 }
7ba0088d
A
1943 if (!strncmp(*av, "ipoptions", strlen(*av))) {
1944 av++; ac--;
b7080c8e
A
1945 if (!ac)
1946 show_usage("missing argument"
1947 " for ``ipoptions''");
1948 fill_ipopt(&rule.fw_ipopt, &rule.fw_ipnopt, av);
1949 av++; ac--; continue;
1950 }
1951 if (rule.fw_prot == IPPROTO_TCP) {
7ba0088d
A
1952 if (!strncmp(*av, "established", strlen(*av))) {
1953 rule.fw_ipflg |= IP_FW_IF_TCPEST;
b7080c8e
A
1954 av++; ac--; continue;
1955 }
7ba0088d 1956 if (!strncmp(*av, "setup", strlen(*av))) {
b7080c8e
A
1957 rule.fw_tcpf |= IP_FW_TCPF_SYN;
1958 rule.fw_tcpnf |= IP_FW_TCPF_ACK;
1959 av++; ac--; continue;
1960 }
7ba0088d
A
1961 if (!strncmp(*av, "tcpflags", strlen(*av)) ||
1962 !strncmp(*av, "tcpflgs", strlen(*av))) {
1963 av++; ac--;
b7080c8e
A
1964 if (!ac)
1965 show_usage("missing argument"
1966 " for ``tcpflags''");
1967 fill_tcpflag(&rule.fw_tcpf, &rule.fw_tcpnf, av);
1968 av++; ac--; continue;
1969 }
7ba0088d
A
1970 if (!strncmp(*av, "tcpoptions", strlen(*av)) ||
1971 !strncmp(*av, "tcpopts", strlen(*av))) {
1972 av++; ac--;
1973 if (!ac)
1974 show_usage("missing argument"
1975 " for ``tcpoptions''");
1976 fill_tcpopts(&rule.fw_tcpopt, &rule.fw_tcpnopt, av);
1977 av++; ac--; continue;
1978 }
b7080c8e
A
1979 }
1980 if (rule.fw_prot == IPPROTO_ICMP) {
7ba0088d 1981 if (!strncmp(*av, "icmptypes", strlen(*av))) {
b7080c8e
A
1982 av++; ac--;
1983 if (!ac)
1984 show_usage("missing argument"
1985 " for ``icmptypes''");
1986 fill_icmptypes(rule.fw_uar.fw_icmptypes,
1987 av, &rule.fw_flg);
1988 av++; ac--; continue;
1989 }
1990 }
1991 show_usage("unknown argument ``%s''", *av);
1992 }
1993
1994 /* No direction specified -> do both directions */
1995 if (!(rule.fw_flg & (IP_FW_F_OUT|IP_FW_F_IN)))
1996 rule.fw_flg |= (IP_FW_F_OUT|IP_FW_F_IN);
1997
1998 /* Sanity check interface check, but handle "via" case separately */
1999 if (saw_via) {
2000 if (rule.fw_flg & IP_FW_F_IN)
2001 rule.fw_flg |= IP_FW_F_IIFACE;
2002 if (rule.fw_flg & IP_FW_F_OUT)
2003 rule.fw_flg |= IP_FW_F_OIFACE;
2004 } else if ((rule.fw_flg & IP_FW_F_OIFACE) && (rule.fw_flg & IP_FW_F_IN))
2005 show_usage("can't check xmit interface of incoming packets");
2006
2007 /* frag may not be used in conjunction with ports or TCP flags */
2008 if (rule.fw_flg & IP_FW_F_FRAG) {
2009 if (rule.fw_tcpf || rule.fw_tcpnf)
2010 show_usage("can't mix 'frag' and tcpflags");
2011
2012 if (rule.fw_nports)
2013 show_usage("can't mix 'frag' and port specifications");
2014 }
7ba0088d
A
2015 if (rule.fw_flg & IP_FW_F_PRN) {
2016 if (!rule.fw_logamount) {
2017 size_t len = sizeof(int);
2018
2019 if (sysctlbyname("net.inet.ip.fw.verbose_limit",
2020 &rule.fw_logamount, &len, NULL, 0) == -1)
2021 errx(1, "sysctlbyname(\"%s\")",
2022 "net.inet.ip.fw.verbose_limit");
2023 } else if (rule.fw_logamount == -1)
2024 rule.fw_logamount = 0;
2025 rule.fw_loghighest = rule.fw_logamount;
2026 }
2027done:
2028 i = sizeof(rule);
2029 if (getsockopt(s, IPPROTO_IP, IP_FW_ADD, &rule, &i) == -1)
2030 err(EX_UNAVAILABLE, "getsockopt(%s)", "IP_FW_ADD");
b7080c8e
A
2031 if (!do_quiet)
2032 show_ipfw(&rule, 10, 10);
b7080c8e
A
2033}
2034
2035static void
2036zero (ac, av)
2037 int ac;
2038 char **av;
2039{
7ba0088d
A
2040 struct ip_fw rule;
2041 memset(&rule, 0, sizeof rule);
2042 rule.version = IP_FW_CURRENT_API_VERSION;
2043
b7080c8e
A
2044 av++; ac--;
2045
2046 if (!ac) {
2047 /* clear all entries */
7ba0088d 2048 if (setsockopt(s, IPPROTO_IP, IP_FW_ZERO, &rule, sizeof rule) < 0)
b7080c8e
A
2049 err(EX_UNAVAILABLE, "setsockopt(%s)", "IP_FW_ZERO");
2050 if (!do_quiet)
2051 printf("Accounting cleared.\n");
2052 } else {
b7080c8e
A
2053 int failed = EX_OK;
2054
b7080c8e
A
2055 while (ac) {
2056 /* Rule number */
2057 if (isdigit(**av)) {
2058 rule.fw_number = atoi(*av); av++; ac--;
2059 if (setsockopt(s, IPPROTO_IP,
2060 IP_FW_ZERO, &rule, sizeof rule)) {
2061 warn("rule %u: setsockopt(%s)", rule.fw_number,
2062 "IP_FW_ZERO");
2063 failed = EX_UNAVAILABLE;
2064 }
2065 else if (!do_quiet)
2066 printf("Entry %d cleared\n",
2067 rule.fw_number);
2068 } else
2069 show_usage("invalid rule number ``%s''", *av);
2070 }
2071 if (failed != EX_OK)
2072 exit(failed);
2073 }
2074}
2075
7ba0088d
A
2076static void
2077resetlog (ac, av)
2078 int ac;
2079 char **av;
2080{
2081 struct ip_fw rule;
2082 memset(&rule, 0, sizeof rule);
2083 rule.version = IP_FW_CURRENT_API_VERSION;
2084
2085 av++; ac--;
2086
2087 if (!ac) {
2088 /* clear all entries */
2089 if (setsockopt(s, IPPROTO_IP, IP_FW_RESETLOG, &rule, sizeof rule) < 0)
2090 err(EX_UNAVAILABLE, "setsockopt(%s)", "IP_FW_RESETLOG");
2091 if (!do_quiet)
2092 printf("Logging counts reset.\n");
2093 } else {
2094 int failed = EX_OK;
2095
2096 while (ac) {
2097 /* Rule number */
2098 if (isdigit(**av)) {
2099 rule.fw_number = atoi(*av); av++; ac--;
2100 if (setsockopt(s, IPPROTO_IP,
2101 IP_FW_RESETLOG, &rule, sizeof rule)) {
2102 warn("rule %u: setsockopt(%s)", rule.fw_number,
2103 "IP_FW_RESETLOG");
2104 failed = EX_UNAVAILABLE;
2105 }
2106 else if (!do_quiet)
2107 printf("Entry %d logging count reset\n",
2108 rule.fw_number);
2109 } else
2110 show_usage("invalid rule number ``%s''", *av);
2111 }
2112 if (failed != EX_OK)
2113 exit(failed);
2114 }
2115}
2116
b7080c8e 2117static int
7ba0088d 2118ipfw_main(ac, av)
b7080c8e
A
2119 int ac;
2120 char **av;
2121{
2122
2123 int ch;
b7080c8e 2124
7ba0088d 2125 if (ac == 1) {
b7080c8e
A
2126 show_usage(NULL);
2127 }
2128
2129 /* Set the force flag for non-interactive processes */
2130 do_force = !isatty(STDIN_FILENO);
2131
2132 optind = optreset = 1;
7ba0088d 2133 while ((ch = getopt(ac, av, "s:afqtvN")) != -1)
b7080c8e 2134 switch(ch) {
7ba0088d
A
2135 case 's': /* sort */
2136 do_sort= atoi(optarg);
2137 break;
b7080c8e 2138 case 'a':
7ba0088d 2139 do_acct = 1;
b7080c8e
A
2140 break;
2141 case 'f':
7ba0088d 2142 do_force = 1;
b7080c8e
A
2143 break;
2144 case 'q':
7ba0088d 2145 do_quiet = 1;
b7080c8e
A
2146 break;
2147 case 't':
7ba0088d
A
2148 do_time = 1;
2149 break;
2150 case 'v': /* verbose */
2151 verbose++;
b7080c8e
A
2152 break;
2153 case 'N':
7ba0088d 2154 do_resolv = 1;
b7080c8e
A
2155 break;
2156 default:
2157 show_usage(NULL);
2158 }
2159
2160 ac -= optind;
2161 if (*(av+=optind)==NULL) {
7ba0088d 2162 show_usage("bad arguments");
b7080c8e
A
2163 }
2164
7ba0088d
A
2165 #ifdef DUMMYNET
2166 if (!strncmp(*av, "pipe", strlen(*av))) {
2167 do_pipe = 1;
2168 ac--;
2169 av++;
2170 } else if (!strncmp(*av, "queue", strlen(*av))) {
2171 do_pipe = 2;
2172 ac--;
2173 av++;
2174 }
b7080c8e
A
2175 if (!ac) {
2176 show_usage("pipe requires arguments");
2177 }
7ba0088d
A
2178 #endif /* DUMMYNET */
2179
2180 /* allow argument swapping */
2181 if (ac > 1 && *av[0] >= '0' && *av[0] <= '9') {
2182 char *p = av[0];
2183 av[0] = av[1];
2184 av[1] = p;
2185 }
b7080c8e 2186 if (!strncmp(*av, "add", strlen(*av))) {
7ba0088d
A
2187 add(ac, av);
2188 }
2189 #ifdef DUMMYNET
2190 else if (do_pipe && !strncmp(*av, "config", strlen(*av))) {
2191 config_pipe(ac, av);
2192 }
2193 #endif /* DUMMYNET */
2194 else if (!strncmp(*av, "delete", strlen(*av))) {
2195 delete(ac, av);
b7080c8e
A
2196 } else if (!strncmp(*av, "flush", strlen(*av))) {
2197 int do_flush = 0;
2198
7ba0088d 2199 if (do_force || do_quiet)
b7080c8e
A
2200 do_flush = 1;
2201 else {
2202 int c;
2203
2204 /* Ask the user */
2205 printf("Are you sure? [yn] ");
7ba0088d 2206 fflush(stdout);
b7080c8e 2207 do {
b7080c8e
A
2208 c = toupper(getc(stdin));
2209 while (c != '\n' && getc(stdin) != '\n')
2210 if (feof(stdin))
2211 return (0);
2212 } while (c != 'Y' && c != 'N');
2213 printf("\n");
7ba0088d 2214 if (c == 'Y')
b7080c8e
A
2215 do_flush = 1;
2216 }
7ba0088d
A
2217 if (do_flush) {
2218 int error = 0;
2219
2220 #ifdef DUMMYNET
2221 if (do_pipe)
2222 {
2223 error = setsockopt(s, IPPROTO_IP, IP_DUMMYNET_FLUSH, NULL, 0);
2224 }
2225 else
2226 #endif /* DUMMYNET */
2227 {
2228 struct ip_fw rule;
2229 memset(&rule, 0, sizeof rule);
2230 rule.version = IP_FW_CURRENT_API_VERSION;
2231 error = setsockopt(s, IPPROTO_IP, IP_FW_FLUSH, &rule, sizeof rule);
2232 }
2233
2234 if (error < 0)
2235 #ifdef DUMMYNET
2236 err(EX_UNAVAILABLE, "setsockopt(IP_%s_FLUSH)",
2237 do_pipe ? "DUMMYNET" : "FW");
2238 #else /* DUMMYNET */
2239 err(EX_UNAVAILABLE, "setsockopt(IP_FW_FLUSH)");
2240 #endif /* DUMMYNET */
b7080c8e 2241 if (!do_quiet)
7ba0088d
A
2242 #ifdef DUMMYNET
2243 printf("Flushed all %s.\n",
2244 do_pipe ? "pipes" : "rules");
2245 #else /* DUMMYNET */
b7080c8e 2246 printf("Flushed all rules.\n");
7ba0088d 2247 #endif /* DUMMYNET */
b7080c8e
A
2248 }
2249 } else if (!strncmp(*av, "zero", strlen(*av))) {
7ba0088d
A
2250 zero(ac, av);
2251 } else if (!strncmp(*av, "resetlog", strlen(*av))) {
2252 resetlog(ac, av);
b7080c8e 2253 } else if (!strncmp(*av, "print", strlen(*av))) {
7ba0088d 2254 list(--ac, ++av);
b7080c8e 2255 } else if (!strncmp(*av, "list", strlen(*av))) {
7ba0088d 2256 list(--ac, ++av);
b7080c8e
A
2257 } else if (!strncmp(*av, "show", strlen(*av))) {
2258 do_acct++;
7ba0088d 2259 list(--ac, ++av);
b7080c8e 2260 } else {
7ba0088d 2261 show_usage("bad arguments");
b7080c8e
A
2262 }
2263 return 0;
2264}
2265
7ba0088d 2266int
b7080c8e
A
2267main(ac, av)
2268 int ac;
2269 char **av;
2270{
2271#define MAX_ARGS 32
2272#define WHITESP " \t\f\v\n\r"
2273 char buf[BUFSIZ];
2274 char *a, *p, *args[MAX_ARGS], *cmd = NULL;
2275 char linename[10];
7ba0088d 2276 int i, c, lineno, qflag, pflag, status;
b7080c8e
A
2277 FILE *f = NULL;
2278 pid_t preproc = 0;
2279
7ba0088d
A
2280 s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
2281 if (s < 0)
b7080c8e
A
2282 err(EX_UNAVAILABLE, "socket");
2283
7ba0088d 2284 setbuf(stdout, 0);
b7080c8e 2285
7ba0088d
A
2286 /*
2287 * this is a nasty check on the last argument!!!
2288 * If there happens to be a filename matching a keyword in the current
2289 * directory, things will fail miserably.
2290 */
2291
2292 if (ac > 1 && av[ac - 1][0] == '/' && access(av[ac - 1], R_OK) == 0) {
b7080c8e
A
2293 qflag = pflag = i = 0;
2294 lineno = 0;
2295
2296 while ((c = getopt(ac, av, "D:U:p:q")) != -1)
2297 switch(c) {
2298 case 'D':
2299 if (!pflag)
2300 errx(EX_USAGE, "-D requires -p");
2301 if (i > MAX_ARGS - 2)
2302 errx(EX_USAGE,
2303 "too many -D or -U options");
2304 args[i++] = "-D";
2305 args[i++] = optarg;
2306 break;
2307
2308 case 'U':
2309 if (!pflag)
2310 errx(EX_USAGE, "-U requires -p");
2311 if (i > MAX_ARGS - 2)
2312 errx(EX_USAGE,
2313 "too many -D or -U options");
2314 args[i++] = "-U";
2315 args[i++] = optarg;
2316 break;
2317
2318 case 'p':
2319 pflag = 1;
2320 cmd = optarg;
2321 args[0] = cmd;
2322 i = 1;
2323 break;
2324
2325 case 'q':
2326 qflag = 1;
2327 break;
2328
2329 default:
2330 show_usage(NULL);
2331 }
2332
2333 av += optind;
2334 ac -= optind;
2335 if (ac != 1)
2336 show_usage("extraneous filename arguments");
2337
2338 if ((f = fopen(av[0], "r")) == NULL)
2339 err(EX_UNAVAILABLE, "fopen: %s", av[0]);
2340
2341 if (pflag) {
2342 /* pipe through preprocessor (cpp or m4) */
2343 int pipedes[2];
2344
2345 args[i] = 0;
2346
2347 if (pipe(pipedes) == -1)
2348 err(EX_OSERR, "cannot create pipe");
2349
2350 switch((preproc = fork())) {
2351 case -1:
2352 err(EX_OSERR, "cannot fork");
2353
2354 case 0:
2355 /* child */
7ba0088d
A
2356 if (dup2(fileno(f), 0) == -1
2357 || dup2(pipedes[1], 1) == -1)
b7080c8e
A
2358 err(EX_OSERR, "dup2()");
2359 fclose(f);
2360 close(pipedes[1]);
2361 close(pipedes[0]);
2362 execvp(cmd, args);
2363 err(EX_OSERR, "execvp(%s) failed", cmd);
2364
2365 default:
2366 /* parent */
2367 fclose(f);
2368 close(pipedes[1]);
2369 if ((f = fdopen(pipedes[0], "r")) == NULL) {
2370 int savederrno = errno;
2371
2372 (void)kill(preproc, SIGTERM);
2373 errno = savederrno;
2374 err(EX_OSERR, "fdopen()");
2375 }
2376 }
2377 }
2378
2379 while (fgets(buf, BUFSIZ, f)) {
2380 lineno++;
2381 sprintf(linename, "Line %d", lineno);
2382 args[0] = linename;
2383
2384 if (*buf == '#')
2385 continue;
2386 if ((p = strchr(buf, '#')) != NULL)
2387 *p = '\0';
7ba0088d
A
2388 i = 1;
2389 if (qflag)
2390 args[i++] = "-q";
b7080c8e
A
2391 for (a = strtok(buf, WHITESP);
2392 a && i < MAX_ARGS; a = strtok(NULL, WHITESP), i++)
2393 args[i] = a;
2394 if (i == (qflag? 2: 1))
2395 continue;
2396 if (i == MAX_ARGS)
7ba0088d
A
2397 errx(EX_USAGE, "%s: too many arguments",
2398 linename);
b7080c8e
A
2399 args[i] = NULL;
2400
7ba0088d 2401 ipfw_main(i, args);
b7080c8e
A
2402 }
2403 fclose(f);
2404 if (pflag) {
7ba0088d
A
2405 if (waitpid(preproc, &status, 0) == -1)
2406 errx(EX_OSERR, "waitpid()");
2407 if (WIFEXITED(status) && WEXITSTATUS(status) != EX_OK)
2408 errx(EX_UNAVAILABLE,
2409 "preprocessor exited with status %d",
2410 WEXITSTATUS(status));
2411 else if (WIFSIGNALED(status))
2412 errx(EX_UNAVAILABLE,
2413 "preprocessor exited with signal %d",
2414 WTERMSIG(status));
b7080c8e 2415 }
7ba0088d
A
2416 } else {
2417 ipfw_main(ac, av);
2418 }
b7080c8e
A
2419 return EX_OK;
2420}