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