]> git.saurik.com Git - apple/network_cmds.git/blob - ipfw.tproj/ipfw.c
network_cmds-77.tar.gz
[apple/network_cmds.git] / ipfw.tproj / ipfw.c
1 /*
2 * Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp
3 * Copyright (c) 1994 Ugen J.S.Antsilevich
4 *
5 * Idea and grammar partially left from:
6 * Copyright (c) 1993 Daniel Boulet
7 *
8 * Redistribution and use in source forms, with and without modification,
9 * are permitted provided that this entire comment appears intact.
10 *
11 * Redistribution in binary form may occur without any restrictions.
12 * Obviously, it would be nice if you gave credit where credit is due
13 * but requiring it would be too onerous.
14 *
15 * This software is provided ``AS IS'' without any warranties of any kind.
16 *
17 * NEW command line interface for IP firewall facility
18 *
19 * $Id: ipfw.c,v 1.2 2000/06/07 04:22:47 lindak Exp $
20 *
21 */
22
23 #include <sys/types.h>
24 #include <sys/queue.h>
25 #include <sys/socket.h>
26 #include <sys/sockio.h>
27 #include <sys/time.h>
28 #include <sys/wait.h>
29
30 #include <ctype.h>
31 #include <err.h>
32 #include <errno.h>
33 #include <limits.h>
34 #include <netdb.h>
35 #include <signal.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <stdarg.h>
39 #include <string.h>
40 #include <sysexits.h>
41 #include <time.h>
42 #include <unistd.h>
43
44 #include <net/if.h>
45 #include <netinet/in.h>
46 #include <netinet/in_systm.h>
47 #include <netinet/ip_var.h>
48 #include <netinet/ip.h>
49 #include <netinet/ip_icmp.h>
50 #include <netinet/ip_fw.h>
51 #include <net/route.h> /* def. of struct route */
52 #include <sys/param.h>
53 #include <sys/mbuf.h>
54 #include <netinet/ip_dummynet.h>
55 #include <netinet/tcp.h>
56 #include <arpa/inet.h>
57
58 int lineno = -1;
59
60 int s; /* main RAW socket */
61 int do_resolv=0; /* Would try to resolve all */
62 int do_acct=0; /* Show packet/byte count */
63 int do_time=0; /* Show time stamps */
64 int do_quiet=0; /* Be quiet in add and flush */
65 int do_force=0; /* Don't ask for confirmation */
66 int do_pipe=0; /* this cmd refers to a pipe */
67
68 struct icmpcode {
69 int code;
70 char *str;
71 };
72
73 static struct icmpcode icmpcodes[] = {
74 { ICMP_UNREACH_NET, "net" },
75 { ICMP_UNREACH_HOST, "host" },
76 { ICMP_UNREACH_PROTOCOL, "protocol" },
77 { ICMP_UNREACH_PORT, "port" },
78 { ICMP_UNREACH_NEEDFRAG, "needfrag" },
79 { ICMP_UNREACH_SRCFAIL, "srcfail" },
80 { ICMP_UNREACH_NET_UNKNOWN, "net-unknown" },
81 { ICMP_UNREACH_HOST_UNKNOWN, "host-unknown" },
82 { ICMP_UNREACH_ISOLATED, "isolated" },
83 { ICMP_UNREACH_NET_PROHIB, "net-prohib" },
84 { ICMP_UNREACH_HOST_PROHIB, "host-prohib" },
85 { ICMP_UNREACH_TOSNET, "tosnet" },
86 { ICMP_UNREACH_TOSHOST, "toshost" },
87 { ICMP_UNREACH_FILTER_PROHIB, "filter-prohib" },
88 { ICMP_UNREACH_HOST_PRECEDENCE, "host-precedence" },
89 { ICMP_UNREACH_PRECEDENCE_CUTOFF, "precedence-cutoff" },
90 { 0, NULL }
91 };
92
93 static void show_usage(const char *fmt, ...);
94
95 static int
96 mask_bits(struct in_addr m_ad)
97 {
98 int h_fnd=0,h_num=0,i;
99 u_long mask;
100
101 mask=ntohl(m_ad.s_addr);
102 for (i=0;i<sizeof(u_long)*CHAR_BIT;i++) {
103 if (mask & 1L) {
104 h_fnd=1;
105 h_num++;
106 } else {
107 if (h_fnd)
108 return -1;
109 }
110 mask=mask>>1;
111 }
112 return h_num;
113 }
114
115 static void
116 print_port(prot, port, comma)
117 u_char prot;
118 u_short port;
119 const char *comma;
120 {
121 struct servent *se;
122 struct protoent *pe;
123 const char *protocol;
124 int printed = 0;
125
126 if (do_resolv) {
127 pe = getprotobynumber(prot);
128 if (pe)
129 protocol = pe->p_name;
130 else
131 protocol = NULL;
132
133 se = getservbyport(htons(port), protocol);
134 if (se) {
135 printf("%s%s", comma, se->s_name);
136 printed = 1;
137 }
138 }
139 if (!printed)
140 printf("%s%d",comma,port);
141 }
142
143 static void
144 print_iface(char *key, union ip_fw_if *un, int byname)
145 {
146 char ifnb[FW_IFNLEN+1];
147
148 if (byname) {
149 strncpy(ifnb, un->fu_via_if.name, FW_IFNLEN);
150 ifnb[FW_IFNLEN]='\0';
151 if (un->fu_via_if.unit == -1)
152 printf(" %s %s*", key, ifnb);
153 else
154 printf(" %s %s%d", key, ifnb, un->fu_via_if.unit);
155 } else if (un->fu_via_ip.s_addr != 0) {
156 printf(" %s %s", key, inet_ntoa(un->fu_via_ip));
157 } else
158 printf(" %s any", key);
159 }
160
161 static void
162 print_reject_code(int code)
163 {
164 struct icmpcode *ic;
165
166 for (ic = icmpcodes; ic->str; ic++)
167 if (ic->code == code) {
168 printf("%s", ic->str);
169 return;
170 }
171 printf("%u", code);
172 }
173
174 static void
175 show_ipfw(struct ip_fw *chain, int pcwidth, int bcwidth)
176 {
177 char *comma;
178 u_long adrt;
179 struct hostent *he;
180 struct protoent *pe;
181 int i, mb;
182 int nsp = IP_FW_GETNSRCP(chain);
183 int ndp = IP_FW_GETNDSTP(chain);
184
185 if (do_resolv)
186 setservent(1/*stayopen*/);
187
188 printf("%05u ", chain->fw_number);
189
190 if (do_acct)
191 printf("%*qu %*qu ",pcwidth,chain->fw_pcnt,bcwidth,chain->fw_bcnt);
192
193 if (do_time)
194 {
195 if (chain->timestamp)
196 {
197 char timestr[30];
198
199 strcpy(timestr, ctime((time_t *)&chain->timestamp));
200 *strchr(timestr, '\n') = '\0';
201 printf("%s ", timestr);
202 }
203 else
204 printf(" ");
205 }
206
207 switch (chain->fw_flg & IP_FW_F_COMMAND)
208 {
209 case IP_FW_F_ACCEPT:
210 printf("allow");
211 break;
212 case IP_FW_F_DENY:
213 printf("deny");
214 break;
215 case IP_FW_F_COUNT:
216 printf("count");
217 break;
218 case IP_FW_F_DIVERT:
219 printf("divert %u", chain->fw_divert_port);
220 break;
221 case IP_FW_F_TEE:
222 printf("tee %u", chain->fw_divert_port);
223 break;
224 case IP_FW_F_SKIPTO:
225 printf("skipto %u", chain->fw_skipto_rule);
226 break;
227 case IP_FW_F_PIPE:
228 printf("pipe %u", chain->fw_skipto_rule);
229 break ;
230 case IP_FW_F_REJECT:
231 if (chain->fw_reject_code == IP_FW_REJECT_RST)
232 printf("reset");
233 else {
234 printf("unreach ");
235 print_reject_code(chain->fw_reject_code);
236 }
237 break;
238 case IP_FW_F_FWD:
239 printf("fwd %s", inet_ntoa(chain->fw_fwd_ip.sin_addr));
240 if(chain->fw_fwd_ip.sin_port)
241 printf(",%d", chain->fw_fwd_ip.sin_port);
242 break;
243 default:
244 errx(EX_OSERR, "impossible");
245 }
246
247 if (chain->fw_flg & IP_FW_F_PRN)
248 printf(" log");
249
250 pe = getprotobynumber(chain->fw_prot);
251 if (pe)
252 printf(" %s", pe->p_name);
253 else
254 printf(" %u", chain->fw_prot);
255
256 printf(" from %s", chain->fw_flg & IP_FW_F_INVSRC ? "not " : "");
257
258 adrt=ntohl(chain->fw_smsk.s_addr);
259 if (adrt==ULONG_MAX && do_resolv) {
260 adrt=(chain->fw_src.s_addr);
261 he=gethostbyaddr((char *)&adrt,sizeof(u_long),AF_INET);
262 if (he==NULL) {
263 printf(inet_ntoa(chain->fw_src));
264 } else
265 printf("%s",he->h_name);
266 } else {
267 if (adrt!=ULONG_MAX) {
268 mb=mask_bits(chain->fw_smsk);
269 if (mb == 0) {
270 printf("any");
271 } else {
272 if (mb > 0) {
273 printf(inet_ntoa(chain->fw_src));
274 printf("/%d",mb);
275 } else {
276 printf(inet_ntoa(chain->fw_src));
277 printf(":");
278 printf(inet_ntoa(chain->fw_smsk));
279 }
280 }
281 } else
282 printf(inet_ntoa(chain->fw_src));
283 }
284
285 if (chain->fw_prot == IPPROTO_TCP || chain->fw_prot == IPPROTO_UDP) {
286 comma = " ";
287 for (i = 0; i < nsp; i++) {
288 print_port(chain->fw_prot, chain->fw_uar.fw_pts[i], comma);
289 if (i==0 && (chain->fw_flg & IP_FW_F_SRNG))
290 comma = "-";
291 else
292 comma = ",";
293 }
294 }
295
296 printf(" to %s", chain->fw_flg & IP_FW_F_INVDST ? "not " : "");
297
298 adrt=ntohl(chain->fw_dmsk.s_addr);
299 if (adrt==ULONG_MAX && do_resolv) {
300 adrt=(chain->fw_dst.s_addr);
301 he=gethostbyaddr((char *)&adrt,sizeof(u_long),AF_INET);
302 if (he==NULL) {
303 printf(inet_ntoa(chain->fw_dst));
304 } else
305 printf("%s",he->h_name);
306 } else {
307 if (adrt!=ULONG_MAX) {
308 mb=mask_bits(chain->fw_dmsk);
309 if (mb == 0) {
310 printf("any");
311 } else {
312 if (mb > 0) {
313 printf(inet_ntoa(chain->fw_dst));
314 printf("/%d",mb);
315 } else {
316 printf(inet_ntoa(chain->fw_dst));
317 printf(":");
318 printf(inet_ntoa(chain->fw_dmsk));
319 }
320 }
321 } else
322 printf(inet_ntoa(chain->fw_dst));
323 }
324
325 if (chain->fw_prot == IPPROTO_TCP || chain->fw_prot == IPPROTO_UDP) {
326 comma = " ";
327 for (i = 0; i < ndp; i++) {
328 print_port(chain->fw_prot, chain->fw_uar.fw_pts[nsp+i], comma);
329 if (i==0 && (chain->fw_flg & IP_FW_F_DRNG))
330 comma = "-";
331 else
332 comma = ",";
333 }
334 }
335
336 /* Direction */
337 if ((chain->fw_flg & IP_FW_F_IN) && !(chain->fw_flg & IP_FW_F_OUT))
338 printf(" in");
339 if (!(chain->fw_flg & IP_FW_F_IN) && (chain->fw_flg & IP_FW_F_OUT))
340 printf(" out");
341
342 /* Handle hack for "via" backwards compatibility */
343 if ((chain->fw_flg & IF_FW_F_VIAHACK) == IF_FW_F_VIAHACK) {
344 print_iface("via",
345 &chain->fw_in_if, chain->fw_flg & IP_FW_F_IIFNAME);
346 } else {
347 /* Receive interface specified */
348 if (chain->fw_flg & IP_FW_F_IIFACE)
349 print_iface("recv", &chain->fw_in_if,
350 chain->fw_flg & IP_FW_F_IIFNAME);
351 /* Transmit interface specified */
352 if (chain->fw_flg & IP_FW_F_OIFACE)
353 print_iface("xmit", &chain->fw_out_if,
354 chain->fw_flg & IP_FW_F_OIFNAME);
355 }
356
357 if (chain->fw_flg & IP_FW_F_FRAG)
358 printf(" frag");
359
360 if (chain->fw_ipopt || chain->fw_ipnopt) {
361 int _opt_printed = 0;
362 #define PRINTOPT(x) {if (_opt_printed) printf(",");\
363 printf(x); _opt_printed = 1;}
364
365 printf(" ipopt ");
366 if (chain->fw_ipopt & IP_FW_IPOPT_SSRR) PRINTOPT("ssrr");
367 if (chain->fw_ipnopt & IP_FW_IPOPT_SSRR) PRINTOPT("!ssrr");
368 if (chain->fw_ipopt & IP_FW_IPOPT_LSRR) PRINTOPT("lsrr");
369 if (chain->fw_ipnopt & IP_FW_IPOPT_LSRR) PRINTOPT("!lsrr");
370 if (chain->fw_ipopt & IP_FW_IPOPT_RR) PRINTOPT("rr");
371 if (chain->fw_ipnopt & IP_FW_IPOPT_RR) PRINTOPT("!rr");
372 if (chain->fw_ipopt & IP_FW_IPOPT_TS) PRINTOPT("ts");
373 if (chain->fw_ipnopt & IP_FW_IPOPT_TS) PRINTOPT("!ts");
374 }
375
376 if (chain->fw_tcpf & IP_FW_TCPF_ESTAB)
377 printf(" established");
378 else if (chain->fw_tcpf == IP_FW_TCPF_SYN &&
379 chain->fw_tcpnf == IP_FW_TCPF_ACK)
380 printf(" setup");
381 else if (chain->fw_tcpf || chain->fw_tcpnf) {
382 int _flg_printed = 0;
383 #define PRINTFLG(x) {if (_flg_printed) printf(",");\
384 printf(x); _flg_printed = 1;}
385
386 printf(" tcpflg ");
387 if (chain->fw_tcpf & IP_FW_TCPF_FIN) PRINTFLG("fin");
388 if (chain->fw_tcpnf & IP_FW_TCPF_FIN) PRINTFLG("!fin");
389 if (chain->fw_tcpf & IP_FW_TCPF_SYN) PRINTFLG("syn");
390 if (chain->fw_tcpnf & IP_FW_TCPF_SYN) PRINTFLG("!syn");
391 if (chain->fw_tcpf & IP_FW_TCPF_RST) PRINTFLG("rst");
392 if (chain->fw_tcpnf & IP_FW_TCPF_RST) PRINTFLG("!rst");
393 if (chain->fw_tcpf & IP_FW_TCPF_PSH) PRINTFLG("psh");
394 if (chain->fw_tcpnf & IP_FW_TCPF_PSH) PRINTFLG("!psh");
395 if (chain->fw_tcpf & IP_FW_TCPF_ACK) PRINTFLG("ack");
396 if (chain->fw_tcpnf & IP_FW_TCPF_ACK) PRINTFLG("!ack");
397 if (chain->fw_tcpf & IP_FW_TCPF_URG) PRINTFLG("urg");
398 if (chain->fw_tcpnf & IP_FW_TCPF_URG) PRINTFLG("!urg");
399 }
400 if (chain->fw_flg & IP_FW_F_ICMPBIT) {
401 int type_index;
402 int first = 1;
403
404 printf(" icmptype");
405
406 for (type_index = 0; type_index < IP_FW_ICMPTYPES_DIM * sizeof(unsigned) * 8; ++type_index)
407 if (chain->fw_uar.fw_icmptypes[type_index / (sizeof(unsigned) * 8)] &
408 (1U << (type_index % (sizeof(unsigned) * 8)))) {
409 printf("%c%d", first == 1 ? ' ' : ',', type_index);
410 first = 0;
411 }
412 }
413 printf("\n");
414 if (do_resolv)
415 endservent();
416 }
417
418 static void
419 list(ac, av)
420 int ac;
421 char **av;
422 {
423 struct ip_fw *rules;
424 struct dn_pipe *pipes;
425 void *data = NULL;
426 int pcwidth = 0;
427 int bcwidth = 0;
428 int n, num = 0;
429
430 /* get rules or pipes from kernel, resizing array as necessary */
431 {
432 const int unit = do_pipe ? sizeof(*pipes) : sizeof(*rules);
433 const int ocmd = do_pipe ? IP_DUMMYNET_GET : IP_FW_GET;
434 int nalloc = 0;
435 int nbytes;
436
437 while (num >= nalloc) {
438 nalloc = nalloc * 2 + 200;
439 nbytes = nalloc * unit;
440 if ((data = realloc(data, nbytes)) == NULL)
441 err(EX_OSERR, "realloc");
442 if (getsockopt(s, IPPROTO_IP, ocmd, data, &nbytes) < 0)
443 err(EX_OSERR, "getsockopt(IP_%s_GET)",
444 do_pipe ? "DUMMYNET" : "FW");
445 num = nbytes / unit;
446 }
447 }
448
449 /* display requested pipes */
450 if (do_pipe) {
451 u_long rulenum;
452
453 pipes = (struct dn_pipe *) data;
454 if (ac > 0)
455 rulenum = strtoul(*av++, NULL, 10);
456 else
457 rulenum = 0 ;
458 for (n = 0; n < num; n++) {
459 struct dn_pipe *const p = &pipes[n];
460 double b = p->bandwidth ;
461 char buf[30] ;
462 char qs[30] ;
463 char plr[30] ;
464 int l ;
465
466 if (rulenum != 0 && rulenum != p->pipe_nr)
467 continue;
468 if (b == 0)
469 sprintf(buf, "unlimited");
470 else if (b >= 1000000)
471 sprintf(buf, "%7.3f Mbit/s", b/1000000 );
472 else if (b >= 1000)
473 sprintf(buf, "%7.3f Kbit/s", b/1000 );
474 else
475 sprintf(buf, "%7.3f bit/s ", b );
476
477 if ( (l = p->queue_size_bytes) != 0 ) {
478 if (l >= 8192)
479 sprintf(qs,"%d KB", l / 1024);
480 else
481 sprintf(qs,"%d B", l);
482 } else
483 sprintf(qs,"%3d sl.", p->queue_size);
484 if (p->plr)
485 sprintf(plr,"plr %f", 1.0*p->plr/(double)(0x7fffffff));
486 else
487 plr[0]='\0';
488
489 printf("%05d: %s %4d ms %s %s -- %d pkts (%d B) %d drops\n",
490 p->pipe_nr, buf, p->delay, qs, plr,
491 p->r_len, p->r_len_bytes, p->r_drops);
492 }
493 free(data);
494 return;
495 }
496
497 /* if showing stats, figure out column widths ahead of time */
498 rules = (struct ip_fw *) data;
499 if (do_acct) {
500 for (n = 0; n < num; n++) {
501 struct ip_fw *const r = &rules[n];
502 char temp[32];
503 int width;
504
505 /* packet counter */
506 width = sprintf(temp, "%qu", r->fw_pcnt);
507 if (width > pcwidth)
508 pcwidth = width;
509
510 /* byte counter */
511 width = sprintf(temp, "%qu", r->fw_bcnt);
512 if (width > bcwidth)
513 bcwidth = width;
514 }
515 }
516 if (ac == 0) {
517 /* display all rules */
518 for (n = 0; n < num; n++) {
519 struct ip_fw *const r = &rules[n];
520
521 show_ipfw(r, pcwidth, bcwidth);
522 }
523 } else {
524 /* display specific rules requested on command line */
525 int exitval = EX_OK;
526
527 while (ac--) {
528 u_long rnum;
529 char *endptr;
530 int seen;
531
532 /* convert command line rule # */
533 rnum = strtoul(*av++, &endptr, 10);
534 if (*endptr) {
535 exitval = EX_USAGE;
536 warnx("invalid rule number: %s", *(av - 1));
537 continue;
538 }
539 for (seen = n = 0; n < num; n++) {
540 struct ip_fw *const r = &rules[n];
541
542 if (r->fw_number > rnum)
543 break;
544 if (r->fw_number == rnum) {
545 show_ipfw(r, pcwidth, bcwidth);
546 seen = 1;
547 }
548 }
549 if (!seen) {
550 /* give precedence to other error(s) */
551 if (exitval == EX_OK)
552 exitval = EX_UNAVAILABLE;
553 warnx("rule %lu does not exist", rnum);
554 }
555 }
556 if (exitval != EX_OK)
557 exit(exitval);
558 }
559 free(data);
560 }
561
562 static void
563 show_usage(const char *fmt, ...)
564 {
565 if (fmt) {
566 char buf[100];
567 va_list args;
568
569 va_start(args, fmt);
570 vsnprintf(buf, sizeof(buf), fmt, args);
571 va_end(args);
572 warnx("error: %s", buf);
573 }
574 fprintf(stderr, "usage: ipfw [options]\n"
575 " flush\n"
576 " add [number] rule\n"
577 " delete number ...\n"
578 " list [number ...]\n"
579 " show [number ...]\n"
580 " zero [number ...]\n"
581 " rule: action proto src dst extras...\n"
582 " action:\n"
583 " {allow|permit|accept|pass|deny|drop|reject|unreach code|\n"
584 " reset|count|skipto num|divert port|tee port|fwd ip} [log]\n"
585 " proto: {ip|tcp|udp|icmp|<number>}\n"
586 " src: from [not] {any|ip[{/bits|:mask}]} [{port|port-port},[port],...]\n"
587 " dst: to [not] {any|ip[{/bits|:mask}]} [{port|port-port},[port],...]\n"
588 " extras:\n"
589 " fragment (may not be used with ports or tcpflags)\n"
590 " in\n"
591 " out\n"
592 " {xmit|recv|via} {iface|ip|any}\n"
593 " {established|setup}\n"
594 " tcpflags [!]{syn|fin|rst|ack|psh|urg},...\n"
595 " ipoptions [!]{ssrr|lsrr|rr|ts},...\n"
596 " icmptypes {type[,type]}...\n");
597
598 exit(EX_USAGE);
599 }
600
601 static int
602 lookup_host (host, ipaddr)
603 char *host;
604 struct in_addr *ipaddr;
605 {
606 struct hostent *he = gethostbyname(host);
607
608 if (!he) {
609 if (inet_aton(host, ipaddr))
610 return(0);
611 else
612 return(-1);
613 }
614 *ipaddr = *(struct in_addr *)he->h_addr_list[0];
615
616 return(0);
617 }
618
619 static void
620 fill_ip(ipno, mask, acp, avp)
621 struct in_addr *ipno, *mask;
622 int *acp;
623 char ***avp;
624 {
625 int ac = *acp;
626 char **av = *avp;
627 char *p = 0, md = 0;
628
629 if (ac && !strncmp(*av,"any",strlen(*av))) {
630 ipno->s_addr = mask->s_addr = 0; av++; ac--;
631 } else {
632 p = strchr(*av, '/');
633 if (!p)
634 p = strchr(*av, ':');
635 if (p) {
636 md = *p;
637 *p++ = '\0';
638 }
639
640 if (lookup_host(*av, ipno) != 0)
641 show_usage("hostname ``%s'' unknown", *av);
642 switch (md) {
643 case ':':
644 if (!inet_aton(p,mask))
645 show_usage("bad netmask ``%s''", p);
646 break;
647 case '/':
648 if (atoi(p) == 0) {
649 mask->s_addr = 0;
650 } else if (atoi(p) > 32) {
651 show_usage("bad width ``%s''", p);
652 } else {
653 mask->s_addr =
654 htonl(~0 << (32 - atoi(p)));
655 }
656 break;
657 default:
658 mask->s_addr = htonl(~0);
659 break;
660 }
661 ipno->s_addr &= mask->s_addr;
662 av++;
663 ac--;
664 }
665 *acp = ac;
666 *avp = av;
667 }
668
669 static void
670 fill_reject_code(u_short *codep, char *str)
671 {
672 struct icmpcode *ic;
673 u_long val;
674 char *s;
675
676 val = strtoul(str, &s, 0);
677 if (s != str && *s == '\0' && val < 0x100) {
678 *codep = val;
679 return;
680 }
681 for (ic = icmpcodes; ic->str; ic++)
682 if (!strcasecmp(str, ic->str)) {
683 *codep = ic->code;
684 return;
685 }
686 show_usage("unknown ICMP unreachable code ``%s''", str);
687 }
688
689 static void
690 add_port(cnt, ptr, off, port)
691 u_short *cnt, *ptr, off, port;
692 {
693 if (off + *cnt >= IP_FW_MAX_PORTS)
694 errx(EX_USAGE, "too many ports (max is %d)", IP_FW_MAX_PORTS);
695 ptr[off+*cnt] = port;
696 (*cnt)++;
697 }
698
699 static int
700 lookup_port(const char *arg, int test, int nodash)
701 {
702 int val;
703 char *earg, buf[32];
704 struct servent *s;
705
706 snprintf(buf, sizeof(buf), "%s", arg);
707 buf[strcspn(arg, nodash ? "-," : ",")] = 0;
708 val = (int) strtoul(buf, &earg, 0);
709 if (!*buf || *earg) {
710 setservent(1);
711 if ((s = getservbyname(buf, NULL))) {
712 val = htons(s->s_port);
713 } else {
714 if (!test) {
715 errx(EX_DATAERR, "unknown port ``%s''", arg);
716 }
717 val = -1;
718 }
719 } else {
720 if (val < 0 || val > 0xffff) {
721 if (!test) {
722 errx(EX_DATAERR, "port ``%s'' out of range", arg);
723 }
724 val = -1;
725 }
726 }
727 return(val);
728 }
729
730 static int
731 fill_port(cnt, ptr, off, arg)
732 u_short *cnt, *ptr, off;
733 char *arg;
734 {
735 char *s;
736 int initial_range = 0;
737
738 s = arg + strcspn(arg, "-,"); /* first port name can't have a dash */
739 if (*s == '-') {
740 *s++ = '\0';
741 if (strchr(arg, ','))
742 errx(EX_USAGE, "port range must be first in list");
743 add_port(cnt, ptr, off, *arg ? lookup_port(arg, 0, 0) : 0x0000);
744 arg = s;
745 s = strchr(arg,',');
746 if (s)
747 *s++ = '\0';
748 add_port(cnt, ptr, off, *arg ? lookup_port(arg, 0, 0) : 0xffff);
749 arg = s;
750 initial_range = 1;
751 }
752 while (arg != NULL) {
753 s = strchr(arg,',');
754 if (s)
755 *s++ = '\0';
756 add_port(cnt, ptr, off, lookup_port(arg, 0, 0));
757 arg = s;
758 }
759 return initial_range;
760 }
761
762 static void
763 fill_tcpflag(set, reset, vp)
764 u_char *set, *reset;
765 char **vp;
766 {
767 char *p = *vp,*q;
768 u_char *d;
769
770 while (p && *p) {
771 struct tpcflags {
772 char * name;
773 u_char value;
774 } flags[] = {
775 { "syn", IP_FW_TCPF_SYN },
776 { "fin", IP_FW_TCPF_FIN },
777 { "ack", IP_FW_TCPF_ACK },
778 { "psh", IP_FW_TCPF_PSH },
779 { "rst", IP_FW_TCPF_RST },
780 { "urg", IP_FW_TCPF_URG }
781 };
782 int i;
783
784 if (*p == '!') {
785 p++;
786 d = reset;
787 } else {
788 d = set;
789 }
790 q = strchr(p, ',');
791 if (q)
792 *q++ = '\0';
793 for (i = 0; i < sizeof(flags) / sizeof(flags[0]); ++i)
794 if (!strncmp(p, flags[i].name, strlen(p))) {
795 *d |= flags[i].value;
796 break;
797 }
798 if (i == sizeof(flags) / sizeof(flags[0]))
799 show_usage("invalid tcp flag ``%s''", p);
800 p = q;
801 }
802 }
803
804 static void
805 fill_ipopt(u_char *set, u_char *reset, char **vp)
806 {
807 char *p = *vp,*q;
808 u_char *d;
809
810 while (p && *p) {
811 if (*p == '!') {
812 p++;
813 d = reset;
814 } else {
815 d = set;
816 }
817 q = strchr(p, ',');
818 if (q)
819 *q++ = '\0';
820 if (!strncmp(p,"ssrr",strlen(p))) *d |= IP_FW_IPOPT_SSRR;
821 if (!strncmp(p,"lsrr",strlen(p))) *d |= IP_FW_IPOPT_LSRR;
822 if (!strncmp(p,"rr",strlen(p))) *d |= IP_FW_IPOPT_RR;
823 if (!strncmp(p,"ts",strlen(p))) *d |= IP_FW_IPOPT_TS;
824 p = q;
825 }
826 }
827
828 static void
829 fill_icmptypes(types, vp, fw_flg)
830 u_long *types;
831 char **vp;
832 u_int *fw_flg;
833 {
834 char *c = *vp;
835
836 while (*c)
837 {
838 unsigned long icmptype;
839
840 if ( *c == ',' )
841 ++c;
842
843 icmptype = strtoul(c, &c, 0);
844
845 if ( *c != ',' && *c != '\0' )
846 show_usage("invalid ICMP type");
847
848 if (icmptype >= IP_FW_ICMPTYPES_DIM * sizeof(unsigned) * 8)
849 show_usage("ICMP type out of range");
850
851 types[icmptype / (sizeof(unsigned) * 8)] |=
852 1 << (icmptype % (sizeof(unsigned) * 8));
853 *fw_flg |= IP_FW_F_ICMPBIT;
854 }
855 }
856
857 static void
858 delete(ac,av)
859 int ac;
860 char **av;
861 {
862 struct ip_fw rule;
863 struct dn_pipe pipe;
864 int i;
865 int exitval = EX_OK;
866
867 memset(&rule, 0, sizeof rule);
868 memset(&pipe, 0, sizeof pipe);
869
870 av++; ac--;
871
872 /* Rule number */
873 while (ac && isdigit(**av)) {
874 if (do_pipe) {
875 pipe.pipe_nr = atoi(*av); av++; ac--;
876 i = setsockopt(s, IPPROTO_IP, IP_DUMMYNET_DEL,
877 &pipe, sizeof pipe);
878 if (i) {
879 exitval = 1;
880 warn("rule %u: setsockopt(%s)", pipe.pipe_nr, "IP_DUMMYNET_DEL");
881 }
882 } else {
883 rule.fw_number = atoi(*av); av++; ac--;
884 i = setsockopt(s, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule);
885 if (i) {
886 exitval = EX_UNAVAILABLE;
887 warn("rule %u: setsockopt(%s)", rule.fw_number, "IP_FW_DEL");
888 }
889 }
890 }
891 if (exitval != EX_OK)
892 exit(exitval);
893 }
894
895 static void
896 verify_interface(union ip_fw_if *ifu)
897 {
898 struct ifreq ifr;
899
900 /*
901 * If a unit was specified, check for that exact interface.
902 * If a wildcard was specified, check for unit 0.
903 */
904 snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d",
905 ifu->fu_via_if.name,
906 ifu->fu_via_if.unit == -1 ? 0 : ifu->fu_via_if.unit);
907
908 if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0)
909 warnx("warning: interface ``%s'' does not exist", ifr.ifr_name);
910 }
911
912 static void
913 fill_iface(char *which, union ip_fw_if *ifu, int *byname, int ac, char *arg)
914 {
915 if (!ac)
916 show_usage("missing argument for ``%s''", which);
917
918 /* Parse the interface or address */
919 if (!strcmp(arg, "any")) {
920 ifu->fu_via_ip.s_addr = 0;
921 *byname = 0;
922 } else if (!isdigit(*arg)) {
923 char *q;
924
925 *byname = 1;
926 strncpy(ifu->fu_via_if.name, arg, sizeof(ifu->fu_via_if.name));
927 ifu->fu_via_if.name[sizeof(ifu->fu_via_if.name) - 1] = '\0';
928 for (q = ifu->fu_via_if.name;
929 *q && !isdigit(*q) && *q != '*'; q++)
930 continue;
931 ifu->fu_via_if.unit = (*q == '*') ? -1 : atoi(q);
932 *q = '\0';
933 verify_interface(ifu);
934 } else if (!inet_aton(arg, &ifu->fu_via_ip)) {
935 show_usage("bad ip address ``%s''", arg);
936 } else
937 *byname = 0;
938 }
939
940 static void
941 config_pipe(int ac, char **av)
942 {
943 struct dn_pipe pipe;
944 int i ;
945 char *end ;
946
947 memset(&pipe, 0, sizeof pipe);
948
949 av++; ac--;
950 /* Pipe number */
951 if (ac && isdigit(**av)) {
952 pipe.pipe_nr = atoi(*av); av++; ac--;
953 }
954 while (ac > 1) {
955 if (!strncmp(*av,"bw",strlen(*av)) ||
956 ! strncmp(*av,"bandwidth",strlen(*av))) {
957 pipe.bandwidth = strtoul(av[1], &end, 0);
958 if (*end == 'K')
959 end++, pipe.bandwidth *= 1000 ;
960 else if (*end == 'M')
961 end++, pipe.bandwidth *= 1000000 ;
962 if (*end == 'B')
963 pipe.bandwidth *= 8 ;
964 av+=2; ac-=2;
965 } else if (!strncmp(*av,"delay",strlen(*av)) ) {
966 pipe.delay = strtoul(av[1], NULL, 0);
967 av+=2; ac-=2;
968 } else if (!strncmp(*av,"plr",strlen(*av)) ) {
969
970 double d = strtod(av[1], NULL);
971 pipe.plr = (int)(d*0x7fffffff) ;
972 av+=2; ac-=2;
973 } else if (!strncmp(*av,"queue",strlen(*av)) ) {
974 end = NULL ;
975 pipe.queue_size = strtoul(av[1], &end, 0);
976 if (*end == 'K') {
977 pipe.queue_size_bytes = pipe.queue_size*1024 ;
978 pipe.queue_size = 0 ;
979 } else if (*end == 'B') {
980 pipe.queue_size_bytes = pipe.queue_size ;
981 pipe.queue_size = 0 ;
982 }
983 av+=2; ac-=2;
984 } else
985 show_usage("unrecognised option ``%s''", *av);
986 }
987 if (pipe.pipe_nr == 0 )
988 show_usage("pipe_nr %d be > 0", pipe.pipe_nr);
989 if (pipe.queue_size > 100 )
990 show_usage("queue size %d must be 2 <= x <= 100", pipe.queue_size);
991 if (pipe.delay > 10000 )
992 show_usage("delay %d must be < 10000", pipe.delay);
993 #if 0
994 printf("configuring pipe %d bw %d delay %d size %d\n",
995 pipe.pipe_nr, pipe.bandwidth, pipe.delay, pipe.queue_size);
996 #endif
997 i = setsockopt(s,IPPROTO_IP, IP_DUMMYNET_CONFIGURE, &pipe,sizeof pipe);
998 if (i)
999 err(1, "setsockopt(%s)", "IP_DUMMYNET_CONFIGURE");
1000
1001 }
1002
1003 static void
1004 add(ac,av)
1005 int ac;
1006 char **av;
1007 {
1008 struct ip_fw rule;
1009 int i;
1010 u_char proto;
1011 struct protoent *pe;
1012 int saw_xmrc = 0, saw_via = 0;
1013
1014 memset(&rule, 0, sizeof rule);
1015
1016 av++; ac--;
1017
1018 /* Rule number */
1019 if (ac && isdigit(**av)) {
1020 rule.fw_number = atoi(*av); av++; ac--;
1021 }
1022
1023 /* Action */
1024 if (ac == 0)
1025 show_usage("missing action");
1026 if (!strncmp(*av,"accept",strlen(*av))
1027 || !strncmp(*av,"pass",strlen(*av))
1028 || !strncmp(*av,"allow",strlen(*av))
1029 || !strncmp(*av,"permit",strlen(*av))) {
1030 rule.fw_flg |= IP_FW_F_ACCEPT; av++; ac--;
1031 } else if (!strncmp(*av,"count",strlen(*av))) {
1032 rule.fw_flg |= IP_FW_F_COUNT; av++; ac--;
1033 } else if (!strncmp(*av,"pipe",strlen(*av))) {
1034 rule.fw_flg |= IP_FW_F_PIPE; av++; ac--;
1035 if (!ac)
1036 show_usage("missing pipe number");
1037 rule.fw_divert_port = strtoul(*av, NULL, 0); av++; ac--;
1038 } else if (!strncmp(*av,"divert",strlen(*av))) {
1039 rule.fw_flg |= IP_FW_F_DIVERT; av++; ac--;
1040 if (!ac)
1041 show_usage("missing %s port", "divert");
1042 rule.fw_divert_port = strtoul(*av, NULL, 0); av++; ac--;
1043 if (rule.fw_divert_port == 0) {
1044 struct servent *s;
1045 setservent(1);
1046 s = getservbyname(av[-1], "divert");
1047 if (s != NULL)
1048 rule.fw_divert_port = ntohs(s->s_port);
1049 else
1050 show_usage("illegal %s port", "divert");
1051 }
1052 } else if (!strncmp(*av,"tee",strlen(*av))) {
1053 rule.fw_flg |= IP_FW_F_TEE; av++; ac--;
1054 if (!ac)
1055 show_usage("missing %s port", "tee divert");
1056 rule.fw_divert_port = strtoul(*av, NULL, 0); av++; ac--;
1057 if (rule.fw_divert_port == 0) {
1058 struct servent *s;
1059 setservent(1);
1060 s = getservbyname(av[-1], "divert");
1061 if (s != NULL)
1062 rule.fw_divert_port = ntohs(s->s_port);
1063 else
1064 show_usage("illegal %s port", "tee divert");
1065 }
1066 #ifndef IPFW_TEE_IS_FINALLY_IMPLEMENTED
1067 err(EX_USAGE, "the ``tee'' action is not implemented");
1068 #endif
1069 } else if (!strncmp(*av,"fwd",strlen(*av)) ||
1070 !strncmp(*av,"forward",strlen(*av))) {
1071 struct in_addr dummyip;
1072 char *pp;
1073 rule.fw_flg |= IP_FW_F_FWD; av++; ac--;
1074 if (!ac)
1075 show_usage("missing forwarding IP address");
1076 rule.fw_fwd_ip.sin_len = sizeof(struct sockaddr_in);
1077 rule.fw_fwd_ip.sin_family = AF_INET;
1078 rule.fw_fwd_ip.sin_port = 0;
1079 pp = strchr(*av, ':');
1080 if(pp == NULL)
1081 pp = strchr(*av, ',');
1082 if(pp != NULL)
1083 {
1084 *(pp++) = '\0';
1085 rule.fw_fwd_ip.sin_port = lookup_port(pp, 1, 1);
1086 if(rule.fw_fwd_ip.sin_port == (unsigned int)-1)
1087 show_usage("illegal forwarding port");
1088 }
1089 fill_ip(&(rule.fw_fwd_ip.sin_addr), &dummyip, &ac, &av);
1090 if (rule.fw_fwd_ip.sin_addr.s_addr == 0)
1091 show_usage("illegal forwarding IP address");
1092
1093 } else if (!strncmp(*av,"skipto",strlen(*av))) {
1094 rule.fw_flg |= IP_FW_F_SKIPTO; av++; ac--;
1095 if (!ac)
1096 show_usage("missing skipto rule number");
1097 rule.fw_skipto_rule = strtoul(*av, NULL, 0); av++; ac--;
1098 } else if ((!strncmp(*av,"deny",strlen(*av))
1099 || !strncmp(*av,"drop",strlen(*av)))) {
1100 rule.fw_flg |= IP_FW_F_DENY; av++; ac--;
1101 } else if (!strncmp(*av,"reject",strlen(*av))) {
1102 rule.fw_flg |= IP_FW_F_REJECT; av++; ac--;
1103 rule.fw_reject_code = ICMP_UNREACH_HOST;
1104 } else if (!strncmp(*av,"reset",strlen(*av))) {
1105 rule.fw_flg |= IP_FW_F_REJECT; av++; ac--;
1106 rule.fw_reject_code = IP_FW_REJECT_RST; /* check TCP later */
1107 } else if (!strncmp(*av,"unreach",strlen(*av))) {
1108 rule.fw_flg |= IP_FW_F_REJECT; av++; ac--;
1109 fill_reject_code(&rule.fw_reject_code, *av); av++; ac--;
1110 } else {
1111 show_usage("invalid action ``%s''", *av);
1112 }
1113
1114 /* [log] */
1115 if (ac && !strncmp(*av,"log",strlen(*av))) {
1116 rule.fw_flg |= IP_FW_F_PRN; av++; ac--;
1117 }
1118
1119 /* protocol */
1120 if (ac == 0)
1121 show_usage("missing protocol");
1122 if ((proto = atoi(*av)) > 0) {
1123 rule.fw_prot = proto; av++; ac--;
1124 } else if (!strncmp(*av,"all",strlen(*av))) {
1125 rule.fw_prot = IPPROTO_IP; av++; ac--;
1126 } else if ((pe = getprotobyname(*av)) != NULL) {
1127 rule.fw_prot = pe->p_proto; av++; ac--;
1128 } else {
1129 show_usage("invalid protocol ``%s''", *av);
1130 }
1131
1132 if (rule.fw_prot != IPPROTO_TCP
1133 && (rule.fw_flg & IP_FW_F_COMMAND) == IP_FW_F_REJECT
1134 && rule.fw_reject_code == IP_FW_REJECT_RST)
1135 show_usage("``reset'' is only valid for tcp packets");
1136
1137 /* from */
1138 if (ac && !strncmp(*av,"from",strlen(*av))) { av++; ac--; }
1139 else
1140 show_usage("missing ``from''");
1141
1142 if (ac && !strncmp(*av,"not",strlen(*av))) {
1143 rule.fw_flg |= IP_FW_F_INVSRC;
1144 av++; ac--;
1145 }
1146 if (!ac)
1147 show_usage("missing arguments");
1148
1149 fill_ip(&rule.fw_src, &rule.fw_smsk, &ac, &av);
1150
1151 if (ac && (isdigit(**av) || lookup_port(*av, 1, 1) >= 0)) {
1152 u_short nports = 0;
1153
1154 if (fill_port(&nports, rule.fw_uar.fw_pts, 0, *av))
1155 rule.fw_flg |= IP_FW_F_SRNG;
1156 IP_FW_SETNSRCP(&rule, nports);
1157 av++; ac--;
1158 }
1159
1160 /* to */
1161 if (ac && !strncmp(*av,"to",strlen(*av))) { av++; ac--; }
1162 else
1163 show_usage("missing ``to''");
1164
1165 if (ac && !strncmp(*av,"not",strlen(*av))) {
1166 rule.fw_flg |= IP_FW_F_INVDST;
1167 av++; ac--;
1168 }
1169 if (!ac)
1170 show_usage("missing arguments");
1171
1172 fill_ip(&rule.fw_dst, &rule.fw_dmsk, &ac, &av);
1173
1174 if (ac && (isdigit(**av) || lookup_port(*av, 1, 1) >= 0)) {
1175 u_short nports = 0;
1176
1177 if (fill_port(&nports,
1178 rule.fw_uar.fw_pts, IP_FW_GETNSRCP(&rule), *av))
1179 rule.fw_flg |= IP_FW_F_DRNG;
1180 IP_FW_SETNDSTP(&rule, nports);
1181 av++; ac--;
1182 }
1183
1184 if ((rule.fw_prot != IPPROTO_TCP) && (rule.fw_prot != IPPROTO_UDP)
1185 && (IP_FW_GETNSRCP(&rule) || IP_FW_GETNDSTP(&rule))) {
1186 show_usage("only TCP and UDP protocols are valid"
1187 " with port specifications");
1188 }
1189
1190 while (ac) {
1191 if (!strncmp(*av,"in",strlen(*av))) {
1192 rule.fw_flg |= IP_FW_F_IN;
1193 av++; ac--; continue;
1194 }
1195 if (!strncmp(*av,"out",strlen(*av))) {
1196 rule.fw_flg |= IP_FW_F_OUT;
1197 av++; ac--; continue;
1198 }
1199 if (ac && !strncmp(*av,"xmit",strlen(*av))) {
1200 union ip_fw_if ifu;
1201 int byname;
1202
1203 if (saw_via) {
1204 badviacombo:
1205 show_usage("``via'' is incompatible"
1206 " with ``xmit'' and ``recv''");
1207 }
1208 saw_xmrc = 1;
1209 av++; ac--;
1210 fill_iface("xmit", &ifu, &byname, ac, *av);
1211 rule.fw_out_if = ifu;
1212 rule.fw_flg |= IP_FW_F_OIFACE;
1213 if (byname)
1214 rule.fw_flg |= IP_FW_F_OIFNAME;
1215 av++; ac--; continue;
1216 }
1217 if (ac && !strncmp(*av,"recv",strlen(*av))) {
1218 union ip_fw_if ifu;
1219 int byname;
1220
1221 if (saw_via)
1222 goto badviacombo;
1223 saw_xmrc = 1;
1224 av++; ac--;
1225 fill_iface("recv", &ifu, &byname, ac, *av);
1226 rule.fw_in_if = ifu;
1227 rule.fw_flg |= IP_FW_F_IIFACE;
1228 if (byname)
1229 rule.fw_flg |= IP_FW_F_IIFNAME;
1230 av++; ac--; continue;
1231 }
1232 if (ac && !strncmp(*av,"via",strlen(*av))) {
1233 union ip_fw_if ifu;
1234 int byname = 0;
1235
1236 if (saw_xmrc)
1237 goto badviacombo;
1238 saw_via = 1;
1239 av++; ac--;
1240 fill_iface("via", &ifu, &byname, ac, *av);
1241 rule.fw_out_if = rule.fw_in_if = ifu;
1242 if (byname)
1243 rule.fw_flg |=
1244 (IP_FW_F_IIFNAME | IP_FW_F_OIFNAME);
1245 av++; ac--; continue;
1246 }
1247 if (!strncmp(*av,"fragment",strlen(*av))) {
1248 rule.fw_flg |= IP_FW_F_FRAG;
1249 av++; ac--; continue;
1250 }
1251 if (!strncmp(*av,"ipoptions",strlen(*av))) {
1252 av++; ac--;
1253 if (!ac)
1254 show_usage("missing argument"
1255 " for ``ipoptions''");
1256 fill_ipopt(&rule.fw_ipopt, &rule.fw_ipnopt, av);
1257 av++; ac--; continue;
1258 }
1259 if (rule.fw_prot == IPPROTO_TCP) {
1260 if (!strncmp(*av,"established",strlen(*av))) {
1261 rule.fw_tcpf |= IP_FW_TCPF_ESTAB;
1262 av++; ac--; continue;
1263 }
1264 if (!strncmp(*av,"setup",strlen(*av))) {
1265 rule.fw_tcpf |= IP_FW_TCPF_SYN;
1266 rule.fw_tcpnf |= IP_FW_TCPF_ACK;
1267 av++; ac--; continue;
1268 }
1269 if (!strncmp(*av,"tcpflags",strlen(*av))) {
1270 av++; ac--;
1271 if (!ac)
1272 show_usage("missing argument"
1273 " for ``tcpflags''");
1274 fill_tcpflag(&rule.fw_tcpf, &rule.fw_tcpnf, av);
1275 av++; ac--; continue;
1276 }
1277 }
1278 if (rule.fw_prot == IPPROTO_ICMP) {
1279 if (!strncmp(*av,"icmptypes",strlen(*av))) {
1280 av++; ac--;
1281 if (!ac)
1282 show_usage("missing argument"
1283 " for ``icmptypes''");
1284 fill_icmptypes(rule.fw_uar.fw_icmptypes,
1285 av, &rule.fw_flg);
1286 av++; ac--; continue;
1287 }
1288 }
1289 show_usage("unknown argument ``%s''", *av);
1290 }
1291
1292 /* No direction specified -> do both directions */
1293 if (!(rule.fw_flg & (IP_FW_F_OUT|IP_FW_F_IN)))
1294 rule.fw_flg |= (IP_FW_F_OUT|IP_FW_F_IN);
1295
1296 /* Sanity check interface check, but handle "via" case separately */
1297 if (saw_via) {
1298 if (rule.fw_flg & IP_FW_F_IN)
1299 rule.fw_flg |= IP_FW_F_IIFACE;
1300 if (rule.fw_flg & IP_FW_F_OUT)
1301 rule.fw_flg |= IP_FW_F_OIFACE;
1302 } else if ((rule.fw_flg & IP_FW_F_OIFACE) && (rule.fw_flg & IP_FW_F_IN))
1303 show_usage("can't check xmit interface of incoming packets");
1304
1305 /* frag may not be used in conjunction with ports or TCP flags */
1306 if (rule.fw_flg & IP_FW_F_FRAG) {
1307 if (rule.fw_tcpf || rule.fw_tcpnf)
1308 show_usage("can't mix 'frag' and tcpflags");
1309
1310 if (rule.fw_nports)
1311 show_usage("can't mix 'frag' and port specifications");
1312 }
1313
1314 if (!do_quiet)
1315 show_ipfw(&rule, 10, 10);
1316 i = setsockopt(s, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule);
1317 if (i)
1318 err(EX_UNAVAILABLE, "setsockopt(%s)", "IP_FW_ADD");
1319 }
1320
1321 static void
1322 zero (ac, av)
1323 int ac;
1324 char **av;
1325 {
1326 av++; ac--;
1327
1328 if (!ac) {
1329 /* clear all entries */
1330 if (setsockopt(s,IPPROTO_IP,IP_FW_ZERO,NULL,0)<0)
1331 err(EX_UNAVAILABLE, "setsockopt(%s)", "IP_FW_ZERO");
1332 if (!do_quiet)
1333 printf("Accounting cleared.\n");
1334 } else {
1335 struct ip_fw rule;
1336 int failed = EX_OK;
1337
1338 memset(&rule, 0, sizeof rule);
1339 while (ac) {
1340 /* Rule number */
1341 if (isdigit(**av)) {
1342 rule.fw_number = atoi(*av); av++; ac--;
1343 if (setsockopt(s, IPPROTO_IP,
1344 IP_FW_ZERO, &rule, sizeof rule)) {
1345 warn("rule %u: setsockopt(%s)", rule.fw_number,
1346 "IP_FW_ZERO");
1347 failed = EX_UNAVAILABLE;
1348 }
1349 else if (!do_quiet)
1350 printf("Entry %d cleared\n",
1351 rule.fw_number);
1352 } else
1353 show_usage("invalid rule number ``%s''", *av);
1354 }
1355 if (failed != EX_OK)
1356 exit(failed);
1357 }
1358 }
1359
1360 static int
1361 ipfw_main(ac,av)
1362 int ac;
1363 char **av;
1364 {
1365
1366 int ch;
1367 extern int optreset; /* XXX should be declared in <unistd.h> */
1368
1369 if ( ac == 1 ) {
1370 show_usage(NULL);
1371 }
1372
1373 /* Set the force flag for non-interactive processes */
1374 do_force = !isatty(STDIN_FILENO);
1375
1376 optind = optreset = 1;
1377 while ((ch = getopt(ac, av, "afqtN")) != -1)
1378 switch(ch) {
1379 case 'a':
1380 do_acct=1;
1381 break;
1382 case 'f':
1383 do_force=1;
1384 break;
1385 case 'q':
1386 do_quiet=1;
1387 break;
1388 case 't':
1389 do_time=1;
1390 break;
1391 case 'N':
1392 do_resolv=1;
1393 break;
1394 default:
1395 show_usage(NULL);
1396 }
1397
1398 ac -= optind;
1399 if (*(av+=optind)==NULL) {
1400 show_usage("Bad arguments");
1401 }
1402
1403 if (!strncmp(*av, "pipe", strlen(*av))) {
1404 do_pipe = 1 ;
1405 ac-- ;
1406 av++ ;
1407 }
1408 if (!ac) {
1409 show_usage("pipe requires arguments");
1410 }
1411 /* allow argument swapping */
1412 if (ac > 1 && *av[0]>='0' && *av[0]<='9') {
1413 char *p = av[0] ;
1414 av[0] = av[1] ;
1415 av[1] = p ;
1416 }
1417 if (!strncmp(*av, "add", strlen(*av))) {
1418 add(ac,av);
1419 } else if (do_pipe && !strncmp(*av, "config", strlen(*av))) {
1420 config_pipe(ac,av);
1421 } else if (!strncmp(*av, "delete", strlen(*av))) {
1422 delete(ac,av);
1423 } else if (!strncmp(*av, "flush", strlen(*av))) {
1424 int do_flush = 0;
1425
1426 if ( do_force || do_quiet )
1427 do_flush = 1;
1428 else {
1429 int c;
1430
1431 /* Ask the user */
1432 printf("Are you sure? [yn] ");
1433 do {
1434 fflush(stdout);
1435 c = toupper(getc(stdin));
1436 while (c != '\n' && getc(stdin) != '\n')
1437 if (feof(stdin))
1438 return (0);
1439 } while (c != 'Y' && c != 'N');
1440 printf("\n");
1441 if (c == 'Y')
1442 do_flush = 1;
1443 }
1444 if ( do_flush ) {
1445 if (setsockopt(s,IPPROTO_IP,IP_FW_FLUSH,NULL,0) < 0)
1446 err(EX_UNAVAILABLE, "setsockopt(%s)", "IP_FW_FLUSH");
1447 if (!do_quiet)
1448 printf("Flushed all rules.\n");
1449 }
1450 } else if (!strncmp(*av, "zero", strlen(*av))) {
1451 zero(ac,av);
1452 } else if (!strncmp(*av, "print", strlen(*av))) {
1453 list(--ac,++av);
1454 } else if (!strncmp(*av, "list", strlen(*av))) {
1455 list(--ac,++av);
1456 } else if (!strncmp(*av, "show", strlen(*av))) {
1457 do_acct++;
1458 list(--ac,++av);
1459 } else {
1460 show_usage("Bad arguments");
1461 }
1462 return 0;
1463 }
1464
1465 int
1466 main(ac, av)
1467 int ac;
1468 char **av;
1469 {
1470 #define MAX_ARGS 32
1471 #define WHITESP " \t\f\v\n\r"
1472 char buf[BUFSIZ];
1473 char *a, *p, *args[MAX_ARGS], *cmd = NULL;
1474 char linename[10];
1475 int i, c, qflag, pflag, status;
1476 FILE *f = NULL;
1477 pid_t preproc = 0;
1478
1479 s = socket( AF_INET, SOCK_RAW, IPPROTO_RAW );
1480 if ( s < 0 )
1481 err(EX_UNAVAILABLE, "socket");
1482
1483 setbuf(stdout,0);
1484
1485 if (ac > 1 && access(av[ac - 1], R_OK) == 0) {
1486 qflag = pflag = i = 0;
1487 lineno = 0;
1488
1489 while ((c = getopt(ac, av, "D:U:p:q")) != -1)
1490 switch(c) {
1491 case 'D':
1492 if (!pflag)
1493 errx(EX_USAGE, "-D requires -p");
1494 if (i > MAX_ARGS - 2)
1495 errx(EX_USAGE,
1496 "too many -D or -U options");
1497 args[i++] = "-D";
1498 args[i++] = optarg;
1499 break;
1500
1501 case 'U':
1502 if (!pflag)
1503 errx(EX_USAGE, "-U requires -p");
1504 if (i > MAX_ARGS - 2)
1505 errx(EX_USAGE,
1506 "too many -D or -U options");
1507 args[i++] = "-U";
1508 args[i++] = optarg;
1509 break;
1510
1511 case 'p':
1512 pflag = 1;
1513 cmd = optarg;
1514 args[0] = cmd;
1515 i = 1;
1516 break;
1517
1518 case 'q':
1519 qflag = 1;
1520 break;
1521
1522 default:
1523 show_usage(NULL);
1524 }
1525
1526 av += optind;
1527 ac -= optind;
1528 if (ac != 1)
1529 show_usage("extraneous filename arguments");
1530
1531 if ((f = fopen(av[0], "r")) == NULL)
1532 err(EX_UNAVAILABLE, "fopen: %s", av[0]);
1533
1534 if (pflag) {
1535 /* pipe through preprocessor (cpp or m4) */
1536 int pipedes[2];
1537
1538 args[i] = 0;
1539
1540 if (pipe(pipedes) == -1)
1541 err(EX_OSERR, "cannot create pipe");
1542
1543 switch((preproc = fork())) {
1544 case -1:
1545 err(EX_OSERR, "cannot fork");
1546
1547 case 0:
1548 /* child */
1549 if (dup2(fileno(f), 0) == -1 ||
1550 dup2(pipedes[1], 1) == -1)
1551 err(EX_OSERR, "dup2()");
1552 fclose(f);
1553 close(pipedes[1]);
1554 close(pipedes[0]);
1555 execvp(cmd, args);
1556 err(EX_OSERR, "execvp(%s) failed", cmd);
1557
1558 default:
1559 /* parent */
1560 fclose(f);
1561 close(pipedes[1]);
1562 if ((f = fdopen(pipedes[0], "r")) == NULL) {
1563 int savederrno = errno;
1564
1565 (void)kill(preproc, SIGTERM);
1566 errno = savederrno;
1567 err(EX_OSERR, "fdopen()");
1568 }
1569 }
1570 }
1571
1572 while (fgets(buf, BUFSIZ, f)) {
1573 lineno++;
1574 sprintf(linename, "Line %d", lineno);
1575 args[0] = linename;
1576
1577 if (*buf == '#')
1578 continue;
1579 if ((p = strchr(buf, '#')) != NULL)
1580 *p = '\0';
1581 i=1;
1582 if (qflag) args[i++]="-q";
1583 for (a = strtok(buf, WHITESP);
1584 a && i < MAX_ARGS; a = strtok(NULL, WHITESP), i++)
1585 args[i] = a;
1586 if (i == (qflag? 2: 1))
1587 continue;
1588 if (i == MAX_ARGS)
1589 errx(EX_USAGE, "%s: too many arguments", linename);
1590 args[i] = NULL;
1591
1592 ipfw_main(i, args);
1593 }
1594 fclose(f);
1595 if (pflag) {
1596 if (waitpid(preproc, &status, 0) != -1) {
1597 if (WIFEXITED(status)) {
1598 if (WEXITSTATUS(status) != EX_OK)
1599 errx(EX_UNAVAILABLE,
1600 "preprocessor exited with status %d",
1601 WEXITSTATUS(status));
1602 } else if (WIFSIGNALED(status)) {
1603 errx(EX_UNAVAILABLE,
1604 "preprocessor exited with signal %d",
1605 WTERMSIG(status));
1606 }
1607 }
1608 }
1609
1610 } else
1611 ipfw_main(ac,av);
1612 return EX_OK;
1613 }