]> git.saurik.com Git - apple/network_cmds.git/blob - ip6fw.tproj/ip6fw.c
7f78a9f1b74d3d9853217cabb788ce4e10f6738f
[apple/network_cmds.git] / ip6fw.tproj / ip6fw.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: ip6fw.c,v 1.3 2006/02/07 06:22:17 lindak Exp $
20 * $FreeBSD: src/sbin/ip6fw/ip6fw.c,v 1.1.2.6 2001/08/01 06:52:18 obrien Exp $
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/ioctl.h>
29 #include <sys/wait.h>
30
31 #include <ctype.h>
32 #include <err.h>
33 #include <limits.h>
34 #include <netdb.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <stdarg.h>
38 #include <string.h>
39 #include <time.h>
40 #include <unistd.h>
41 #include <errno.h>
42 #include <signal.h>
43 #include <sysexits.h>
44
45 #include <net/if.h>
46 #include <netinet/in.h>
47 #include <netinet/in_systm.h>
48 #include <netinet/ip6.h>
49 #include <netinet/icmp6.h>
50 #include <netinet6/ip6_fw.h>
51 #include <netinet/tcp.h>
52 #include <arpa/inet.h>
53
54 int lineno = -1;
55
56 int s; /* main RAW socket */
57 int do_resolv=0; /* Would try to resolv all */
58 int do_acct=0; /* Show packet/byte count */
59 int do_time=0; /* Show time stamps */
60 int do_quiet=0; /* Be quiet in add and flush */
61 int do_force=0; /* Don't ask for confirmation */
62
63 struct icmpcode {
64 int code;
65 char *str;
66 };
67
68 static struct icmpcode icmp6codes[] = {
69 { ICMP6_DST_UNREACH_NOROUTE, "noroute" },
70 { ICMP6_DST_UNREACH_ADMIN, "admin" },
71 { ICMP6_DST_UNREACH_NOTNEIGHBOR, "notneighbor" },
72 { ICMP6_DST_UNREACH_ADDR, "addr" },
73 { ICMP6_DST_UNREACH_NOPORT, "noport" },
74 { 0, NULL }
75 };
76
77 static char ntop_buf[INET6_ADDRSTRLEN];
78
79 static void show_usage(const char *fmt, ...);
80
81 static int
82 mask_bits(u_char *m_ad, int m_len)
83 {
84 int h_num = 0,i;
85
86 for (i = 0; i < m_len; i++, m_ad++) {
87 if (*m_ad != 0xff)
88 break;
89 h_num += 8;
90 }
91 if (i < m_len) {
92 switch (*m_ad) {
93 #define MASKLEN(m, l) case m: h_num += l; break
94 MASKLEN(0xfe, 7);
95 MASKLEN(0xfc, 6);
96 MASKLEN(0xf8, 5);
97 MASKLEN(0xf0, 4);
98 MASKLEN(0xe0, 3);
99 MASKLEN(0xc0, 2);
100 MASKLEN(0x80, 1);
101 #undef MASKLEN
102 }
103 }
104 return h_num;
105 }
106
107 static int pl2m[9] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
108
109 struct in6_addr *plen2mask(int n)
110 {
111 static struct in6_addr ia;
112 u_char *p;
113 int i;
114
115 memset(&ia, 0, sizeof(struct in6_addr));
116 p = (u_char *)&ia;
117 for (i = 0; i < 16; i++, p++, n -= 8) {
118 if (n >= 8) {
119 *p = 0xff;
120 continue;
121 }
122 *p = pl2m[n];
123 break;
124 }
125 return &ia;
126 }
127
128 void
129 print_port(prot, port, comma)
130 u_char prot;
131 u_short port;
132 const char *comma;
133 {
134 struct servent *se;
135 struct protoent *pe;
136 const char *protocol;
137 int printed = 0;
138
139 if (do_resolv) {
140 pe = getprotobynumber(prot);
141 if (pe)
142 protocol = pe->p_name;
143 else
144 protocol = NULL;
145
146 se = getservbyport(htons(port), protocol);
147 if (se) {
148 printf("%s%s", comma, se->s_name);
149 printed = 1;
150 }
151 }
152 if (!printed)
153 printf("%s%d",comma,port);
154 }
155
156 static void
157 print_iface(char *key, union ip6_fw_if *un, int byname)
158 {
159 char ifnb[IP6FW_IFNLEN+1];
160
161 if (byname) {
162 strncpy(ifnb, un->fu_via_if.name, IP6FW_IFNLEN);
163 ifnb[IP6FW_IFNLEN]='\0';
164 if (un->fu_via_if.unit == -1)
165 printf(" %s %s*", key, ifnb);
166 else
167 printf(" %s %s%d", key, ifnb, un->fu_via_if.unit);
168 } else if (!IN6_IS_ADDR_UNSPECIFIED(&un->fu_via_ip6)) {
169 printf(" %s %s", key, inet_ntop(AF_INET6,&un->fu_via_ip6,ntop_buf,sizeof(ntop_buf)));
170 } else
171 printf(" %s any", key);
172 }
173
174 static void
175 print_reject_code(int code)
176 {
177 struct icmpcode *ic;
178
179 for (ic = icmp6codes; ic->str; ic++)
180 if (ic->code == code) {
181 printf("%s", ic->str);
182 return;
183 }
184 printf("%u", code);
185 }
186
187 static void
188 show_ip6fw(struct ip6_fw *chain)
189 {
190 char *comma;
191 struct hostent *he;
192 struct protoent *pe;
193 int i, mb;
194 int nsp = IPV6_FW_GETNSRCP(chain);
195 int ndp = IPV6_FW_GETNDSTP(chain);
196
197 if (do_resolv)
198 setservent(1/*stayopen*/);
199
200 printf("%05u ", chain->fw_number);
201
202 if (do_acct)
203 printf("%10lu %10lu ",chain->fw_pcnt,chain->fw_bcnt);
204
205 if (do_time)
206 {
207 if (chain->timestamp)
208 {
209 char timestr[30];
210
211 strcpy(timestr, ctime((time_t *)&chain->timestamp));
212 *strchr(timestr, '\n') = '\0';
213 printf("%s ", timestr);
214 }
215 else
216 printf(" ");
217 }
218
219 switch (chain->fw_flg & IPV6_FW_F_COMMAND)
220 {
221 case IPV6_FW_F_ACCEPT:
222 printf("allow");
223 break;
224 case IPV6_FW_F_DENY:
225 printf("deny");
226 break;
227 case IPV6_FW_F_COUNT:
228 printf("count");
229 break;
230 case IPV6_FW_F_DIVERT:
231 printf("divert %u", chain->fw_divert_port);
232 break;
233 case IPV6_FW_F_TEE:
234 printf("tee %u", chain->fw_divert_port);
235 break;
236 case IPV6_FW_F_SKIPTO:
237 printf("skipto %u", chain->fw_skipto_rule);
238 break;
239 case IPV6_FW_F_REJECT:
240 if (chain->fw_reject_code == IPV6_FW_REJECT_RST)
241 printf("reset");
242 else {
243 printf("unreach ");
244 print_reject_code(chain->fw_reject_code);
245 }
246 break;
247 default:
248 errx(EX_OSERR, "impossible");
249 }
250
251 if (chain->fw_flg & IPV6_FW_F_PRN)
252 printf(" log");
253
254 pe = getprotobynumber(chain->fw_prot);
255 if (pe)
256 printf(" %s", pe->p_name);
257 else
258 printf(" %u", chain->fw_prot);
259
260 printf(" from %s", chain->fw_flg & IPV6_FW_F_INVSRC ? "not " : "");
261
262 mb=mask_bits((u_char *)&chain->fw_smsk,sizeof(chain->fw_smsk));
263 if (mb==128 && do_resolv) {
264 he=gethostbyaddr((char *)&(chain->fw_src),sizeof(chain->fw_src),AF_INET6);
265 if (he==NULL) {
266 printf(inet_ntop(AF_INET6,&chain->fw_src,ntop_buf,sizeof(ntop_buf)));
267 } else
268 printf("%s",he->h_name);
269 } else {
270 if (mb!=128) {
271 if (mb == 0) {
272 printf("any");
273 } else {
274 printf(inet_ntop(AF_INET6,&chain->fw_src,ntop_buf,sizeof(ntop_buf)));
275 printf("/%d",mb);
276 }
277 } else
278 printf(inet_ntop(AF_INET6,&chain->fw_src,ntop_buf,sizeof(ntop_buf)));
279 }
280
281 if (chain->fw_prot == IPPROTO_TCP || chain->fw_prot == IPPROTO_UDP) {
282 comma = " ";
283 for (i = 0; i < nsp; i++) {
284 print_port(chain->fw_prot, chain->fw_pts[i], comma);
285 if (i==0 && (chain->fw_flg & IPV6_FW_F_SRNG))
286 comma = "-";
287 else
288 comma = ",";
289 }
290 }
291
292 printf(" to %s", chain->fw_flg & IPV6_FW_F_INVDST ? "not " : "");
293
294 mb=mask_bits((u_char *)&chain->fw_dmsk,sizeof(chain->fw_dmsk));
295 if (mb==128 && do_resolv) {
296 he=gethostbyaddr((char *)&(chain->fw_dst),sizeof(chain->fw_dst),AF_INET);
297 if (he==NULL) {
298 printf(inet_ntop(AF_INET6,&chain->fw_dst,ntop_buf,sizeof(ntop_buf)));
299 } else
300 printf("%s",he->h_name);
301 } else {
302 if (mb!=128) {
303 if (mb == 0) {
304 printf("any");
305 } else {
306 printf(inet_ntop(AF_INET6,&chain->fw_dst,ntop_buf,sizeof(ntop_buf)));
307 printf("/%d",mb);
308 }
309 } else
310 printf(inet_ntop(AF_INET6,&chain->fw_dst,ntop_buf,sizeof(ntop_buf)));
311 }
312
313 if (chain->fw_prot == IPPROTO_TCP || chain->fw_prot == IPPROTO_UDP) {
314 comma = " ";
315 for (i = 0; i < ndp; i++) {
316 print_port(chain->fw_prot, chain->fw_pts[nsp+i], comma);
317 if (i==0 && (chain->fw_flg & IPV6_FW_F_DRNG))
318 comma = "-";
319 else
320 comma = ",";
321 }
322 }
323
324 /* Direction */
325 if ((chain->fw_flg & IPV6_FW_F_IN) && !(chain->fw_flg & IPV6_FW_F_OUT))
326 printf(" in");
327 if (!(chain->fw_flg & IPV6_FW_F_IN) && (chain->fw_flg & IPV6_FW_F_OUT))
328 printf(" out");
329
330 /* Handle hack for "via" backwards compatibility */
331 if ((chain->fw_flg & IF6_FW_F_VIAHACK) == IF6_FW_F_VIAHACK) {
332 print_iface("via",
333 &chain->fw_in_if, chain->fw_flg & IPV6_FW_F_IIFNAME);
334 } else {
335 /* Receive interface specified */
336 if (chain->fw_flg & IPV6_FW_F_IIFACE)
337 print_iface("recv", &chain->fw_in_if,
338 chain->fw_flg & IPV6_FW_F_IIFNAME);
339 /* Transmit interface specified */
340 if (chain->fw_flg & IPV6_FW_F_OIFACE)
341 print_iface("xmit", &chain->fw_out_if,
342 chain->fw_flg & IPV6_FW_F_OIFNAME);
343 }
344
345 if (chain->fw_flg & IPV6_FW_F_FRAG)
346 printf(" frag");
347
348 if (chain->fw_ip6opt || chain->fw_ip6nopt) {
349 int _opt_printed = 0;
350 #define PRINTOPT(x) {if (_opt_printed) printf(",");\
351 printf(x); _opt_printed = 1;}
352
353 printf(" ip6opt ");
354 if (chain->fw_ip6opt & IPV6_FW_IP6OPT_HOPOPT) PRINTOPT("hopopt");
355 if (chain->fw_ip6nopt & IPV6_FW_IP6OPT_HOPOPT) PRINTOPT("!hopopt");
356 if (chain->fw_ip6opt & IPV6_FW_IP6OPT_ROUTE) PRINTOPT("route");
357 if (chain->fw_ip6nopt & IPV6_FW_IP6OPT_ROUTE) PRINTOPT("!route");
358 if (chain->fw_ip6opt & IPV6_FW_IP6OPT_FRAG) PRINTOPT("frag");
359 if (chain->fw_ip6nopt & IPV6_FW_IP6OPT_FRAG) PRINTOPT("!frag");
360 if (chain->fw_ip6opt & IPV6_FW_IP6OPT_ESP) PRINTOPT("esp");
361 if (chain->fw_ip6nopt & IPV6_FW_IP6OPT_ESP) PRINTOPT("!esp");
362 if (chain->fw_ip6opt & IPV6_FW_IP6OPT_AH) PRINTOPT("ah");
363 if (chain->fw_ip6nopt & IPV6_FW_IP6OPT_AH) PRINTOPT("!ah");
364 if (chain->fw_ip6opt & IPV6_FW_IP6OPT_NONXT) PRINTOPT("nonxt");
365 if (chain->fw_ip6nopt & IPV6_FW_IP6OPT_NONXT) PRINTOPT("!nonxt");
366 if (chain->fw_ip6opt & IPV6_FW_IP6OPT_OPTS) PRINTOPT("opts");
367 if (chain->fw_ip6nopt & IPV6_FW_IP6OPT_OPTS) PRINTOPT("!opts");
368 }
369
370 if (chain->fw_ipflg & IPV6_FW_IF_TCPEST)
371 printf(" established");
372 else if (chain->fw_tcpf == IPV6_FW_TCPF_SYN &&
373 chain->fw_tcpnf == IPV6_FW_TCPF_ACK)
374 printf(" setup");
375 else if (chain->fw_tcpf || chain->fw_tcpnf) {
376 int _flg_printed = 0;
377 #define PRINTFLG(x) {if (_flg_printed) printf(",");\
378 printf(x); _flg_printed = 1;}
379
380 printf(" tcpflg ");
381 if (chain->fw_tcpf & IPV6_FW_TCPF_FIN) PRINTFLG("fin");
382 if (chain->fw_tcpnf & IPV6_FW_TCPF_FIN) PRINTFLG("!fin");
383 if (chain->fw_tcpf & IPV6_FW_TCPF_SYN) PRINTFLG("syn");
384 if (chain->fw_tcpnf & IPV6_FW_TCPF_SYN) PRINTFLG("!syn");
385 if (chain->fw_tcpf & IPV6_FW_TCPF_RST) PRINTFLG("rst");
386 if (chain->fw_tcpnf & IPV6_FW_TCPF_RST) PRINTFLG("!rst");
387 if (chain->fw_tcpf & IPV6_FW_TCPF_PSH) PRINTFLG("psh");
388 if (chain->fw_tcpnf & IPV6_FW_TCPF_PSH) PRINTFLG("!psh");
389 if (chain->fw_tcpf & IPV6_FW_TCPF_ACK) PRINTFLG("ack");
390 if (chain->fw_tcpnf & IPV6_FW_TCPF_ACK) PRINTFLG("!ack");
391 if (chain->fw_tcpf & IPV6_FW_TCPF_URG) PRINTFLG("urg");
392 if (chain->fw_tcpnf & IPV6_FW_TCPF_URG) PRINTFLG("!urg");
393 }
394 if (chain->fw_flg & IPV6_FW_F_ICMPBIT) {
395 int type_index;
396 int first = 1;
397
398 printf(" icmptype");
399
400 for (type_index = 0; type_index < IPV6_FW_ICMPTYPES_DIM * sizeof(unsigned) * 8; ++type_index)
401 if (chain->fw_icmp6types[type_index / (sizeof(unsigned) * 8)] &
402 (1U << (type_index % (sizeof(unsigned) * 8)))) {
403 printf("%c%d", first == 1 ? ' ' : ',', type_index);
404 first = 0;
405 }
406 }
407 printf("\n");
408 if (do_resolv)
409 endservent();
410 }
411
412 void
413 list(ac, av)
414 int ac;
415 char **av;
416 {
417 struct ip6_fw *r, *rules;
418 int l,i;
419 unsigned long rulenum;
420 int nalloc, maxbytes;
421 socklen_t bytes;
422
423 /* extract rules from kernel, resizing array as necessary */
424 rules = NULL;
425 nalloc = sizeof *rules;
426 bytes = nalloc;
427 maxbytes = 65536 * sizeof *rules;
428 while (bytes >= nalloc) {
429 nalloc = nalloc * 2 + 200;
430 bytes = nalloc;
431 if ((rules = realloc(rules, bytes)) == NULL)
432 err(EX_OSERR, "realloc");
433 memset(rules, 0, sizeof *rules);
434 rules->version = IPV6_FW_CURRENT_API_VERSION;
435 i = getsockopt(s, IPPROTO_IPV6, IPV6_FW_GET, rules, &bytes);
436 if ((i < 0 && errno != EINVAL) || nalloc > maxbytes)
437 err(EX_OSERR, "getsockopt(IPV6_FW_GET)");
438 }
439 if (!ac) {
440 /* display all rules */
441 for (r = rules, l = bytes; l >= sizeof rules[0];
442 r++, l-=sizeof rules[0])
443 show_ip6fw(r);
444 }
445 else {
446 /* display specific rules requested on command line */
447 int exitval = 0;
448
449 while (ac--) {
450 char *endptr;
451 int seen;
452
453 /* convert command line rule # */
454 rulenum = strtoul(*av++, &endptr, 10);
455 if (*endptr) {
456 exitval = 1;
457 warn("invalid rule number: %s", av[-1]);
458 continue;
459 }
460 seen = 0;
461 for (r = rules, l = bytes;
462 l >= sizeof rules[0] && r->fw_number <= rulenum;
463 r++, l-=sizeof rules[0])
464 if (rulenum == r->fw_number) {
465 show_ip6fw(r);
466 seen = 1;
467 }
468 if (!seen) {
469 exitval = 1;
470 warnx("rule %lu does not exist", rulenum);
471 }
472 }
473 if (exitval != 0)
474 exit(exitval);
475 }
476 }
477
478 static void
479 show_usage(const char *fmt, ...)
480 {
481 if (fmt) {
482 char buf[100];
483 va_list args;
484
485 va_start(args, fmt);
486 vsnprintf(buf, sizeof(buf), fmt, args);
487 va_end(args);
488 warnx("error: %s", buf);
489 }
490 fprintf(stderr, "usage: ip6fw [options]\n"
491 " flush\n"
492 " add [number] rule\n"
493 " delete number ...\n"
494 " list [number ...]\n"
495 " show [number ...]\n"
496 " zero [number ...]\n"
497 " rule: action proto src dst extras...\n"
498 " action:\n"
499 " {allow|permit|accept|pass|deny|drop|reject|unreach code|\n"
500 " reset|count|skipto num} [log]\n"
501 " proto: {ipv6|tcp|udp|ipv6-icmp|<number>}\n"
502 " src: from [not] {any|ipv6[/prefixlen]} [{port|port-port},[port],...]\n"
503 " dst: to [not] {any|ipv6[/prefixlen]} [{port|port-port},[port],...]\n"
504 " extras:\n"
505 " fragment (may not be used with ports or tcpflags)\n"
506 " in\n"
507 " out\n"
508 " {xmit|recv|via} {iface|ipv6|any}\n"
509 " {established|setup}\n"
510 " tcpflags [!]{syn|fin|rst|ack|psh|urg},...\n"
511 " ipv6options [!]{hopopt|route|frag|esp|ah|nonxt|opts},...\n"
512 " icmptypes {type[,type]}...\n");
513
514 exit(1);
515 }
516
517 static int
518 lookup_host (host, addr, family)
519 char *host;
520 u_char *addr;
521 {
522 struct hostent *he = gethostbyname2(host, family);
523
524 if (!he)
525 return(-1);
526
527 memcpy(addr, he->h_addr_list[0], he->h_length);
528
529 return(0);
530 }
531
532 void
533 fill_ip6(ipno, mask, acp, avp)
534 struct in6_addr *ipno, *mask;
535 int *acp;
536 char ***avp;
537 {
538 int ac = *acp;
539 char **av = *avp;
540 char *p = 0, md = 0;
541 int i;
542
543 if (ac && !strncmp(*av,"any",strlen(*av))) {
544 *ipno = *mask = in6addr_any; av++; ac--;
545 } else {
546 p = strchr(*av, '/');
547 if (p) {
548 md = *p;
549 *p++ = '\0';
550 }
551
552 if (lookup_host(*av, (u_char *)ipno, AF_INET6) != 0)
553 show_usage("hostname ``%s'' unknown", *av);
554 switch (md) {
555 case '/':
556 if (atoi(p) == 0) {
557 *mask = in6addr_any;
558 } else if (atoi(p) > 128) {
559 show_usage("bad width ``%s''", p);
560 } else {
561 *mask = *(plen2mask(atoi(p)));
562 }
563 break;
564 default:
565 *mask = *(plen2mask(128));
566 break;
567 }
568 for (i = 0; i < sizeof(*ipno); i++)
569 ipno->s6_addr[i] &= mask->s6_addr[i];
570 av++;
571 ac--;
572 }
573 *acp = ac;
574 *avp = av;
575 }
576
577 static void
578 fill_reject_code6(u_short *codep, char *str)
579 {
580 struct icmpcode *ic;
581 u_long val;
582 char *s;
583
584 val = strtoul(str, &s, 0);
585 if (s != str && *s == '\0' && val < 0x100) {
586 *codep = val;
587 return;
588 }
589 for (ic = icmp6codes; ic->str; ic++)
590 if (!strcasecmp(str, ic->str)) {
591 *codep = ic->code;
592 return;
593 }
594 show_usage("unknown ICMP6 unreachable code ``%s''", str);
595 }
596
597 static void
598 add_port(cnt, ptr, off, port)
599 u_short *cnt, *ptr, off, port;
600 {
601 if (off + *cnt >= IPV6_FW_MAX_PORTS)
602 errx(1, "too many ports (max is %d)", IPV6_FW_MAX_PORTS);
603 ptr[off+*cnt] = port;
604 (*cnt)++;
605 }
606
607 static int
608 lookup_port(const char *arg, int test, int nodash)
609 {
610 int val;
611 char *earg, buf[32];
612 struct servent *s;
613
614 snprintf(buf, sizeof(buf), "%s", arg);
615 buf[strcspn(arg, nodash ? "-," : ",")] = 0;
616 val = (int) strtoul(buf, &earg, 0);
617 if (!*buf || *earg) {
618 setservent(1);
619 if ((s = getservbyname(buf, NULL))) {
620 val = htons(s->s_port);
621 } else {
622 if (!test) {
623 errx(1, "unknown port ``%s''", arg);
624 }
625 val = -1;
626 }
627 } else {
628 if (val < 0 || val > 0xffff) {
629 if (!test) {
630 errx(1, "port ``%s'' out of range", arg);
631 }
632 val = -1;
633 }
634 }
635 return(val);
636 }
637
638 int
639 fill_port(cnt, ptr, off, arg)
640 u_short *cnt, *ptr, off;
641 char *arg;
642 {
643 char *s;
644 int initial_range = 0;
645
646 s = arg + strcspn(arg, "-,"); /* first port name can't have a dash */
647 if (*s == '-') {
648 *s++ = '\0';
649 if (strchr(arg, ','))
650 errx(1, "port range must be first in list");
651 add_port(cnt, ptr, off, *arg ? lookup_port(arg, 0, 0) : 0x0000);
652 arg = s;
653 s = strchr(arg,',');
654 if (s)
655 *s++ = '\0';
656 add_port(cnt, ptr, off, *arg ? lookup_port(arg, 0, 0) : 0xffff);
657 arg = s;
658 initial_range = 1;
659 }
660 while (arg != NULL) {
661 s = strchr(arg,',');
662 if (s)
663 *s++ = '\0';
664 add_port(cnt, ptr, off, lookup_port(arg, 0, 0));
665 arg = s;
666 }
667 return initial_range;
668 }
669
670 void
671 fill_tcpflag(set, reset, vp)
672 u_char *set, *reset;
673 char **vp;
674 {
675 char *p = *vp,*q;
676 u_char *d;
677
678 while (p && *p) {
679 struct tpcflags {
680 char * name;
681 u_char value;
682 } flags[] = {
683 { "syn", IPV6_FW_TCPF_SYN },
684 { "fin", IPV6_FW_TCPF_FIN },
685 { "ack", IPV6_FW_TCPF_ACK },
686 { "psh", IPV6_FW_TCPF_PSH },
687 { "rst", IPV6_FW_TCPF_RST },
688 { "urg", IPV6_FW_TCPF_URG }
689 };
690 int i;
691
692 if (*p == '!') {
693 p++;
694 d = reset;
695 } else {
696 d = set;
697 }
698 q = strchr(p, ',');
699 if (q)
700 *q++ = '\0';
701 for (i = 0; i < sizeof(flags) / sizeof(flags[0]); ++i)
702 if (!strncmp(p, flags[i].name, strlen(p))) {
703 *d |= flags[i].value;
704 break;
705 }
706 if (i == sizeof(flags) / sizeof(flags[0]))
707 show_usage("invalid tcp flag ``%s''", p);
708 p = q;
709 }
710 }
711
712 static void
713 fill_ip6opt(u_char *set, u_char *reset, char **vp)
714 {
715 char *p = *vp,*q;
716 u_char *d;
717
718 while (p && *p) {
719 if (*p == '!') {
720 p++;
721 d = reset;
722 } else {
723 d = set;
724 }
725 q = strchr(p, ',');
726 if (q)
727 *q++ = '\0';
728 if (!strncmp(p,"hopopt",strlen(p))) *d |= IPV6_FW_IP6OPT_HOPOPT;
729 if (!strncmp(p,"route",strlen(p))) *d |= IPV6_FW_IP6OPT_ROUTE;
730 if (!strncmp(p,"frag",strlen(p))) *d |= IPV6_FW_IP6OPT_FRAG;
731 if (!strncmp(p,"esp",strlen(p))) *d |= IPV6_FW_IP6OPT_ESP;
732 if (!strncmp(p,"ah",strlen(p))) *d |= IPV6_FW_IP6OPT_AH;
733 if (!strncmp(p,"nonxt",strlen(p))) *d |= IPV6_FW_IP6OPT_NONXT;
734 if (!strncmp(p,"opts",strlen(p))) *d |= IPV6_FW_IP6OPT_OPTS;
735 p = q;
736 }
737 }
738
739 void
740 fill_icmptypes(types, vp, fw_flg)
741 u_long *types;
742 char **vp;
743 u_short *fw_flg;
744 {
745 char *c = *vp;
746
747 while (*c)
748 {
749 unsigned long icmptype;
750
751 if ( *c == ',' )
752 ++c;
753
754 icmptype = strtoul(c, &c, 0);
755
756 if ( *c != ',' && *c != '\0' )
757 show_usage("invalid ICMP6 type");
758
759 if (icmptype >= IPV6_FW_ICMPTYPES_DIM * sizeof(unsigned) * 8)
760 show_usage("ICMP6 type out of range");
761
762 types[icmptype / (sizeof(unsigned) * 8)] |=
763 1 << (icmptype % (sizeof(unsigned) * 8));
764 *fw_flg |= IPV6_FW_F_ICMPBIT;
765 }
766 }
767
768 void
769 delete(ac,av)
770 int ac;
771 char **av;
772 {
773 struct ip6_fw rule;
774 int i;
775 int exitval = 0;
776
777 memset(&rule, 0, sizeof rule);
778 rule.version = IPV6_FW_CURRENT_API_VERSION;
779
780 av++; ac--;
781
782 /* Rule number */
783 while (ac && isdigit(**av)) {
784 rule.fw_number = atoi(*av); av++; ac--;
785 i = setsockopt(s, IPPROTO_IPV6, IPV6_FW_DEL, &rule, sizeof rule);
786 if (i) {
787 exitval = 1;
788 warn("rule %u: setsockopt(%s)", rule.fw_number, "IPV6_FW_DEL");
789 }
790 }
791 if (exitval != 0)
792 exit(exitval);
793 }
794
795 static void
796 verify_interface(union ip6_fw_if *ifu)
797 {
798 struct ifreq ifr;
799
800 /*
801 * If a unit was specified, check for that exact interface.
802 * If a wildcard was specified, check for unit 0.
803 */
804 snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d",
805 ifu->fu_via_if.name,
806 ifu->fu_via_if.unit == -1 ? 0 : ifu->fu_via_if.unit);
807
808 if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0)
809 warnx("warning: interface ``%s'' does not exist", ifr.ifr_name);
810 }
811
812 static void
813 fill_iface(char *which, union ip6_fw_if *ifu, int *byname, int ac, char *arg)
814 {
815 if (!ac)
816 show_usage("missing argument for ``%s''", which);
817
818 /* Parse the interface or address */
819 if (!strcmp(arg, "any")) {
820 ifu->fu_via_ip6 = in6addr_any;
821 *byname = 0;
822 } else if (!isdigit(*arg)) {
823 char *q;
824
825 *byname = 1;
826 strncpy(ifu->fu_via_if.name, arg, sizeof(ifu->fu_via_if.name));
827 ifu->fu_via_if.name[sizeof(ifu->fu_via_if.name) - 1] = '\0';
828 for (q = ifu->fu_via_if.name;
829 *q && !isdigit(*q) && *q != '*'; q++)
830 continue;
831 ifu->fu_via_if.unit = (*q == '*') ? -1 : atoi(q);
832 *q = '\0';
833 verify_interface(ifu);
834 } else if (inet_pton(AF_INET6, arg, &ifu->fu_via_ip6) != 1) {
835 show_usage("bad ip6 address ``%s''", arg);
836 } else
837 *byname = 0;
838 }
839
840 static void
841 add(ac,av)
842 int ac;
843 char **av;
844 {
845 struct ip6_fw rule;
846 int i;
847 u_char proto;
848 struct protoent *pe;
849 int saw_xmrc = 0, saw_via = 0;
850
851 memset(&rule, 0, sizeof rule);
852 rule.version = IPV6_FW_CURRENT_API_VERSION;
853
854 av++; ac--;
855
856 /* Rule number */
857 if (ac && isdigit(**av)) {
858 rule.fw_number = atoi(*av); av++; ac--;
859 }
860
861 /* Action */
862 if (ac == 0)
863 show_usage("missing action");
864 if (!strncmp(*av,"accept",strlen(*av))
865 || !strncmp(*av,"pass",strlen(*av))
866 || !strncmp(*av,"allow",strlen(*av))
867 || !strncmp(*av,"permit",strlen(*av))) {
868 rule.fw_flg |= IPV6_FW_F_ACCEPT; av++; ac--;
869 } else if (!strncmp(*av,"count",strlen(*av))) {
870 rule.fw_flg |= IPV6_FW_F_COUNT; av++; ac--;
871 }
872 #if 0
873 else if (!strncmp(*av,"divert",strlen(*av))) {
874 rule.fw_flg |= IPV6_FW_F_DIVERT; av++; ac--;
875 if (!ac)
876 show_usage("missing divert port");
877 rule.fw_divert_port = strtoul(*av, NULL, 0); av++; ac--;
878 if (rule.fw_divert_port == 0) {
879 struct servent *s;
880 setservent(1);
881 s = getservbyname(av[-1], "divert");
882 if (s != NULL)
883 rule.fw_divert_port = ntohs(s->s_port);
884 else
885 show_usage("illegal divert port");
886 }
887 } else if (!strncmp(*av,"tee",strlen(*av))) {
888 rule.fw_flg |= IPV6_FW_F_TEE; av++; ac--;
889 if (!ac)
890 show_usage("missing divert port");
891 rule.fw_divert_port = strtoul(*av, NULL, 0); av++; ac--;
892 if (rule.fw_divert_port == 0) {
893 struct servent *s;
894 setservent(1);
895 s = getservbyname(av[-1], "divert");
896 if (s != NULL)
897 rule.fw_divert_port = ntohs(s->s_port);
898 else
899 show_usage("illegal divert port");
900 }
901 }
902 #endif
903 else if (!strncmp(*av,"skipto",strlen(*av))) {
904 rule.fw_flg |= IPV6_FW_F_SKIPTO; av++; ac--;
905 if (!ac)
906 show_usage("missing skipto rule number");
907 rule.fw_skipto_rule = strtoul(*av, NULL, 0); av++; ac--;
908 } else if ((!strncmp(*av,"deny",strlen(*av))
909 || !strncmp(*av,"drop",strlen(*av)))) {
910 rule.fw_flg |= IPV6_FW_F_DENY; av++; ac--;
911 } else if (!strncmp(*av,"reject",strlen(*av))) {
912 rule.fw_flg |= IPV6_FW_F_REJECT; av++; ac--;
913 rule.fw_reject_code = ICMP6_DST_UNREACH_NOROUTE;
914 } else if (!strncmp(*av,"reset",strlen(*av))) {
915 rule.fw_flg |= IPV6_FW_F_REJECT; av++; ac--;
916 rule.fw_reject_code = IPV6_FW_REJECT_RST; /* check TCP later */
917 } else if (!strncmp(*av,"unreach",strlen(*av))) {
918 rule.fw_flg |= IPV6_FW_F_REJECT; av++; ac--;
919 fill_reject_code6(&rule.fw_reject_code, *av); av++; ac--;
920 } else {
921 show_usage("invalid action ``%s''", *av);
922 }
923
924 /* [log] */
925 if (ac && !strncmp(*av,"log",strlen(*av))) {
926 rule.fw_flg |= IPV6_FW_F_PRN; av++; ac--;
927 }
928
929 /* protocol */
930 if (ac == 0)
931 show_usage("missing protocol");
932 if ((proto = atoi(*av)) > 0) {
933 rule.fw_prot = proto; av++; ac--;
934 } else if (!strncmp(*av,"all",strlen(*av))) {
935 rule.fw_prot = IPPROTO_IPV6; av++; ac--;
936 } else if ((pe = getprotobyname(*av)) != NULL) {
937 rule.fw_prot = pe->p_proto; av++; ac--;
938 } else {
939 show_usage("invalid protocol ``%s''", *av);
940 }
941
942 if (rule.fw_prot != IPPROTO_TCP
943 && (rule.fw_flg & IPV6_FW_F_COMMAND) == IPV6_FW_F_REJECT
944 && rule.fw_reject_code == IPV6_FW_REJECT_RST)
945 show_usage("``reset'' is only valid for tcp packets");
946
947 /* from */
948 if (ac && !strncmp(*av,"from",strlen(*av))) { av++; ac--; }
949 else
950 show_usage("missing ``from''");
951
952 if (ac && !strncmp(*av,"not",strlen(*av))) {
953 rule.fw_flg |= IPV6_FW_F_INVSRC;
954 av++; ac--;
955 }
956 if (!ac)
957 show_usage("missing arguments");
958
959 fill_ip6(&rule.fw_src, &rule.fw_smsk, &ac, &av);
960
961 if (ac && (isdigit(**av) || lookup_port(*av, 1, 1) >= 0)) {
962 u_short nports = 0;
963
964 if (fill_port(&nports, rule.fw_pts, 0, *av))
965 rule.fw_flg |= IPV6_FW_F_SRNG;
966 IPV6_FW_SETNSRCP(&rule, nports);
967 av++; ac--;
968 }
969
970 /* to */
971 if (ac && !strncmp(*av,"to",strlen(*av))) { av++; ac--; }
972 else
973 show_usage("missing ``to''");
974
975 if (ac && !strncmp(*av,"not",strlen(*av))) {
976 rule.fw_flg |= IPV6_FW_F_INVDST;
977 av++; ac--;
978 }
979 if (!ac)
980 show_usage("missing arguments");
981
982 fill_ip6(&rule.fw_dst, &rule.fw_dmsk, &ac, &av);
983
984 if (ac && (isdigit(**av) || lookup_port(*av, 1, 1) >= 0)) {
985 u_short nports = 0;
986
987 if (fill_port(&nports,
988 rule.fw_pts, IPV6_FW_GETNSRCP(&rule), *av))
989 rule.fw_flg |= IPV6_FW_F_DRNG;
990 IPV6_FW_SETNDSTP(&rule, nports);
991 av++; ac--;
992 }
993
994 if ((rule.fw_prot != IPPROTO_TCP) && (rule.fw_prot != IPPROTO_UDP)
995 && (IPV6_FW_GETNSRCP(&rule) || IPV6_FW_GETNDSTP(&rule))) {
996 show_usage("only TCP and UDP protocols are valid"
997 " with port specifications");
998 }
999
1000 while (ac) {
1001 if (!strncmp(*av,"in",strlen(*av))) {
1002 rule.fw_flg |= IPV6_FW_F_IN;
1003 av++; ac--; continue;
1004 }
1005 if (!strncmp(*av,"out",strlen(*av))) {
1006 rule.fw_flg |= IPV6_FW_F_OUT;
1007 av++; ac--; continue;
1008 }
1009 if (ac && !strncmp(*av,"xmit",strlen(*av))) {
1010 union ip6_fw_if ifu;
1011 int byname;
1012
1013 if (saw_via) {
1014 badviacombo:
1015 show_usage("``via'' is incompatible"
1016 " with ``xmit'' and ``recv''");
1017 }
1018 saw_xmrc = 1;
1019 av++; ac--;
1020 fill_iface("xmit", &ifu, &byname, ac, *av);
1021 rule.fw_out_if = ifu;
1022 rule.fw_flg |= IPV6_FW_F_OIFACE;
1023 if (byname)
1024 rule.fw_flg |= IPV6_FW_F_OIFNAME;
1025 av++; ac--; continue;
1026 }
1027 if (ac && !strncmp(*av,"recv",strlen(*av))) {
1028 union ip6_fw_if ifu;
1029 int byname;
1030
1031 if (saw_via)
1032 goto badviacombo;
1033 saw_xmrc = 1;
1034 av++; ac--;
1035 fill_iface("recv", &ifu, &byname, ac, *av);
1036 rule.fw_in_if = ifu;
1037 rule.fw_flg |= IPV6_FW_F_IIFACE;
1038 if (byname)
1039 rule.fw_flg |= IPV6_FW_F_IIFNAME;
1040 av++; ac--; continue;
1041 }
1042 if (ac && !strncmp(*av,"via",strlen(*av))) {
1043 union ip6_fw_if ifu;
1044 int byname = 0;
1045
1046 if (saw_xmrc)
1047 goto badviacombo;
1048 saw_via = 1;
1049 av++; ac--;
1050 fill_iface("via", &ifu, &byname, ac, *av);
1051 rule.fw_out_if = rule.fw_in_if = ifu;
1052 if (byname)
1053 rule.fw_flg |=
1054 (IPV6_FW_F_IIFNAME | IPV6_FW_F_OIFNAME);
1055 av++; ac--; continue;
1056 }
1057 if (!strncmp(*av,"fragment",strlen(*av))) {
1058 rule.fw_flg |= IPV6_FW_F_FRAG;
1059 av++; ac--; continue;
1060 }
1061 if (!strncmp(*av,"ipv6options",strlen(*av))) {
1062 av++; ac--;
1063 if (!ac)
1064 show_usage("missing argument"
1065 " for ``ipv6options''");
1066 fill_ip6opt(&rule.fw_ip6opt, &rule.fw_ip6nopt, av);
1067 av++; ac--; continue;
1068 }
1069 if (rule.fw_prot == IPPROTO_TCP) {
1070 if (!strncmp(*av,"established",strlen(*av))) {
1071 rule.fw_ipflg |= IPV6_FW_IF_TCPEST;
1072 av++; ac--; continue;
1073 }
1074 if (!strncmp(*av,"setup",strlen(*av))) {
1075 rule.fw_tcpf |= IPV6_FW_TCPF_SYN;
1076 rule.fw_tcpnf |= IPV6_FW_TCPF_ACK;
1077 av++; ac--; continue;
1078 }
1079 if (!strncmp(*av,"tcpflags",strlen(*av))) {
1080 av++; ac--;
1081 if (!ac)
1082 show_usage("missing argument"
1083 " for ``tcpflags''");
1084 fill_tcpflag(&rule.fw_tcpf, &rule.fw_tcpnf, av);
1085 av++; ac--; continue;
1086 }
1087 }
1088 if (rule.fw_prot == IPPROTO_ICMPV6) {
1089 if (!strncmp(*av,"icmptypes",strlen(*av))) {
1090 av++; ac--;
1091 if (!ac)
1092 show_usage("missing argument"
1093 " for ``icmptypes''");
1094 fill_icmptypes(rule.fw_icmp6types,
1095 av, &rule.fw_flg);
1096 av++; ac--; continue;
1097 }
1098 }
1099 show_usage("unknown argument ``%s''", *av);
1100 }
1101
1102 /* No direction specified -> do both directions */
1103 if (!(rule.fw_flg & (IPV6_FW_F_OUT|IPV6_FW_F_IN)))
1104 rule.fw_flg |= (IPV6_FW_F_OUT|IPV6_FW_F_IN);
1105
1106 /* Sanity check interface check, but handle "via" case separately */
1107 if (saw_via) {
1108 if (rule.fw_flg & IPV6_FW_F_IN)
1109 rule.fw_flg |= IPV6_FW_F_IIFACE;
1110 if (rule.fw_flg & IPV6_FW_F_OUT)
1111 rule.fw_flg |= IPV6_FW_F_OIFACE;
1112 } else if ((rule.fw_flg & IPV6_FW_F_OIFACE) && (rule.fw_flg & IPV6_FW_F_IN))
1113 show_usage("can't check xmit interface of incoming packets");
1114
1115 /* frag may not be used in conjunction with ports or TCP flags */
1116 if (rule.fw_flg & IPV6_FW_F_FRAG) {
1117 if (rule.fw_tcpf || rule.fw_tcpnf)
1118 show_usage("can't mix 'frag' and tcpflags");
1119
1120 if (rule.fw_nports)
1121 show_usage("can't mix 'frag' and port specifications");
1122 }
1123
1124 if (!do_quiet)
1125 show_ip6fw(&rule);
1126 i = setsockopt(s, IPPROTO_IPV6, IPV6_FW_ADD, &rule, sizeof rule);
1127 if (i)
1128 err(EX_UNAVAILABLE, "setsockopt(%s)", "IPV6_FW_ADD");
1129 }
1130
1131 static void
1132 zero (ac, av)
1133 int ac;
1134 char **av;
1135 {
1136 struct ip6_fw rule;
1137
1138 av++; ac--;
1139 memset(&rule, 0, sizeof rule);
1140 rule.version = IPV6_FW_CURRENT_API_VERSION;
1141
1142 if (!ac) {
1143 /* clear all entries */
1144 if (setsockopt(s, IPPROTO_IPV6, IPV6_FW_ZERO, &rule, sizeof rule) < 0)
1145 err(EX_UNAVAILABLE, "setsockopt(%s)", "IPV6_FW_ZERO");
1146 if (!do_quiet)
1147 printf("Accounting cleared.\n");
1148 } else {
1149 int failed = 0;
1150
1151 while (ac) {
1152 /* Rule number */
1153 if (isdigit(**av)) {
1154 rule.fw_number = atoi(*av); av++; ac--;
1155 if (setsockopt(s, IPPROTO_IPV6,
1156 IPV6_FW_ZERO, &rule, sizeof rule)) {
1157 warn("rule %u: setsockopt(%s)", rule.fw_number,
1158 "IPV6_FW_ZERO");
1159 failed = 1;
1160 }
1161 else if (!do_quiet)
1162 printf("Entry %d cleared\n",
1163 rule.fw_number);
1164 } else
1165 show_usage("invalid rule number ``%s''", *av);
1166 }
1167 if (failed != 0)
1168 exit(failed);
1169 }
1170 }
1171
1172 int
1173 ip6fw_main(ac,av)
1174 int ac;
1175 char **av;
1176 {
1177 int ch;
1178 extern int optind;
1179
1180 /* init optind to 1 */
1181 optind = 1;
1182
1183 if ( ac == 1 ) {
1184 show_usage(NULL);
1185 }
1186
1187 /* Set the force flag for non-interactive processes */
1188 do_force = !isatty(STDIN_FILENO);
1189
1190 while ((ch = getopt(ac, av ,"afqtN")) != -1)
1191 switch(ch) {
1192 case 'a':
1193 do_acct=1;
1194 break;
1195 case 'f':
1196 do_force=1;
1197 break;
1198 case 'q':
1199 do_quiet=1;
1200 break;
1201 case 't':
1202 do_time=1;
1203 break;
1204 case 'N':
1205 do_resolv=1;
1206 break;
1207 default:
1208 show_usage(NULL);
1209 }
1210
1211 ac -= optind;
1212 if (*(av+=optind)==NULL) {
1213 show_usage("Bad arguments");
1214 }
1215
1216 if (!strncmp(*av, "add", strlen(*av))) {
1217 add(ac,av);
1218 } else if (!strncmp(*av, "delete", strlen(*av))) {
1219 delete(ac,av);
1220 } else if (!strncmp(*av, "flush", strlen(*av))) {
1221 int do_flush = 0;
1222
1223 if ( do_force || do_quiet )
1224 do_flush = 1;
1225 else {
1226 int c;
1227
1228 /* Ask the user */
1229 printf("Are you sure? [yn] ");
1230 do {
1231 fflush(stdout);
1232 c = toupper(getc(stdin));
1233 while (c != '\n' && getc(stdin) != '\n')
1234 if (feof(stdin))
1235 return (0);
1236 } while (c != 'Y' && c != 'N');
1237 printf("\n");
1238 if (c == 'Y')
1239 do_flush = 1;
1240 }
1241 if ( do_flush ) {
1242 struct ip6_fw rule;
1243
1244 memset(&rule, 0, sizeof rule);
1245 rule.version = IPV6_FW_CURRENT_API_VERSION;
1246 if (setsockopt(s, IPPROTO_IPV6, IPV6_FW_FLUSH, &rule, sizeof rule) < 0)
1247 err(EX_UNAVAILABLE, "setsockopt(%s)", "IPV6_FW_FLUSH");
1248 if (!do_quiet)
1249 printf("Flushed all rules.\n");
1250 }
1251 } else if (!strncmp(*av, "zero", strlen(*av))) {
1252 zero(ac,av);
1253 } else if (!strncmp(*av, "print", strlen(*av))) {
1254 list(--ac,++av);
1255 } else if (!strncmp(*av, "list", strlen(*av))) {
1256 list(--ac,++av);
1257 } else if (!strncmp(*av, "show", strlen(*av))) {
1258 do_acct++;
1259 list(--ac,++av);
1260 } else {
1261 show_usage("Bad arguments");
1262 }
1263 return 0;
1264 }
1265
1266 int
1267 main(ac, av)
1268 int ac;
1269 char **av;
1270 {
1271 #define MAX_ARGS 32
1272 #define WHITESP " \t\f\v\n\r"
1273 char buf[BUFSIZ];
1274 char *a, *p, *args[MAX_ARGS], *cmd = NULL;
1275 char linename[10];
1276 int i, c, lineno, qflag, pflag, status;
1277 FILE *f = NULL;
1278 pid_t preproc = 0;
1279
1280 s = socket( AF_INET6, SOCK_RAW, IPPROTO_RAW );
1281 if ( s < 0 )
1282 err(EX_UNAVAILABLE, "socket");
1283
1284 setbuf(stdout,0);
1285
1286 /*
1287 * Only interpret the last command line argument as a file to
1288 * be preprocessed if it is specified as an absolute pathname.
1289 */
1290
1291 if (ac > 1 && av[ac - 1][0] == '/' && access(av[ac - 1], R_OK) == 0) {
1292 qflag = pflag = i = 0;
1293 lineno = 0;
1294
1295 while ((c = getopt(ac, av, "D:U:p:q")) != -1)
1296 switch(c) {
1297 case 'D':
1298 if (!pflag)
1299 errx(EX_USAGE, "-D requires -p");
1300 if (i > MAX_ARGS - 2)
1301 errx(EX_USAGE,
1302 "too many -D or -U options");
1303 args[i++] = "-D";
1304 args[i++] = optarg;
1305 break;
1306
1307 case 'U':
1308 if (!pflag)
1309 errx(EX_USAGE, "-U requires -p");
1310 if (i > MAX_ARGS - 2)
1311 errx(EX_USAGE,
1312 "too many -D or -U options");
1313 args[i++] = "-U";
1314 args[i++] = optarg;
1315 break;
1316
1317 case 'p':
1318 pflag = 1;
1319 cmd = optarg;
1320 args[0] = cmd;
1321 i = 1;
1322 break;
1323
1324 case 'q':
1325 qflag = 1;
1326 break;
1327
1328 default:
1329 show_usage(NULL);
1330 }
1331
1332 av += optind;
1333 ac -= optind;
1334 if (ac != 1)
1335 show_usage("extraneous filename arguments");
1336
1337 if ((f = fopen(av[0], "r")) == NULL)
1338 err(EX_UNAVAILABLE, "fopen: %s", av[0]);
1339
1340 if (pflag) {
1341 /* pipe through preprocessor (cpp or m4) */
1342 int pipedes[2];
1343
1344 args[i] = 0;
1345
1346 if (pipe(pipedes) == -1)
1347 err(EX_OSERR, "cannot create pipe");
1348
1349 switch((preproc = fork())) {
1350 case -1:
1351 err(EX_OSERR, "cannot fork");
1352
1353 case 0:
1354 /* child */
1355 if (dup2(fileno(f), 0) == -1 ||
1356 dup2(pipedes[1], 1) == -1)
1357 err(EX_OSERR, "dup2()");
1358 fclose(f);
1359 close(pipedes[1]);
1360 close(pipedes[0]);
1361 execvp(cmd, args);
1362 err(EX_OSERR, "execvp(%s) failed", cmd);
1363
1364 default:
1365 /* parent */
1366 fclose(f);
1367 close(pipedes[1]);
1368 if ((f = fdopen(pipedes[0], "r")) == NULL) {
1369 int savederrno = errno;
1370
1371 (void)kill(preproc, SIGTERM);
1372 errno = savederrno;
1373 err(EX_OSERR, "fdopen()");
1374 }
1375 }
1376 }
1377
1378 while (fgets(buf, BUFSIZ, f)) {
1379 lineno++;
1380 sprintf(linename, "Line %d", lineno);
1381 args[0] = linename;
1382
1383 if (*buf == '#')
1384 continue;
1385 if ((p = strchr(buf, '#')) != NULL)
1386 *p = '\0';
1387 i=1;
1388 if (qflag) args[i++]="-q";
1389 for (a = strtok(buf, WHITESP);
1390 a && i < MAX_ARGS; a = strtok(NULL, WHITESP), i++)
1391 args[i] = a;
1392 if (i == (qflag? 2: 1))
1393 continue;
1394 if (i == MAX_ARGS)
1395 errx(EX_USAGE, "%s: too many arguments", linename);
1396 args[i] = NULL;
1397
1398 ip6fw_main(i, args);
1399 }
1400 fclose(f);
1401 if (pflag) {
1402 if (waitpid(preproc, &status, 0) != -1) {
1403 if (WIFEXITED(status)) {
1404 if (WEXITSTATUS(status) != EX_OK)
1405 errx(EX_UNAVAILABLE,
1406 "preprocessor exited with status %d",
1407 WEXITSTATUS(status));
1408 } else if (WIFSIGNALED(status)) {
1409 errx(EX_UNAVAILABLE,
1410 "preprocessor exited with signal %d",
1411 WTERMSIG(status));
1412 }
1413 }
1414 }
1415 } else
1416 ip6fw_main(ac,av);
1417 return 0;
1418 }