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