]> git.saurik.com Git - apple/network_cmds.git/blame_incremental - ip6fw.tproj/ip6fw.c
network_cmds-245.19.tar.gz
[apple/network_cmds.git] / ip6fw.tproj / ip6fw.c
... / ...
CommitLineData
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.2 2003/02/28 07:01:29 mscopp 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
54int lineno = -1;
55
56int s; /* main RAW socket */
57int do_resolv=0; /* Would try to resolv all */
58int do_acct=0; /* Show packet/byte count */
59int do_time=0; /* Show time stamps */
60int do_quiet=0; /* Be quiet in add and flush */
61int do_force=0; /* Don't ask for confirmation */
62
63struct icmpcode {
64 int code;
65 char *str;
66};
67
68static 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
77static char ntop_buf[INET6_ADDRSTRLEN];
78
79static void show_usage(const char *fmt, ...);
80
81static int
82mask_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
107static int pl2m[9] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
108
109struct 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
128void
129print_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
156static void
157print_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
174static void
175print_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
187static void
188show_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
412void
413list(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, bytes, maxbytes;
421
422 /* extract rules from kernel, resizing array as necessary */
423 rules = NULL;
424 nalloc = sizeof *rules;
425 bytes = nalloc;
426 maxbytes = 65536 * sizeof *rules;
427 while (bytes >= nalloc) {
428 nalloc = nalloc * 2 + 200;
429 bytes = nalloc;
430 if ((rules = realloc(rules, bytes)) == NULL)
431 err(EX_OSERR, "realloc");
432 memset(rules, 0, sizeof *rules);
433 rules->version = IPV6_FW_CURRENT_API_VERSION;
434 i = getsockopt(s, IPPROTO_IPV6, IPV6_FW_GET, rules, &bytes);
435 if ((i < 0 && errno != EINVAL) || nalloc > maxbytes)
436 err(EX_OSERR, "getsockopt(IPV6_FW_GET)");
437 }
438 if (!ac) {
439 /* display all rules */
440 for (r = rules, l = bytes; l >= sizeof rules[0];
441 r++, l-=sizeof rules[0])
442 show_ip6fw(r);
443 }
444 else {
445 /* display specific rules requested on command line */
446 int exitval = 0;
447
448 while (ac--) {
449 char *endptr;
450 int seen;
451
452 /* convert command line rule # */
453 rulenum = strtoul(*av++, &endptr, 10);
454 if (*endptr) {
455 exitval = 1;
456 warn("invalid rule number: %s", av[-1]);
457 continue;
458 }
459 seen = 0;
460 for (r = rules, l = bytes;
461 l >= sizeof rules[0] && r->fw_number <= rulenum;
462 r++, l-=sizeof rules[0])
463 if (rulenum == r->fw_number) {
464 show_ip6fw(r);
465 seen = 1;
466 }
467 if (!seen) {
468 exitval = 1;
469 warnx("rule %lu does not exist", rulenum);
470 }
471 }
472 if (exitval != 0)
473 exit(exitval);
474 }
475}
476
477static void
478show_usage(const char *fmt, ...)
479{
480 if (fmt) {
481 char buf[100];
482 va_list args;
483
484 va_start(args, fmt);
485 vsnprintf(buf, sizeof(buf), fmt, args);
486 va_end(args);
487 warnx("error: %s", buf);
488 }
489 fprintf(stderr, "usage: ip6fw [options]\n"
490" flush\n"
491" add [number] rule\n"
492" delete number ...\n"
493" list [number ...]\n"
494" show [number ...]\n"
495" zero [number ...]\n"
496" rule: action proto src dst extras...\n"
497" action:\n"
498" {allow|permit|accept|pass|deny|drop|reject|unreach code|\n"
499" reset|count|skipto num} [log]\n"
500" proto: {ipv6|tcp|udp|ipv6-icmp|<number>}\n"
501" src: from [not] {any|ipv6[/prefixlen]} [{port|port-port},[port],...]\n"
502" dst: to [not] {any|ipv6[/prefixlen]} [{port|port-port},[port],...]\n"
503" extras:\n"
504" fragment (may not be used with ports or tcpflags)\n"
505" in\n"
506" out\n"
507" {xmit|recv|via} {iface|ipv6|any}\n"
508" {established|setup}\n"
509" tcpflags [!]{syn|fin|rst|ack|psh|urg},...\n"
510" ipv6options [!]{hopopt|route|frag|esp|ah|nonxt|opts},...\n"
511" icmptypes {type[,type]}...\n");
512
513 exit(1);
514}
515
516static int
517lookup_host (host, addr, family)
518 char *host;
519 u_char *addr;
520{
521 struct hostent *he = gethostbyname2(host, family);
522
523 if (!he)
524 return(-1);
525
526 memcpy(addr, he->h_addr_list[0], he->h_length);
527
528 return(0);
529}
530
531void
532fill_ip6(ipno, mask, acp, avp)
533 struct in6_addr *ipno, *mask;
534 int *acp;
535 char ***avp;
536{
537 int ac = *acp;
538 char **av = *avp;
539 char *p = 0, md = 0;
540 int i;
541
542 if (ac && !strncmp(*av,"any",strlen(*av))) {
543 *ipno = *mask = in6addr_any; av++; ac--;
544 } else {
545 p = strchr(*av, '/');
546 if (p) {
547 md = *p;
548 *p++ = '\0';
549 }
550
551 if (lookup_host(*av, ipno, AF_INET6) != 0)
552 show_usage("hostname ``%s'' unknown", *av);
553 switch (md) {
554 case '/':
555 if (atoi(p) == 0) {
556 *mask = in6addr_any;
557 } else if (atoi(p) > 128) {
558 show_usage("bad width ``%s''", p);
559 } else {
560 *mask = *(plen2mask(atoi(p)));
561 }
562 break;
563 default:
564 *mask = *(plen2mask(128));
565 break;
566 }
567 for (i = 0; i < sizeof(*ipno); i++)
568 ipno->s6_addr[i] &= mask->s6_addr[i];
569 av++;
570 ac--;
571 }
572 *acp = ac;
573 *avp = av;
574}
575
576static void
577fill_reject_code6(u_short *codep, char *str)
578{
579 struct icmpcode *ic;
580 u_long val;
581 char *s;
582
583 val = strtoul(str, &s, 0);
584 if (s != str && *s == '\0' && val < 0x100) {
585 *codep = val;
586 return;
587 }
588 for (ic = icmp6codes; ic->str; ic++)
589 if (!strcasecmp(str, ic->str)) {
590 *codep = ic->code;
591 return;
592 }
593 show_usage("unknown ICMP6 unreachable code ``%s''", str);
594}
595
596static void
597add_port(cnt, ptr, off, port)
598 u_short *cnt, *ptr, off, port;
599{
600 if (off + *cnt >= IPV6_FW_MAX_PORTS)
601 errx(1, "too many ports (max is %d)", IPV6_FW_MAX_PORTS);
602 ptr[off+*cnt] = port;
603 (*cnt)++;
604}
605
606static int
607lookup_port(const char *arg, int test, int nodash)
608{
609 int val;
610 char *earg, buf[32];
611 struct servent *s;
612
613 snprintf(buf, sizeof(buf), "%s", arg);
614 buf[strcspn(arg, nodash ? "-," : ",")] = 0;
615 val = (int) strtoul(buf, &earg, 0);
616 if (!*buf || *earg) {
617 setservent(1);
618 if ((s = getservbyname(buf, NULL))) {
619 val = htons(s->s_port);
620 } else {
621 if (!test) {
622 errx(1, "unknown port ``%s''", arg);
623 }
624 val = -1;
625 }
626 } else {
627 if (val < 0 || val > 0xffff) {
628 if (!test) {
629 errx(1, "port ``%s'' out of range", arg);
630 }
631 val = -1;
632 }
633 }
634 return(val);
635}
636
637int
638fill_port(cnt, ptr, off, arg)
639 u_short *cnt, *ptr, off;
640 char *arg;
641{
642 char *s;
643 int initial_range = 0;
644
645 s = arg + strcspn(arg, "-,"); /* first port name can't have a dash */
646 if (*s == '-') {
647 *s++ = '\0';
648 if (strchr(arg, ','))
649 errx(1, "port range must be first in list");
650 add_port(cnt, ptr, off, *arg ? lookup_port(arg, 0, 0) : 0x0000);
651 arg = s;
652 s = strchr(arg,',');
653 if (s)
654 *s++ = '\0';
655 add_port(cnt, ptr, off, *arg ? lookup_port(arg, 0, 0) : 0xffff);
656 arg = s;
657 initial_range = 1;
658 }
659 while (arg != NULL) {
660 s = strchr(arg,',');
661 if (s)
662 *s++ = '\0';
663 add_port(cnt, ptr, off, lookup_port(arg, 0, 0));
664 arg = s;
665 }
666 return initial_range;
667}
668
669void
670fill_tcpflag(set, reset, vp)
671 u_char *set, *reset;
672 char **vp;
673{
674 char *p = *vp,*q;
675 u_char *d;
676
677 while (p && *p) {
678 struct tpcflags {
679 char * name;
680 u_char value;
681 } flags[] = {
682 { "syn", IPV6_FW_TCPF_SYN },
683 { "fin", IPV6_FW_TCPF_FIN },
684 { "ack", IPV6_FW_TCPF_ACK },
685 { "psh", IPV6_FW_TCPF_PSH },
686 { "rst", IPV6_FW_TCPF_RST },
687 { "urg", IPV6_FW_TCPF_URG }
688 };
689 int i;
690
691 if (*p == '!') {
692 p++;
693 d = reset;
694 } else {
695 d = set;
696 }
697 q = strchr(p, ',');
698 if (q)
699 *q++ = '\0';
700 for (i = 0; i < sizeof(flags) / sizeof(flags[0]); ++i)
701 if (!strncmp(p, flags[i].name, strlen(p))) {
702 *d |= flags[i].value;
703 break;
704 }
705 if (i == sizeof(flags) / sizeof(flags[0]))
706 show_usage("invalid tcp flag ``%s''", p);
707 p = q;
708 }
709}
710
711static void
712fill_ip6opt(u_char *set, u_char *reset, char **vp)
713{
714 char *p = *vp,*q;
715 u_char *d;
716
717 while (p && *p) {
718 if (*p == '!') {
719 p++;
720 d = reset;
721 } else {
722 d = set;
723 }
724 q = strchr(p, ',');
725 if (q)
726 *q++ = '\0';
727 if (!strncmp(p,"hopopt",strlen(p))) *d |= IPV6_FW_IP6OPT_HOPOPT;
728 if (!strncmp(p,"route",strlen(p))) *d |= IPV6_FW_IP6OPT_ROUTE;
729 if (!strncmp(p,"frag",strlen(p))) *d |= IPV6_FW_IP6OPT_FRAG;
730 if (!strncmp(p,"esp",strlen(p))) *d |= IPV6_FW_IP6OPT_ESP;
731 if (!strncmp(p,"ah",strlen(p))) *d |= IPV6_FW_IP6OPT_AH;
732 if (!strncmp(p,"nonxt",strlen(p))) *d |= IPV6_FW_IP6OPT_NONXT;
733 if (!strncmp(p,"opts",strlen(p))) *d |= IPV6_FW_IP6OPT_OPTS;
734 p = q;
735 }
736}
737
738void
739fill_icmptypes(types, vp, fw_flg)
740 u_long *types;
741 char **vp;
742 u_short *fw_flg;
743{
744 char *c = *vp;
745
746 while (*c)
747 {
748 unsigned long icmptype;
749
750 if ( *c == ',' )
751 ++c;
752
753 icmptype = strtoul(c, &c, 0);
754
755 if ( *c != ',' && *c != '\0' )
756 show_usage("invalid ICMP6 type");
757
758 if (icmptype >= IPV6_FW_ICMPTYPES_DIM * sizeof(unsigned) * 8)
759 show_usage("ICMP6 type out of range");
760
761 types[icmptype / (sizeof(unsigned) * 8)] |=
762 1 << (icmptype % (sizeof(unsigned) * 8));
763 *fw_flg |= IPV6_FW_F_ICMPBIT;
764 }
765}
766
767void
768delete(ac,av)
769 int ac;
770 char **av;
771{
772 struct ip6_fw rule;
773 int i;
774 int exitval = 0;
775
776 memset(&rule, 0, sizeof rule);
777 rule.version = IPV6_FW_CURRENT_API_VERSION;
778
779 av++; ac--;
780
781 /* Rule number */
782 while (ac && isdigit(**av)) {
783 rule.fw_number = atoi(*av); av++; ac--;
784 i = setsockopt(s, IPPROTO_IPV6, IPV6_FW_DEL, &rule, sizeof rule);
785 if (i) {
786 exitval = 1;
787 warn("rule %u: setsockopt(%s)", rule.fw_number, "IPV6_FW_DEL");
788 }
789 }
790 if (exitval != 0)
791 exit(exitval);
792}
793
794static void
795verify_interface(union ip6_fw_if *ifu)
796{
797 struct ifreq ifr;
798
799 /*
800 * If a unit was specified, check for that exact interface.
801 * If a wildcard was specified, check for unit 0.
802 */
803 snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d",
804 ifu->fu_via_if.name,
805 ifu->fu_via_if.unit == -1 ? 0 : ifu->fu_via_if.unit);
806
807 if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0)
808 warnx("warning: interface ``%s'' does not exist", ifr.ifr_name);
809}
810
811static void
812fill_iface(char *which, union ip6_fw_if *ifu, int *byname, int ac, char *arg)
813{
814 if (!ac)
815 show_usage("missing argument for ``%s''", which);
816
817 /* Parse the interface or address */
818 if (!strcmp(arg, "any")) {
819 ifu->fu_via_ip6 = in6addr_any;
820 *byname = 0;
821 } else if (!isdigit(*arg)) {
822 char *q;
823
824 *byname = 1;
825 strncpy(ifu->fu_via_if.name, arg, sizeof(ifu->fu_via_if.name));
826 ifu->fu_via_if.name[sizeof(ifu->fu_via_if.name) - 1] = '\0';
827 for (q = ifu->fu_via_if.name;
828 *q && !isdigit(*q) && *q != '*'; q++)
829 continue;
830 ifu->fu_via_if.unit = (*q == '*') ? -1 : atoi(q);
831 *q = '\0';
832 verify_interface(ifu);
833 } else if (inet_pton(AF_INET6, arg, &ifu->fu_via_ip6) != 1) {
834 show_usage("bad ip6 address ``%s''", arg);
835 } else
836 *byname = 0;
837}
838
839static void
840add(ac,av)
841 int ac;
842 char **av;
843{
844 struct ip6_fw rule;
845 int i;
846 u_char proto;
847 struct protoent *pe;
848 int saw_xmrc = 0, saw_via = 0;
849
850 memset(&rule, 0, sizeof rule);
851 rule.version = IPV6_FW_CURRENT_API_VERSION;
852
853 av++; ac--;
854
855 /* Rule number */
856 if (ac && isdigit(**av)) {
857 rule.fw_number = atoi(*av); av++; ac--;
858 }
859
860 /* Action */
861 if (ac == 0)
862 show_usage("missing action");
863 if (!strncmp(*av,"accept",strlen(*av))
864 || !strncmp(*av,"pass",strlen(*av))
865 || !strncmp(*av,"allow",strlen(*av))
866 || !strncmp(*av,"permit",strlen(*av))) {
867 rule.fw_flg |= IPV6_FW_F_ACCEPT; av++; ac--;
868 } else if (!strncmp(*av,"count",strlen(*av))) {
869 rule.fw_flg |= IPV6_FW_F_COUNT; av++; ac--;
870 }
871#if 0
872 else if (!strncmp(*av,"divert",strlen(*av))) {
873 rule.fw_flg |= IPV6_FW_F_DIVERT; av++; ac--;
874 if (!ac)
875 show_usage("missing divert port");
876 rule.fw_divert_port = strtoul(*av, NULL, 0); av++; ac--;
877 if (rule.fw_divert_port == 0) {
878 struct servent *s;
879 setservent(1);
880 s = getservbyname(av[-1], "divert");
881 if (s != NULL)
882 rule.fw_divert_port = ntohs(s->s_port);
883 else
884 show_usage("illegal divert port");
885 }
886 } else if (!strncmp(*av,"tee",strlen(*av))) {
887 rule.fw_flg |= IPV6_FW_F_TEE; av++; ac--;
888 if (!ac)
889 show_usage("missing divert port");
890 rule.fw_divert_port = strtoul(*av, NULL, 0); av++; ac--;
891 if (rule.fw_divert_port == 0) {
892 struct servent *s;
893 setservent(1);
894 s = getservbyname(av[-1], "divert");
895 if (s != NULL)
896 rule.fw_divert_port = ntohs(s->s_port);
897 else
898 show_usage("illegal divert port");
899 }
900 }
901#endif
902 else if (!strncmp(*av,"skipto",strlen(*av))) {
903 rule.fw_flg |= IPV6_FW_F_SKIPTO; av++; ac--;
904 if (!ac)
905 show_usage("missing skipto rule number");
906 rule.fw_skipto_rule = strtoul(*av, NULL, 0); av++; ac--;
907 } else if ((!strncmp(*av,"deny",strlen(*av))
908 || !strncmp(*av,"drop",strlen(*av)))) {
909 rule.fw_flg |= IPV6_FW_F_DENY; av++; ac--;
910 } else if (!strncmp(*av,"reject",strlen(*av))) {
911 rule.fw_flg |= IPV6_FW_F_REJECT; av++; ac--;
912 rule.fw_reject_code = ICMP6_DST_UNREACH_NOROUTE;
913 } else if (!strncmp(*av,"reset",strlen(*av))) {
914 rule.fw_flg |= IPV6_FW_F_REJECT; av++; ac--;
915 rule.fw_reject_code = IPV6_FW_REJECT_RST; /* check TCP later */
916 } else if (!strncmp(*av,"unreach",strlen(*av))) {
917 rule.fw_flg |= IPV6_FW_F_REJECT; av++; ac--;
918 fill_reject_code6(&rule.fw_reject_code, *av); av++; ac--;
919 } else {
920 show_usage("invalid action ``%s''", *av);
921 }
922
923 /* [log] */
924 if (ac && !strncmp(*av,"log",strlen(*av))) {
925 rule.fw_flg |= IPV6_FW_F_PRN; av++; ac--;
926 }
927
928 /* protocol */
929 if (ac == 0)
930 show_usage("missing protocol");
931 if ((proto = atoi(*av)) > 0) {
932 rule.fw_prot = proto; av++; ac--;
933 } else if (!strncmp(*av,"all",strlen(*av))) {
934 rule.fw_prot = IPPROTO_IPV6; av++; ac--;
935 } else if ((pe = getprotobyname(*av)) != NULL) {
936 rule.fw_prot = pe->p_proto; av++; ac--;
937 } else {
938 show_usage("invalid protocol ``%s''", *av);
939 }
940
941 if (rule.fw_prot != IPPROTO_TCP
942 && (rule.fw_flg & IPV6_FW_F_COMMAND) == IPV6_FW_F_REJECT
943 && rule.fw_reject_code == IPV6_FW_REJECT_RST)
944 show_usage("``reset'' is only valid for tcp packets");
945
946 /* from */
947 if (ac && !strncmp(*av,"from",strlen(*av))) { av++; ac--; }
948 else
949 show_usage("missing ``from''");
950
951 if (ac && !strncmp(*av,"not",strlen(*av))) {
952 rule.fw_flg |= IPV6_FW_F_INVSRC;
953 av++; ac--;
954 }
955 if (!ac)
956 show_usage("missing arguments");
957
958 fill_ip6(&rule.fw_src, &rule.fw_smsk, &ac, &av);
959
960 if (ac && (isdigit(**av) || lookup_port(*av, 1, 1) >= 0)) {
961 u_short nports = 0;
962
963 if (fill_port(&nports, rule.fw_pts, 0, *av))
964 rule.fw_flg |= IPV6_FW_F_SRNG;
965 IPV6_FW_SETNSRCP(&rule, nports);
966 av++; ac--;
967 }
968
969 /* to */
970 if (ac && !strncmp(*av,"to",strlen(*av))) { av++; ac--; }
971 else
972 show_usage("missing ``to''");
973
974 if (ac && !strncmp(*av,"not",strlen(*av))) {
975 rule.fw_flg |= IPV6_FW_F_INVDST;
976 av++; ac--;
977 }
978 if (!ac)
979 show_usage("missing arguments");
980
981 fill_ip6(&rule.fw_dst, &rule.fw_dmsk, &ac, &av);
982
983 if (ac && (isdigit(**av) || lookup_port(*av, 1, 1) >= 0)) {
984 u_short nports = 0;
985
986 if (fill_port(&nports,
987 rule.fw_pts, IPV6_FW_GETNSRCP(&rule), *av))
988 rule.fw_flg |= IPV6_FW_F_DRNG;
989 IPV6_FW_SETNDSTP(&rule, nports);
990 av++; ac--;
991 }
992
993 if ((rule.fw_prot != IPPROTO_TCP) && (rule.fw_prot != IPPROTO_UDP)
994 && (IPV6_FW_GETNSRCP(&rule) || IPV6_FW_GETNDSTP(&rule))) {
995 show_usage("only TCP and UDP protocols are valid"
996 " with port specifications");
997 }
998
999 while (ac) {
1000 if (!strncmp(*av,"in",strlen(*av))) {
1001 rule.fw_flg |= IPV6_FW_F_IN;
1002 av++; ac--; continue;
1003 }
1004 if (!strncmp(*av,"out",strlen(*av))) {
1005 rule.fw_flg |= IPV6_FW_F_OUT;
1006 av++; ac--; continue;
1007 }
1008 if (ac && !strncmp(*av,"xmit",strlen(*av))) {
1009 union ip6_fw_if ifu;
1010 int byname;
1011
1012 if (saw_via) {
1013badviacombo:
1014 show_usage("``via'' is incompatible"
1015 " with ``xmit'' and ``recv''");
1016 }
1017 saw_xmrc = 1;
1018 av++; ac--;
1019 fill_iface("xmit", &ifu, &byname, ac, *av);
1020 rule.fw_out_if = ifu;
1021 rule.fw_flg |= IPV6_FW_F_OIFACE;
1022 if (byname)
1023 rule.fw_flg |= IPV6_FW_F_OIFNAME;
1024 av++; ac--; continue;
1025 }
1026 if (ac && !strncmp(*av,"recv",strlen(*av))) {
1027 union ip6_fw_if ifu;
1028 int byname;
1029
1030 if (saw_via)
1031 goto badviacombo;
1032 saw_xmrc = 1;
1033 av++; ac--;
1034 fill_iface("recv", &ifu, &byname, ac, *av);
1035 rule.fw_in_if = ifu;
1036 rule.fw_flg |= IPV6_FW_F_IIFACE;
1037 if (byname)
1038 rule.fw_flg |= IPV6_FW_F_IIFNAME;
1039 av++; ac--; continue;
1040 }
1041 if (ac && !strncmp(*av,"via",strlen(*av))) {
1042 union ip6_fw_if ifu;
1043 int byname = 0;
1044
1045 if (saw_xmrc)
1046 goto badviacombo;
1047 saw_via = 1;
1048 av++; ac--;
1049 fill_iface("via", &ifu, &byname, ac, *av);
1050 rule.fw_out_if = rule.fw_in_if = ifu;
1051 if (byname)
1052 rule.fw_flg |=
1053 (IPV6_FW_F_IIFNAME | IPV6_FW_F_OIFNAME);
1054 av++; ac--; continue;
1055 }
1056 if (!strncmp(*av,"fragment",strlen(*av))) {
1057 rule.fw_flg |= IPV6_FW_F_FRAG;
1058 av++; ac--; continue;
1059 }
1060 if (!strncmp(*av,"ipv6options",strlen(*av))) {
1061 av++; ac--;
1062 if (!ac)
1063 show_usage("missing argument"
1064 " for ``ipv6options''");
1065 fill_ip6opt(&rule.fw_ip6opt, &rule.fw_ip6nopt, av);
1066 av++; ac--; continue;
1067 }
1068 if (rule.fw_prot == IPPROTO_TCP) {
1069 if (!strncmp(*av,"established",strlen(*av))) {
1070 rule.fw_ipflg |= IPV6_FW_IF_TCPEST;
1071 av++; ac--; continue;
1072 }
1073 if (!strncmp(*av,"setup",strlen(*av))) {
1074 rule.fw_tcpf |= IPV6_FW_TCPF_SYN;
1075 rule.fw_tcpnf |= IPV6_FW_TCPF_ACK;
1076 av++; ac--; continue;
1077 }
1078 if (!strncmp(*av,"tcpflags",strlen(*av))) {
1079 av++; ac--;
1080 if (!ac)
1081 show_usage("missing argument"
1082 " for ``tcpflags''");
1083 fill_tcpflag(&rule.fw_tcpf, &rule.fw_tcpnf, av);
1084 av++; ac--; continue;
1085 }
1086 }
1087 if (rule.fw_prot == IPPROTO_ICMPV6) {
1088 if (!strncmp(*av,"icmptypes",strlen(*av))) {
1089 av++; ac--;
1090 if (!ac)
1091 show_usage("missing argument"
1092 " for ``icmptypes''");
1093 fill_icmptypes(rule.fw_icmp6types,
1094 av, &rule.fw_flg);
1095 av++; ac--; continue;
1096 }
1097 }
1098 show_usage("unknown argument ``%s''", *av);
1099 }
1100
1101 /* No direction specified -> do both directions */
1102 if (!(rule.fw_flg & (IPV6_FW_F_OUT|IPV6_FW_F_IN)))
1103 rule.fw_flg |= (IPV6_FW_F_OUT|IPV6_FW_F_IN);
1104
1105 /* Sanity check interface check, but handle "via" case separately */
1106 if (saw_via) {
1107 if (rule.fw_flg & IPV6_FW_F_IN)
1108 rule.fw_flg |= IPV6_FW_F_IIFACE;
1109 if (rule.fw_flg & IPV6_FW_F_OUT)
1110 rule.fw_flg |= IPV6_FW_F_OIFACE;
1111 } else if ((rule.fw_flg & IPV6_FW_F_OIFACE) && (rule.fw_flg & IPV6_FW_F_IN))
1112 show_usage("can't check xmit interface of incoming packets");
1113
1114 /* frag may not be used in conjunction with ports or TCP flags */
1115 if (rule.fw_flg & IPV6_FW_F_FRAG) {
1116 if (rule.fw_tcpf || rule.fw_tcpnf)
1117 show_usage("can't mix 'frag' and tcpflags");
1118
1119 if (rule.fw_nports)
1120 show_usage("can't mix 'frag' and port specifications");
1121 }
1122
1123 if (!do_quiet)
1124 show_ip6fw(&rule);
1125 i = setsockopt(s, IPPROTO_IPV6, IPV6_FW_ADD, &rule, sizeof rule);
1126 if (i)
1127 err(EX_UNAVAILABLE, "setsockopt(%s)", "IPV6_FW_ADD");
1128}
1129
1130static void
1131zero (ac, av)
1132 int ac;
1133 char **av;
1134{
1135 struct ip6_fw rule;
1136
1137 av++; ac--;
1138 memset(&rule, 0, sizeof rule);
1139 rule.version = IPV6_FW_CURRENT_API_VERSION;
1140
1141 if (!ac) {
1142 /* clear all entries */
1143 if (setsockopt(s, IPPROTO_IPV6, IPV6_FW_ZERO, &rule, sizeof rule) < 0)
1144 err(EX_UNAVAILABLE, "setsockopt(%s)", "IPV6_FW_ZERO");
1145 if (!do_quiet)
1146 printf("Accounting cleared.\n");
1147 } else {
1148 int failed = 0;
1149
1150 while (ac) {
1151 /* Rule number */
1152 if (isdigit(**av)) {
1153 rule.fw_number = atoi(*av); av++; ac--;
1154 if (setsockopt(s, IPPROTO_IPV6,
1155 IPV6_FW_ZERO, &rule, sizeof rule)) {
1156 warn("rule %u: setsockopt(%s)", rule.fw_number,
1157 "IPV6_FW_ZERO");
1158 failed = 1;
1159 }
1160 else if (!do_quiet)
1161 printf("Entry %d cleared\n",
1162 rule.fw_number);
1163 } else
1164 show_usage("invalid rule number ``%s''", *av);
1165 }
1166 if (failed != 0)
1167 exit(failed);
1168 }
1169}
1170
1171int
1172ip6fw_main(ac,av)
1173 int ac;
1174 char **av;
1175{
1176 int ch;
1177 extern int optind;
1178
1179 /* init optind to 1 */
1180 optind = 1;
1181
1182 if ( ac == 1 ) {
1183 show_usage(NULL);
1184 }
1185
1186 /* Set the force flag for non-interactive processes */
1187 do_force = !isatty(STDIN_FILENO);
1188
1189 while ((ch = getopt(ac, av ,"afqtN")) != -1)
1190 switch(ch) {
1191 case 'a':
1192 do_acct=1;
1193 break;
1194 case 'f':
1195 do_force=1;
1196 break;
1197 case 'q':
1198 do_quiet=1;
1199 break;
1200 case 't':
1201 do_time=1;
1202 break;
1203 case 'N':
1204 do_resolv=1;
1205 break;
1206 default:
1207 show_usage(NULL);
1208 }
1209
1210 ac -= optind;
1211 if (*(av+=optind)==NULL) {
1212 show_usage("Bad arguments");
1213 }
1214
1215 if (!strncmp(*av, "add", strlen(*av))) {
1216 add(ac,av);
1217 } else if (!strncmp(*av, "delete", strlen(*av))) {
1218 delete(ac,av);
1219 } else if (!strncmp(*av, "flush", strlen(*av))) {
1220 int do_flush = 0;
1221
1222 if ( do_force || do_quiet )
1223 do_flush = 1;
1224 else {
1225 int c;
1226
1227 /* Ask the user */
1228 printf("Are you sure? [yn] ");
1229 do {
1230 fflush(stdout);
1231 c = toupper(getc(stdin));
1232 while (c != '\n' && getc(stdin) != '\n')
1233 if (feof(stdin))
1234 return (0);
1235 } while (c != 'Y' && c != 'N');
1236 printf("\n");
1237 if (c == 'Y')
1238 do_flush = 1;
1239 }
1240 if ( do_flush ) {
1241 struct ip6_fw rule;
1242
1243 memset(&rule, 0, sizeof rule);
1244 rule.version = IPV6_FW_CURRENT_API_VERSION;
1245 if (setsockopt(s, IPPROTO_IPV6, IPV6_FW_FLUSH, &rule, sizeof rule) < 0)
1246 err(EX_UNAVAILABLE, "setsockopt(%s)", "IPV6_FW_FLUSH");
1247 if (!do_quiet)
1248 printf("Flushed all rules.\n");
1249 }
1250 } else if (!strncmp(*av, "zero", strlen(*av))) {
1251 zero(ac,av);
1252 } else if (!strncmp(*av, "print", strlen(*av))) {
1253 list(--ac,++av);
1254 } else if (!strncmp(*av, "list", strlen(*av))) {
1255 list(--ac,++av);
1256 } else if (!strncmp(*av, "show", strlen(*av))) {
1257 do_acct++;
1258 list(--ac,++av);
1259 } else {
1260 show_usage("Bad arguments");
1261 }
1262 return 0;
1263}
1264
1265int
1266main(ac, av)
1267 int ac;
1268 char **av;
1269{
1270#define MAX_ARGS 32
1271#define WHITESP " \t\f\v\n\r"
1272 char buf[BUFSIZ];
1273 char *a, *p, *args[MAX_ARGS], *cmd = NULL;
1274 char linename[10];
1275 int i, c, lineno, qflag, pflag, status;
1276 FILE *f = NULL;
1277 pid_t preproc = 0;
1278
1279 s = socket( AF_INET6, SOCK_RAW, IPPROTO_RAW );
1280 if ( s < 0 )
1281 err(EX_UNAVAILABLE, "socket");
1282
1283 setbuf(stdout,0);
1284
1285 /*
1286 * Only interpret the last command line argument as a file to
1287 * be preprocessed if it is specified as an absolute pathname.
1288 */
1289
1290 if (ac > 1 && av[ac - 1][0] == '/' && access(av[ac - 1], R_OK) == 0) {
1291 qflag = pflag = i = 0;
1292 lineno = 0;
1293
1294 while ((c = getopt(ac, av, "D:U:p:q")) != -1)
1295 switch(c) {
1296 case 'D':
1297 if (!pflag)
1298 errx(EX_USAGE, "-D requires -p");
1299 if (i > MAX_ARGS - 2)
1300 errx(EX_USAGE,
1301 "too many -D or -U options");
1302 args[i++] = "-D";
1303 args[i++] = optarg;
1304 break;
1305
1306 case 'U':
1307 if (!pflag)
1308 errx(EX_USAGE, "-U requires -p");
1309 if (i > MAX_ARGS - 2)
1310 errx(EX_USAGE,
1311 "too many -D or -U options");
1312 args[i++] = "-U";
1313 args[i++] = optarg;
1314 break;
1315
1316 case 'p':
1317 pflag = 1;
1318 cmd = optarg;
1319 args[0] = cmd;
1320 i = 1;
1321 break;
1322
1323 case 'q':
1324 qflag = 1;
1325 break;
1326
1327 default:
1328 show_usage(NULL);
1329 }
1330
1331 av += optind;
1332 ac -= optind;
1333 if (ac != 1)
1334 show_usage("extraneous filename arguments");
1335
1336 if ((f = fopen(av[0], "r")) == NULL)
1337 err(EX_UNAVAILABLE, "fopen: %s", av[0]);
1338
1339 if (pflag) {
1340 /* pipe through preprocessor (cpp or m4) */
1341 int pipedes[2];
1342
1343 args[i] = 0;
1344
1345 if (pipe(pipedes) == -1)
1346 err(EX_OSERR, "cannot create pipe");
1347
1348 switch((preproc = fork())) {
1349 case -1:
1350 err(EX_OSERR, "cannot fork");
1351
1352 case 0:
1353 /* child */
1354 if (dup2(fileno(f), 0) == -1 ||
1355 dup2(pipedes[1], 1) == -1)
1356 err(EX_OSERR, "dup2()");
1357 fclose(f);
1358 close(pipedes[1]);
1359 close(pipedes[0]);
1360 execvp(cmd, args);
1361 err(EX_OSERR, "execvp(%s) failed", cmd);
1362
1363 default:
1364 /* parent */
1365 fclose(f);
1366 close(pipedes[1]);
1367 if ((f = fdopen(pipedes[0], "r")) == NULL) {
1368 int savederrno = errno;
1369
1370 (void)kill(preproc, SIGTERM);
1371 errno = savederrno;
1372 err(EX_OSERR, "fdopen()");
1373 }
1374 }
1375 }
1376
1377 while (fgets(buf, BUFSIZ, f)) {
1378 lineno++;
1379 sprintf(linename, "Line %d", lineno);
1380 args[0] = linename;
1381
1382 if (*buf == '#')
1383 continue;
1384 if ((p = strchr(buf, '#')) != NULL)
1385 *p = '\0';
1386 i=1;
1387 if (qflag) args[i++]="-q";
1388 for (a = strtok(buf, WHITESP);
1389 a && i < MAX_ARGS; a = strtok(NULL, WHITESP), i++)
1390 args[i] = a;
1391 if (i == (qflag? 2: 1))
1392 continue;
1393 if (i == MAX_ARGS)
1394 errx(EX_USAGE, "%s: too many arguments", linename);
1395 args[i] = NULL;
1396
1397 ip6fw_main(i, args);
1398 }
1399 fclose(f);
1400 if (pflag) {
1401 if (waitpid(preproc, &status, 0) != -1) {
1402 if (WIFEXITED(status)) {
1403 if (WEXITSTATUS(status) != EX_OK)
1404 errx(EX_UNAVAILABLE,
1405 "preprocessor exited with status %d",
1406 WEXITSTATUS(status));
1407 } else if (WIFSIGNALED(status)) {
1408 errx(EX_UNAVAILABLE,
1409 "preprocessor exited with signal %d",
1410 WTERMSIG(status));
1411 }
1412 }
1413 }
1414 } else
1415 ip6fw_main(ac,av);
1416 return 0;
1417}