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 82int lineno = -1; 83 84int s; /* main RAW socket */ 85int do_resolv=0; /* Would try to resolv all */ 86int do_acct=0; /* Show packet/byte count */ 87int do_time=0; /* Show time stamps */ 88int do_quiet=0; /* Be quiet in add and flush */ 89int do_force=0; /* Don't ask for confirmation */ 90 91struct icmpcode { 92 int code; 93 char *str; 94}; 95 96static 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 105static char ntop_buf[INET6_ADDRSTRLEN]; 106 107static void show_usage(const char *fmt, ...); 108 109static int 110mask_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 135static int pl2m[9] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; 136 137struct 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 156void 157print_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 184static void 185print_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 202static void 203print_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 215static void 216show_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 440void 441list(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 506static void 507show_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 545static int 546lookup_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 560void 561fill_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 605static void 606fill_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 625static void 626add_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 635static int 636lookup_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 666int 667fill_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 698void 699fill_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 740static void 741fill_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 767void 768fill_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 796void 797delete(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 823static void 824verify_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 840static void 841fill_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 868static void 869add(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) { 1042badviacombo: 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 1159static void 1160zero (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 1200int 1201ip6fw_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 1294int 1295main(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} 1447