parse.y revision 1.161
1/* $OpenBSD: parse.y,v 1.161 2002/10/07 13:18:40 henning Exp $ */ 2 3/* 4 * Copyright (c) 2001 Markus Friedl. All rights reserved. 5 * Copyright (c) 2001 Daniel Hartmeier. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27%{ 28#include <sys/types.h> 29#include <sys/socket.h> 30#include <sys/ioctl.h> 31#include <net/if.h> 32#include <netinet/in.h> 33#include <netinet/in_systm.h> 34#include <netinet/ip.h> 35#include <netinet/ip_icmp.h> 36#include <netinet/icmp6.h> 37#include <net/pfvar.h> 38#include <arpa/inet.h> 39 40#include <stdio.h> 41#include <stdlib.h> 42#include <ifaddrs.h> 43#include <netdb.h> 44#include <stdarg.h> 45#include <errno.h> 46#include <string.h> 47#include <ctype.h> 48#include <err.h> 49#include <pwd.h> 50#include <grp.h> 51 52#include "pfctl_parser.h" 53 54static struct pfctl *pf = NULL; 55static FILE *fin = NULL; 56static int debug = 0; 57static int lineno = 1; 58static int errors = 0; 59static int rulestate = 0; 60static u_int16_t returnicmpdefault = (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT; 61static u_int16_t returnicmp6default = (ICMP6_DST_UNREACH << 8) 62 | ICMP6_DST_UNREACH_NOPORT; 63 64enum { 65 PFCTL_STATE_NONE = 0, 66 PFCTL_STATE_OPTION = 1, 67 PFCTL_STATE_SCRUB = 2, 68 PFCTL_STATE_NAT = 3, 69 PFCTL_STATE_FILTER = 4 70}; 71 72enum pfctl_iflookup_mode { 73 PFCTL_IFLOOKUP_HOST = 0, 74 PFCTL_IFLOOKUP_NET = 1, 75 PFCTL_IFLOOKUP_BCAST = 2 76}; 77 78struct node_if { 79 char ifname[IFNAMSIZ]; 80 u_int8_t not; 81 u_int ifa_flags; 82 struct node_if *next; 83 struct node_if *tail; 84}; 85 86struct node_proto { 87 u_int8_t proto; 88 struct node_proto *next; 89 struct node_proto *tail; 90}; 91 92struct node_host { 93 struct pf_addr_wrap addr; 94 struct pf_addr mask; 95 struct pf_addr bcast; 96 u_int8_t af; 97 u_int8_t not; 98 u_int8_t noroute; 99 u_int32_t ifindex; /* link-local IPv6 addrs */ 100 char *ifname; 101 u_int ifa_flags; 102 struct node_host *next; 103 struct node_host *tail; 104}; 105 106struct node_port { 107 u_int16_t port[2]; 108 u_int8_t op; 109 struct node_port *next; 110 struct node_port *tail; 111}; 112 113struct node_uid { 114 uid_t uid[2]; 115 u_int8_t op; 116 struct node_uid *next; 117 struct node_uid *tail; 118}; 119 120struct node_gid { 121 gid_t gid[2]; 122 u_int8_t op; 123 struct node_gid *next; 124 struct node_gid *tail; 125}; 126 127struct node_icmp { 128 u_int8_t code; 129 u_int8_t type; 130 u_int8_t proto; 131 struct node_icmp *next; 132 struct node_icmp *tail; 133}; 134 135enum { PF_STATE_OPT_MAX=0, PF_STATE_OPT_TIMEOUT=1 }; 136struct node_state_opt { 137 int type; 138 union { 139 u_int32_t max_states; 140 struct { 141 int number; 142 u_int32_t seconds; 143 } timeout; 144 } data; 145 struct node_state_opt *next; 146 struct node_state_opt *tail; 147}; 148 149struct peer { 150 struct node_host *host; 151 struct node_port *port; 152}; 153 154int yyerror(char *, ...); 155int rule_consistent(struct pf_rule *); 156int nat_consistent(struct pf_nat *); 157int rdr_consistent(struct pf_rdr *); 158int yyparse(void); 159void ipmask(struct pf_addr *, u_int8_t); 160void expand_rdr(struct pf_rdr *, struct node_if *, struct node_proto *, 161 struct node_host *, struct node_host *); 162void expand_nat(struct pf_nat *, struct node_if *, struct node_proto *, 163 struct node_host *, struct node_port *, 164 struct node_host *, struct node_port *); 165void expand_label_addr(const char *, char *, u_int8_t, struct node_host *); 166void expand_label_port(const char *, char *, struct node_port *); 167void expand_label_proto(const char *, char *, u_int8_t); 168void expand_label_nr(const char *, char *); 169void expand_label(char *, u_int8_t, struct node_host *, struct node_port *, 170 struct node_host *, struct node_port *, u_int8_t); 171void expand_rule(struct pf_rule *, struct node_if *, struct node_proto *, 172 struct node_host *, struct node_port *, struct node_host *, 173 struct node_port *, struct node_uid *, struct node_gid *, 174 struct node_icmp *); 175int check_rulestate(int); 176int kw_cmp(const void *, const void *); 177int lookup(char *); 178int lgetc(FILE *); 179int lungetc(int, FILE *); 180int findeol(void); 181int yylex(void); 182struct node_host *host(char *); 183int atoul(char *, u_long *); 184int getservice(char *); 185 186 187struct sym { 188 struct sym *next; 189 char *nam; 190 char *val; 191}; 192struct sym *symhead = NULL; 193 194int symset(const char *, const char *); 195char * symget(const char *); 196 197void ifa_load(void); 198struct node_host *ifa_exists(char *); 199struct node_host *ifa_lookup(char *, enum pfctl_iflookup_mode); 200struct node_host *ifa_pick_ip(struct node_host *, u_int8_t); 201u_int16_t parseicmpspec(char *, u_int8_t); 202 203typedef struct { 204 union { 205 u_int32_t number; 206 int i; 207 char *string; 208 struct { 209 u_int8_t b1; 210 u_int8_t b2; 211 u_int16_t w; 212 u_int16_t w2; 213 } b; 214 struct range { 215 int a; 216 int b; 217 int t; 218 } range; 219 struct node_if *interface; 220 struct node_proto *proto; 221 struct node_icmp *icmp; 222 struct node_host *host; 223 struct node_port *port; 224 struct node_uid *uid; 225 struct node_gid *gid; 226 struct node_state_opt *state_opt; 227 struct peer peer; 228 struct { 229 struct peer src, dst; 230 } fromto; 231 struct { 232 char *string; 233 struct pf_addr *addr; 234 u_int8_t rt; 235 u_int8_t af; 236 } route; 237 struct redirection { 238 struct node_host *address; 239 struct range rport; 240 } *redirection; 241 struct { 242 int action; 243 struct node_state_opt *options; 244 } keep_state; 245 struct { 246 u_int8_t log; 247 u_int8_t quick; 248 } logquick; 249 } v; 250 int lineno; 251} YYSTYPE; 252 253%} 254 255%token PASS BLOCK SCRUB RETURN IN OUT LOG LOGALL QUICK ON FROM TO FLAGS 256%token RETURNRST RETURNICMP RETURNICMP6 PROTO INET INET6 ALL ANY ICMPTYPE 257%token ICMP6TYPE CODE KEEP MODULATE STATE PORT RDR NAT BINAT ARROW NODF 258%token MINTTL ERROR ALLOWOPTS FASTROUTE ROUTETO DUPTO REPLYTO NO LABEL 259%token NOROUTE FRAGMENT USER GROUP MAXMSS MAXIMUM TTL TOS 260%token FRAGNORM FRAGDROP FRAGCROP 261%token SET OPTIMIZATION TIMEOUT LIMIT LOGINTERFACE 262%token ANTISPOOF FOR 263%token <v.string> STRING 264%token <v.i> PORTUNARY PORTBINARY 265%type <v.interface> interface if_list if_item_not if_item 266%type <v.number> number port icmptype icmp6type minttl uid gid maxmss 267%type <v.number> tos 268%type <v.i> no dir log af nodf allowopts fragment fragcache 269%type <v.b> action flag flags blockspec 270%type <v.range> dport rport 271%type <v.proto> proto proto_list proto_item 272%type <v.icmp> icmpspec icmp_list icmp6_list icmp_item icmp6_item 273%type <v.fromto> fromto 274%type <v.peer> ipportspec 275%type <v.host> ipspec xhost host address host_list 276%type <v.port> portspec port_list port_item 277%type <v.uid> uids uid_list uid_item 278%type <v.gid> gids gid_list gid_item 279%type <v.route> route 280%type <v.redirection> redirection 281%type <v.string> label string 282%type <v.keep_state> keep 283%type <v.state_opt> state_opt_spec state_opt_list state_opt_item 284%type <v.logquick> logquick 285%type <v.interface> antispoof_ifspc antispoof_iflst 286%% 287 288ruleset : /* empty */ 289 | ruleset '\n' 290 | ruleset option '\n' 291 | ruleset scrubrule '\n' 292 | ruleset natrule '\n' 293 | ruleset binatrule '\n' 294 | ruleset rdrrule '\n' 295 | ruleset pfrule '\n' 296 | ruleset varset '\n' 297 | ruleset antispoof '\n' 298 | ruleset error '\n' { errors++; } 299 ; 300 301option : SET OPTIMIZATION STRING { 302 if (pf->opts & PF_OPT_VERBOSE) 303 printf("set optimization %s\n", $3); 304 if (check_rulestate(PFCTL_STATE_OPTION)) 305 YYERROR; 306 if (pfctl_set_optimization(pf, $3) != 0) { 307 yyerror("unknown optimization %s", $3); 308 YYERROR; 309 } 310 } 311 | SET TIMEOUT timeout_spec 312 | SET TIMEOUT '{' timeout_list '}' 313 | SET LIMIT limit_spec 314 | SET LIMIT '{' limit_list '}' 315 | SET LOGINTERFACE STRING { 316 if (pf->opts & PF_OPT_VERBOSE) 317 printf("set loginterface %s\n", $3); 318 if (check_rulestate(PFCTL_STATE_OPTION)) 319 YYERROR; 320 if (pfctl_set_logif(pf, $3) != 0) { 321 yyerror("error setting loginterface %s", $3); 322 YYERROR; 323 } 324 } 325 ; 326 327string : string STRING { 328 if (asprintf(&$$, "%s %s", $1, $2) == -1) { 329 yyerror("malloc failed"); 330 YYERROR; 331 } 332 free($1); 333 free($2); 334 } 335 | STRING 336 ; 337 338varset : STRING PORTUNARY string { 339 if (pf->opts & PF_OPT_VERBOSE) 340 printf("%s = %s\n", $1, $3); 341 if (symset($1, $3) == -1) { 342 yyerror("cannot store variable %s", $1); 343 YYERROR; 344 } 345 } 346 ; 347 348scrubrule : SCRUB dir interface fromto nodf minttl maxmss fragcache 349 { 350 struct pf_rule r; 351 352 if (check_rulestate(PFCTL_STATE_SCRUB)) 353 YYERROR; 354 355 memset(&r, 0, sizeof(r)); 356 357 r.action = PF_SCRUB; 358 r.direction = $2; 359 360 if ($3) { 361 if ($3->not) { 362 yyerror("scrub rules don't support " 363 "'! <if>'"); 364 YYERROR; 365 } else if ($3->next) { 366 yyerror("scrub rules don't support " 367 "{} expansion"); 368 YYERROR; 369 } 370 memcpy(r.ifname, $3->ifname, 371 sizeof(r.ifname)); 372 free($3); 373 } 374 if ($5) 375 r.rule_flag |= PFRULE_NODF; 376 if ($6) 377 r.min_ttl = $6; 378 if ($7) 379 r.max_mss = $7; 380 if ($8) 381 r.rule_flag |= $8; 382 383 r.nr = pf->rule_nr++; 384 if (rule_consistent(&r) < 0) 385 yyerror("skipping scrub rule due to errors"); 386 else 387 pfctl_add_rule(pf, &r); 388 389 } 390 ; 391 392antispoof : ANTISPOOF logquick antispoof_ifspc af { 393 struct pf_rule r; 394 struct node_host *h = NULL; 395 struct node_if *i, *j; 396 397 if (check_rulestate(PFCTL_STATE_FILTER)) 398 YYERROR; 399 400 for (i = $3; i; i = i->next) { 401 memset(&r, 0, sizeof(r)); 402 403 r.action = PF_DROP; 404 r.direction = PF_IN; 405 r.log = $2.log; 406 r.quick = $2.quick; 407 r.af = $4; 408 409 j = calloc(1, sizeof(struct node_if)); 410 if (j == NULL) 411 errx(1, "antispoof: calloc"); 412 strlcpy(j->ifname, i->ifname, IFNAMSIZ); 413 j->not = 1; 414 h = ifa_lookup(j->ifname, PFCTL_IFLOOKUP_NET); 415 416 expand_rule(&r, j, NULL, h, NULL, NULL, NULL, 417 NULL, NULL, NULL); 418 419 if ((i->ifa_flags & IFF_LOOPBACK) == 0) { 420 memset(&r, 0, sizeof(r)); 421 422 r.action = PF_DROP; 423 r.direction = PF_IN; 424 r.log = $2.log; 425 r.quick = $2.quick; 426 r.af = $4; 427 428 h = ifa_lookup(i->ifname, 429 PFCTL_IFLOOKUP_HOST); 430 431 expand_rule(&r, NULL, NULL, h, NULL, 432 NULL, NULL, NULL, NULL, NULL); 433 } 434 } 435 } 436 ; 437 438antispoof_ifspc : FOR if_item { $$ = $2; } 439 | FOR '{' antispoof_iflst '}' { $$ = $3; } 440 ; 441 442antispoof_iflst : if_item { $$ = $1; } 443 | antispoof_iflst comma if_item { 444 $1->tail->next = $3; 445 $1->tail = $3; 446 $$ = $1; 447 } 448 ; 449 450pfrule : action dir logquick interface route af proto fromto 451 uids gids flags icmpspec tos keep fragment allowopts label 452 { 453 struct pf_rule r; 454 struct node_state_opt *o; 455 struct node_proto *proto; 456 457 if (check_rulestate(PFCTL_STATE_FILTER)) 458 YYERROR; 459 460 memset(&r, 0, sizeof(r)); 461 462 r.action = $1.b1; 463 switch ($1.b2) { 464 case PFRULE_RETURNRST: 465 r.rule_flag |= PFRULE_RETURNRST; 466 r.return_ttl = $1.w; 467 break; 468 case PFRULE_RETURNICMP: 469 r.rule_flag |= PFRULE_RETURNICMP; 470 r.return_icmp = $1.w; 471 r.return_icmp6 = $1.w2; 472 break; 473 case PFRULE_RETURN: 474 r.rule_flag |= PFRULE_RETURN; 475 r.return_icmp = $1.w; 476 r.return_icmp6 = $1.w2; 477 break; 478 } 479 r.direction = $2; 480 r.log = $3.log; 481 r.quick = $3.quick; 482 483 r.af = $6; 484 r.flags = $11.b1; 485 r.flagset = $11.b2; 486 487 if ($11.b1 || $11.b2) { 488 for (proto = $7; proto != NULL && 489 proto->proto != IPPROTO_TCP; 490 proto = proto->next) 491 ; /* nothing */ 492 if (proto == NULL && $7 != NULL) { 493 yyerror("flags only apply to tcp"); 494 YYERROR; 495 } 496 } 497 498 r.tos = $13; 499 r.keep_state = $14.action; 500 o = $14.options; 501 while (o) { 502 struct node_state_opt *p = o; 503 504 switch (o->type) { 505 case PF_STATE_OPT_MAX: 506 if (r.max_states) { 507 yyerror("state option 'max' " 508 "multiple definitions"); 509 YYERROR; 510 } 511 r.max_states = o->data.max_states; 512 break; 513 case PF_STATE_OPT_TIMEOUT: 514 if (r.timeout[o->data.timeout.number]) { 515 yyerror("state timeout %s " 516 "multiple definitions", 517 pf_timeouts[o->data. 518 timeout.number].name); 519 YYERROR; 520 } 521 r.timeout[o->data.timeout.number] = 522 o->data.timeout.seconds; 523 } 524 o = o->next; 525 free(p); 526 } 527 528 if ($15) 529 r.rule_flag |= PFRULE_FRAGMENT; 530 r.allow_opts = $16; 531 532 if ($5.rt) { 533 r.rt = $5.rt; 534 if ($5.string) { 535 strlcpy(r.rt_ifname, $5.string, 536 IFNAMSIZ); 537 if (ifa_exists(r.rt_ifname) == NULL) { 538 yyerror("unknown interface %s", 539 r.rt_ifname); 540 YYERROR; 541 } 542 free($5.string); 543 } 544 if ($5.addr) { 545 if (!r.af) 546 r.af = $5.af; 547 else if (r.af != $5.af) { 548 yyerror("address family" 549 " mismatch"); 550 YYERROR; 551 } 552 memcpy(&r.rt_addr, $5.addr, 553 sizeof(r.rt_addr)); 554 free($5.addr); 555 } 556 } 557 558 if ($17) { 559 if (strlen($17) >= PF_RULE_LABEL_SIZE) { 560 yyerror("rule label too long (max " 561 "%d chars)", PF_RULE_LABEL_SIZE-1); 562 YYERROR; 563 } 564 strlcpy(r.label, $17, sizeof(r.label)); 565 free($17); 566 } 567 568 expand_rule(&r, $4, $7, $8.src.host, $8.src.port, 569 $8.dst.host, $8.dst.port, $9, $10, $12); 570 } 571 ; 572 573action : PASS { $$.b1 = PF_PASS; $$.b2 = $$.w = 0; } 574 | BLOCK blockspec { $$ = $2; $$.b1 = PF_DROP; } 575 ; 576 577blockspec : /* empty */ { $$.b2 = 0; $$.w = 0; $$.w2 = 0; } 578 | RETURNRST { 579 $$.b2 = PFRULE_RETURNRST; 580 $$.w = 0; 581 $$.w2 = 0; 582 } 583 | RETURNRST '(' TTL number ')' { 584 $$.b2 = PFRULE_RETURNRST; 585 $$.w = $4; 586 $$.w2 = 0; 587 } 588 | RETURNICMP { 589 $$.b2 = PFRULE_RETURNICMP; 590 $$.w = returnicmpdefault; 591 $$.w2 = returnicmp6default; 592 } 593 | RETURNICMP6 { 594 $$.b2 = PFRULE_RETURNICMP; 595 $$.w = returnicmpdefault; 596 $$.w2 = returnicmp6default; 597 } 598 | RETURNICMP '(' STRING ')' { 599 $$.b2 = PFRULE_RETURNICMP; 600 if (!($$.w = parseicmpspec($3, AF_INET))) 601 YYERROR; 602 $$.w2 = returnicmp6default; 603 } 604 | RETURNICMP6 '(' STRING ')' { 605 $$.b2 = PFRULE_RETURNICMP; 606 $$.w = returnicmpdefault; 607 if (!($$.w2 = parseicmpspec($3, AF_INET6))) 608 YYERROR; 609 } 610 | RETURNICMP '(' STRING comma STRING ')' { 611 $$.b2 = PFRULE_RETURNICMP; 612 if (!($$.w = parseicmpspec($3, AF_INET))) 613 YYERROR; 614 if (!($$.w2 = parseicmpspec($5, AF_INET6))); 615 } 616 | RETURN { 617 $$.b2 = PFRULE_RETURN; 618 $$.w = returnicmpdefault; 619 $$.w2 = returnicmp6default; 620 } 621 ; 622 623fragcache : /* empty */ { $$ = 0; } 624 | fragment FRAGNORM { $$ = 0; /* default */ } 625 | fragment FRAGCROP { $$ = PFRULE_FRAGCROP; } 626 | fragment FRAGDROP { $$ = PFRULE_FRAGDROP; } 627 ; 628 629 630dir : IN { $$ = PF_IN; } 631 | OUT { $$ = PF_OUT; } 632 ; 633 634logquick : /* empty */ { $$.log = 0; $$.quick = 0; } 635 | log { $$.log = $1; $$.quick = 0; } 636 | QUICK { $$.log = 0; $$.quick = 1; } 637 | log QUICK { $$.log = $1; $$.quick = 1; } 638 | QUICK log { $$.log = $2; $$.quick = 1; } 639 ; 640 641log : LOG { $$ = 1; } 642 | LOGALL { $$ = 2; } 643 ; 644 645interface : /* empty */ { $$ = NULL; } 646 | ON if_item_not { $$ = $2; } 647 | ON '{' if_list '}' { $$ = $3; } 648 ; 649 650if_list : if_item_not { $$ = $1; } 651 | if_list comma if_item_not { 652 $1->tail->next = $3; 653 $1->tail = $3; 654 $$ = $1; 655 } 656 ; 657 658if_item_not : '!' if_item { $$ = $2; $$->not = 1; } 659 | if_item { $$ = $1; } 660 661if_item : STRING { 662 struct node_host *n; 663 664 if ((n = ifa_exists($1)) == NULL) { 665 yyerror("unknown interface %s", $1); 666 YYERROR; 667 } 668 $$ = malloc(sizeof(struct node_if)); 669 if ($$ == NULL) 670 err(1, "if_item: malloc"); 671 strlcpy($$->ifname, $1, IFNAMSIZ); 672 $$->ifa_flags = n->ifa_flags; 673 $$->not = 0; 674 $$->next = NULL; 675 $$->tail = $$; 676 } 677 ; 678 679af : /* empty */ { $$ = 0; } 680 | INET { $$ = AF_INET; } 681 | INET6 { $$ = AF_INET6; } 682 683proto : /* empty */ { $$ = NULL; } 684 | PROTO proto_item { $$ = $2; } 685 | PROTO '{' proto_list '}' { $$ = $3; } 686 ; 687 688proto_list : proto_item { $$ = $1; } 689 | proto_list comma proto_item { 690 $1->tail->next = $3; 691 $1->tail = $3; 692 $$ = $1; 693 } 694 ; 695 696proto_item : STRING { 697 struct protoent *p; 698 u_long ulval; 699 700 if (atoul($1, &ulval) == 0) 701 p = getprotobynumber(ulval); 702 else 703 p = getprotobyname($1); 704 705 if (p == NULL) { 706 yyerror("unknown protocol %s", $1); 707 YYERROR; 708 } 709 $$ = malloc(sizeof(struct node_proto)); 710 if ($$ == NULL) 711 err(1, "proto_item: malloc"); 712 $$->proto = p->p_proto; 713 $$->next = NULL; 714 $$->tail = $$; 715 } 716 ; 717 718fromto : ALL { 719 $$.src.host = NULL; 720 $$.src.port = NULL; 721 $$.dst.host = NULL; 722 $$.dst.port = NULL; 723 } 724 | FROM ipportspec TO ipportspec { 725 $$.src = $2; 726 $$.dst = $4; 727 } 728 ; 729 730ipportspec : ipspec { $$.host = $1; $$.port = NULL; } 731 | ipspec PORT portspec { 732 $$.host = $1; 733 $$.port = $3; 734 } 735 ; 736 737ipspec : ANY { $$ = NULL; } 738 | xhost { $$ = $1; } 739 | '{' host_list '}' { $$ = $2; } 740 ; 741 742host_list : xhost { $$ = $1; } 743 | host_list comma xhost { 744 /* $3 may be a list, so use its tail pointer */ 745 $1->tail->next = $3->tail; 746 $1->tail = $3->tail; 747 $$ = $1; 748 } 749 ; 750 751xhost : '!' host { 752 struct node_host *h; 753 for (h = $2; h; h = h->next) 754 h->not = 1; 755 $$ = $2; 756 } 757 | host { $$ = $1; } 758 | NOROUTE { 759 $$ = calloc(1, sizeof(struct node_host)); 760 if ($$ == NULL) 761 err(1, "xhost: calloc"); 762 $$->noroute = 1; 763 $$->next = NULL; 764 $$->tail = $$; 765 } 766 ; 767 768host : address 769 | address '/' number { 770 struct node_host *n; 771 for (n = $1; n; n = n->next) { 772 if ($1->af == AF_INET) { 773 if ($3 < 0 || $3 > 32) { 774 yyerror( 775 "illegal netmask value /%d", 776 $3); 777 YYERROR; 778 } 779 } else { 780 if ($3 < 0 || $3 > 128) { 781 yyerror( 782 "illegal netmask value /%d", 783 $3); 784 YYERROR; 785 } 786 } 787 ipmask(&n->mask, $3); 788 } 789 $$ = $1; 790 } 791 ; 792 793number: STRING 794 { 795 u_long ulval; 796 797 if (atoul($1, &ulval) == -1) { 798 yyerror("%s is not a number", $1); 799 YYERROR; 800 } else 801 $$ = ulval; 802 } 803 ; 804 805address : '(' STRING ')' { 806 $$ = calloc(1, sizeof(struct node_host)); 807 if ($$ == NULL) 808 err(1, "address: calloc"); 809 $$->af = 0; 810 ipmask(&$$->mask, 128); 811 $$->addr.addr_dyn = (struct pf_addr_dyn *)1; 812 strncpy($$->addr.addr.pfa.ifname, $2, 813 sizeof($$->addr.addr.pfa.ifname)); 814 } 815 | STRING { $$ = host($1); } 816 ; 817 818portspec : port_item { $$ = $1; } 819 | '{' port_list '}' { $$ = $2; } 820 ; 821 822port_list : port_item { $$ = $1; } 823 | port_list comma port_item { 824 $1->tail->next = $3; 825 $1->tail = $3; 826 $$ = $1; 827 } 828 ; 829 830port_item : port { 831 $$ = malloc(sizeof(struct node_port)); 832 if ($$ == NULL) 833 err(1, "port_item: malloc"); 834 $$->port[0] = $1; 835 $$->port[1] = $1; 836 $$->op = PF_OP_EQ; 837 $$->next = NULL; 838 $$->tail = $$; 839 } 840 | PORTUNARY port { 841 $$ = malloc(sizeof(struct node_port)); 842 if ($$ == NULL) 843 err(1, "port_item: malloc"); 844 $$->port[0] = $2; 845 $$->port[1] = $2; 846 $$->op = $1; 847 $$->next = NULL; 848 $$->tail = $$; 849 } 850 | port PORTBINARY port { 851 $$ = malloc(sizeof(struct node_port)); 852 if ($$ == NULL) 853 err(1, "port_item: malloc"); 854 $$->port[0] = $1; 855 $$->port[1] = $3; 856 $$->op = $2; 857 $$->next = NULL; 858 $$->tail = $$; 859 } 860 ; 861 862port : STRING { 863 struct servent *s = NULL; 864 u_long ulval; 865 866 if (atoul($1, &ulval) == 0) { 867 if (ulval < 0 || ulval > 65535) { 868 yyerror("illegal port value %d", ulval); 869 YYERROR; 870 } 871 $$ = htons(ulval); 872 } else { 873 s = getservbyname($1, "tcp"); 874 if (s == NULL) 875 s = getservbyname($1, "udp"); 876 if (s == NULL) { 877 yyerror("unknown port %s", $1); 878 YYERROR; 879 } 880 $$ = s->s_port; 881 } 882 } 883 ; 884 885uids : /* empty */ { $$ = NULL; } 886 | USER uid_item { $$ = $2; } 887 | USER '{' uid_list '}' { $$ = $3; } 888 ; 889 890uid_list : uid_item { $$ = $1; } 891 | uid_list comma uid_item { 892 $1->tail->next = $3; 893 $1->tail = $3; 894 $$ = $1; 895 } 896 ; 897 898uid_item : uid { 899 $$ = malloc(sizeof(struct node_uid)); 900 if ($$ == NULL) 901 err(1, "uid_item: malloc"); 902 $$->uid[0] = $1; 903 $$->uid[1] = $1; 904 $$->op = PF_OP_EQ; 905 $$->next = NULL; 906 $$->tail = $$; 907 } 908 | PORTUNARY uid { 909 if ($2 == UID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) { 910 yyerror("user unknown requires operator = or !="); 911 YYERROR; 912 } 913 $$ = malloc(sizeof(struct node_uid)); 914 if ($$ == NULL) 915 err(1, "uid_item: malloc"); 916 $$->uid[0] = $2; 917 $$->uid[1] = $2; 918 $$->op = $1; 919 $$->next = NULL; 920 $$->tail = $$; 921 } 922 | uid PORTBINARY uid { 923 if ($1 == UID_MAX || $3 == UID_MAX) { 924 yyerror("user unknown requires operator = or !="); 925 YYERROR; 926 } 927 $$ = malloc(sizeof(struct node_uid)); 928 if ($$ == NULL) 929 err(1, "uid_item: malloc"); 930 $$->uid[0] = $1; 931 $$->uid[1] = $3; 932 $$->op = $2; 933 $$->next = NULL; 934 $$->tail = $$; 935 } 936 ; 937 938uid : STRING { 939 u_long ulval; 940 941 if (atoul($1, &ulval) == -1) { 942 if (!strcmp($1, "unknown")) 943 $$ = UID_MAX; 944 else { 945 struct passwd *pw; 946 947 if ((pw = getpwnam($1)) == NULL) { 948 yyerror("unknown user %s", $1); 949 YYERROR; 950 } 951 $$ = pw->pw_uid; 952 } 953 } else { 954 if (ulval < 0 || ulval >= UID_MAX) { 955 yyerror("illegal uid value %ul", ulval); 956 YYERROR; 957 } 958 $$ = ulval; 959 } 960 } 961 ; 962 963gids : /* empty */ { $$ = NULL; } 964 | GROUP gid_item { $$ = $2; } 965 | GROUP '{' gid_list '}' { $$ = $3; } 966 ; 967 968gid_list : gid_item { $$ = $1; } 969 | gid_list comma gid_item { 970 $1->tail->next = $3; 971 $1->tail = $3; 972 $$ = $1; 973 } 974 ; 975 976gid_item : gid { 977 $$ = malloc(sizeof(struct node_gid)); 978 if ($$ == NULL) 979 err(1, "gid_item: malloc"); 980 $$->gid[0] = $1; 981 $$->gid[1] = $1; 982 $$->op = PF_OP_EQ; 983 $$->next = NULL; 984 $$->tail = $$; 985 } 986 | PORTUNARY gid { 987 if ($2 == GID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) { 988 yyerror("group unknown requires operator = or !="); 989 YYERROR; 990 } 991 $$ = malloc(sizeof(struct node_gid)); 992 if ($$ == NULL) 993 err(1, "gid_item: malloc"); 994 $$->gid[0] = $2; 995 $$->gid[1] = $2; 996 $$->op = $1; 997 $$->next = NULL; 998 $$->tail = $$; 999 } 1000 | gid PORTBINARY gid { 1001 if ($1 == GID_MAX || $3 == GID_MAX) { 1002 yyerror("group unknown requires operator = or !="); 1003 YYERROR; 1004 } 1005 $$ = malloc(sizeof(struct node_gid)); 1006 if ($$ == NULL) 1007 err(1, "gid_item: malloc"); 1008 $$->gid[0] = $1; 1009 $$->gid[1] = $3; 1010 $$->op = $2; 1011 $$->next = NULL; 1012 $$->tail = $$; 1013 } 1014 ; 1015 1016gid : STRING { 1017 u_long ulval; 1018 1019 if (atoul($1, &ulval) == -1) { 1020 if (!strcmp($1, "unknown")) 1021 $$ = GID_MAX; 1022 else { 1023 struct group *grp; 1024 1025 if ((grp = getgrnam($1)) == NULL) { 1026 yyerror("unknown group %s", $1); 1027 YYERROR; 1028 } 1029 $$ = grp->gr_gid; 1030 } 1031 } else { 1032 if (ulval < 0 || ulval >= GID_MAX) { 1033 yyerror("illegal gid value %ul", ulval); 1034 YYERROR; 1035 } 1036 $$ = ulval; 1037 } 1038 } 1039 ; 1040 1041flag : STRING { 1042 int f; 1043 1044 if ((f = parse_flags($1)) < 0) { 1045 yyerror("bad flags %s", $1); 1046 YYERROR; 1047 } 1048 $$.b1 = f; 1049 } 1050 ; 1051 1052flags : /* empty */ { $$.b1 = 0; $$.b2 = 0; } 1053 | FLAGS flag { $$.b1 = $2.b1; $$.b2 = PF_TH_ALL; } 1054 | FLAGS flag "/" flag { $$.b1 = $2.b1; $$.b2 = $4.b1; } 1055 | FLAGS "/" flag { $$.b1 = 0; $$.b2 = $3.b1; } 1056 ; 1057 1058icmpspec : /* empty */ { $$ = NULL; } 1059 | ICMPTYPE icmp_item { $$ = $2; } 1060 | ICMPTYPE '{' icmp_list '}' { $$ = $3; } 1061 | ICMP6TYPE icmp6_item { $$ = $2; } 1062 | ICMP6TYPE '{' icmp6_list '}' { $$ = $3; } 1063 ; 1064 1065icmp_list : icmp_item { $$ = $1; } 1066 | icmp_list comma icmp_item { 1067 $1->tail->next = $3; 1068 $1->tail = $3; 1069 $$ = $1; 1070 } 1071 ; 1072 1073icmp6_list : icmp6_item { $$ = $1; } 1074 | icmp6_list comma icmp6_item { 1075 $1->tail->next = $3; 1076 $1->tail = $3; 1077 $$ = $1; 1078 } 1079 ; 1080 1081icmp_item : icmptype { 1082 $$ = malloc(sizeof(struct node_icmp)); 1083 if ($$ == NULL) 1084 err(1, "icmp_item: malloc"); 1085 $$->type = $1; 1086 $$->code = 0; 1087 $$->proto = IPPROTO_ICMP; 1088 $$->next = NULL; 1089 $$->tail = $$; 1090 } 1091 | icmptype CODE STRING { 1092 const struct icmpcodeent *p; 1093 u_long ulval; 1094 1095 if (atoul($3, &ulval) == 0) { 1096 if (ulval < 0 || ulval > 255) { 1097 yyerror("illegal icmp-code %d", ulval); 1098 YYERROR; 1099 } 1100 } else { 1101 if ((p = geticmpcodebyname($1, $3, 1102 AF_INET)) == NULL) { 1103 yyerror("unknown icmp-code %s", $3); 1104 YYERROR; 1105 } 1106 ulval = p->code; 1107 } 1108 $$ = malloc(sizeof(struct node_icmp)); 1109 if ($$ == NULL) 1110 err(1, "icmp_item: malloc"); 1111 $$->type = $1; 1112 $$->code = ulval + 1; 1113 $$->proto = IPPROTO_ICMP; 1114 $$->next = NULL; 1115 $$->tail = $$; 1116 } 1117 ; 1118 1119icmp6_item : icmp6type { 1120 $$ = malloc(sizeof(struct node_icmp)); 1121 if ($$ == NULL) 1122 err(1, "icmp_item: malloc"); 1123 $$->type = $1; 1124 $$->code = 0; 1125 $$->proto = IPPROTO_ICMPV6; 1126 $$->next = NULL; 1127 $$->tail = $$; 1128 } 1129 | icmp6type CODE STRING { 1130 const struct icmpcodeent *p; 1131 u_long ulval; 1132 1133 if (atoul($3, &ulval) == 0) { 1134 if (ulval < 0 || ulval > 255) { 1135 yyerror("illegal icmp6-code %ld", ulval); 1136 YYERROR; 1137 } 1138 } else { 1139 if ((p = geticmpcodebyname($1, $3, 1140 AF_INET6)) == NULL) { 1141 yyerror("unknown icmp6-code %s", $3); 1142 YYERROR; 1143 } 1144 ulval = p->code; 1145 } 1146 $$ = malloc(sizeof(struct node_icmp)); 1147 if ($$ == NULL) 1148 err(1, "icmp_item: malloc"); 1149 $$->type = $1; 1150 $$->code = ulval + 1; 1151 $$->proto = IPPROTO_ICMPV6; 1152 $$->next = NULL; 1153 $$->tail = $$; 1154 } 1155 ; 1156 1157icmptype : STRING { 1158 const struct icmptypeent *p; 1159 u_long ulval; 1160 1161 if (atoul($1, &ulval) == 0) { 1162 if (ulval < 0 || ulval > 255) { 1163 yyerror("illegal icmp-type %d", ulval); 1164 YYERROR; 1165 } 1166 $$ = ulval + 1; 1167 } else { 1168 if ((p = geticmptypebyname($1, AF_INET)) == NULL) { 1169 yyerror("unknown icmp-type %s", $1); 1170 YYERROR; 1171 } 1172 $$ = p->type + 1; 1173 } 1174 } 1175 ; 1176 1177icmp6type : STRING { 1178 const struct icmptypeent *p; 1179 u_long ulval; 1180 1181 if (atoul($1, &ulval) == 0) { 1182 if (ulval < 0 || ulval > 255) { 1183 yyerror("illegal icmp6-type %d", ulval); 1184 YYERROR; 1185 } 1186 $$ = ulval + 1; 1187 } else { 1188 if ((p = geticmptypebyname($1, AF_INET6)) == NULL) { 1189 yyerror("unknown ipv6-icmp-type %s", $1); 1190 YYERROR; 1191 } 1192 $$ = p->type + 1; 1193 } 1194 } 1195 ; 1196 1197tos : /* empty */ { $$ = 0; } 1198 | TOS STRING { 1199 if (!strcmp($2, "lowdelay")) 1200 $$ = IPTOS_LOWDELAY; 1201 else if (!strcmp($2, "throughput")) 1202 $$ = IPTOS_THROUGHPUT; 1203 else if (!strcmp($2, "reliability")) 1204 $$ = IPTOS_RELIABILITY; 1205 else if ($2[0] == '0' && $2[1] == 'x') 1206 $$ = strtoul($2, NULL, 16); 1207 else 1208 $$ = strtoul($2, NULL, 10); 1209 if (!$$ || $$ > 255) { 1210 yyerror("illegal tos value %s", $2); 1211 YYERROR; 1212 } 1213 } 1214 ; 1215 1216keep : /* empty */ { 1217 $$.action = 0; 1218 $$.options = NULL; 1219 } 1220 | KEEP STATE state_opt_spec { 1221 $$.action = PF_STATE_NORMAL; 1222 $$.options = $3; 1223 } 1224 | MODULATE STATE state_opt_spec { 1225 $$.action = PF_STATE_MODULATE; 1226 $$.options = $3; 1227 } 1228 ; 1229 1230state_opt_spec : /* empty */ { $$ = NULL; } 1231 | '(' state_opt_list ')' { $$ = $2; } 1232 ; 1233 1234state_opt_list : state_opt_item { $$ = $1; } 1235 | state_opt_list comma state_opt_item { 1236 $1->tail->next = $3; 1237 $1->tail = $3; 1238 $$ = $1; 1239 } 1240 ; 1241 1242state_opt_item : MAXIMUM number { 1243 if ($2 <= 0) { 1244 yyerror("illegal states max value %d", $2); 1245 YYERROR; 1246 } 1247 $$ = calloc(1, sizeof(struct node_state_opt)); 1248 if ($$ == NULL) 1249 err(1, "state_opt_item: calloc"); 1250 $$->type = PF_STATE_OPT_MAX; 1251 $$->data.max_states = $2; 1252 $$->next = NULL; 1253 $$->tail = $$; 1254 } 1255 | STRING number { 1256 int i; 1257 1258 for (i = 0; pf_timeouts[i].name && 1259 strcmp(pf_timeouts[i].name, $1); ++i); 1260 if (!pf_timeouts[i].name) { 1261 yyerror("illegal timeout name %s", $1); 1262 YYERROR; 1263 } 1264 if (strchr(pf_timeouts[i].name, '.') == NULL) { 1265 yyerror("illegal state timeout %s", $1); 1266 YYERROR; 1267 } 1268 if ($2 < 0) { 1269 yyerror("illegal timeout value %d", $2); 1270 YYERROR; 1271 } 1272 $$ = calloc(1, sizeof(struct node_state_opt)); 1273 if ($$ == NULL) 1274 err(1, "state_opt_item: calloc"); 1275 $$->type = PF_STATE_OPT_TIMEOUT; 1276 $$->data.timeout.number = pf_timeouts[i].timeout; 1277 $$->data.timeout.seconds = $2; 1278 $$->next = NULL; 1279 $$->tail = $$; 1280 } 1281 ; 1282 1283fragment : /* empty */ { $$ = 0; } 1284 | FRAGMENT { $$ = 1; } 1285 1286minttl : /* empty */ { $$ = 0; } 1287 | MINTTL number { 1288 if ($2 < 0 || $2 > 255) { 1289 yyerror("illegal min-ttl value %d", $2); 1290 YYERROR; 1291 } 1292 $$ = $2; 1293 } 1294 ; 1295 1296nodf : /* empty */ { $$ = 0; } 1297 | NODF { $$ = 1; } 1298 ; 1299 1300maxmss : /* empty */ { $$ = 0; } 1301 | MAXMSS number { 1302 if ($2 < 0) { 1303 yyerror("illegal max-mss value %d", $2); 1304 YYERROR; 1305 } 1306 $$ = $2; 1307 } 1308 ; 1309 1310allowopts : /* empty */ { $$ = 0; } 1311 | ALLOWOPTS { $$ = 1; } 1312 1313label : /* empty */ { $$ = NULL; } 1314 | LABEL STRING { 1315 if (($$ = strdup($2)) == NULL) { 1316 yyerror("rule label strdup() failed"); 1317 YYERROR; 1318 } 1319 } 1320 ; 1321 1322no : /* empty */ { $$ = 0; } 1323 | NO { $$ = 1; } 1324 ; 1325 1326rport : STRING { 1327 char *p = strchr($1, ':'); 1328 1329 if (p == NULL) { 1330 if (($$.a = getservice($1)) == -1) 1331 YYERROR; 1332 $$.b = $$.t = 0; 1333 } else if (!strcmp(p+1, "*")) { 1334 *p = 0; 1335 if (($$.a = getservice($1)) == -1) 1336 YYERROR; 1337 $$.b = 0; 1338 $$.t = PF_RPORT_RANGE; 1339 } else { 1340 *p++ = 0; 1341 if (($$.a = getservice($1)) == -1 || 1342 ($$.b = getservice(p)) == -1) 1343 YYERROR; 1344 $$.t = PF_RPORT_RANGE; 1345 } 1346 } 1347 ; 1348 1349redirection : /* empty */ { $$ = NULL; } 1350 | ARROW address { 1351 $$ = malloc(sizeof(struct redirection)); 1352 if ($$ == NULL) 1353 err(1, "redirection: malloc"); 1354 $$->address = $2; 1355 $$->rport.a = $$->rport.b = $$->rport.t = 0; 1356 } 1357 | ARROW address PORT rport { 1358 $$ = malloc(sizeof(struct redirection)); 1359 if ($$ == NULL) 1360 err(1, "redirection: malloc"); 1361 $$->address = $2; 1362 $$->rport = $4; 1363 } 1364 ; 1365 1366natrule : no NAT interface af proto fromto redirection 1367 { 1368 struct pf_nat nat; 1369 1370 if (check_rulestate(PFCTL_STATE_NAT)) 1371 YYERROR; 1372 1373 memset(&nat, 0, sizeof(nat)); 1374 1375 nat.no = $1; 1376 nat.af = $4; 1377 1378 if (!nat.af) { 1379 if ($6.src.host && $6.src.host->af 1380 && !$6.src.host->ifindex) 1381 nat.af = $6.src.host->af; 1382 else if ($6.dst.host && $6.dst.host->af 1383 && !$6.dst.host->ifindex) 1384 nat.af = $6.dst.host->af; 1385 } 1386 1387 if (nat.no) { 1388 if ($7 != NULL) { 1389 yyerror("'no nat' rule does not need " 1390 "'->'"); 1391 YYERROR; 1392 } 1393 } else { 1394 struct node_host *n; 1395 1396 if ($7 == NULL || $7->address == NULL) { 1397 yyerror("'nat' rule requires '-> " 1398 "address'"); 1399 YYERROR; 1400 } 1401 if (!nat.af && !$7->address->ifindex) 1402 nat.af = $7->address->af; 1403 n = ifa_pick_ip($7->address, nat.af); 1404 if (n == NULL) 1405 YYERROR; 1406 if (!nat.af) 1407 nat.af = n->af; 1408 memcpy(&nat.raddr, &n->addr, 1409 sizeof(nat.raddr)); 1410 nat.proxy_port[0] = ntohs($7->rport.a); 1411 nat.proxy_port[1] = ntohs($7->rport.b); 1412 if (!nat.proxy_port[0] && !nat.proxy_port[1]) { 1413 nat.proxy_port[0] = 1414 PF_NAT_PROXY_PORT_LOW; 1415 nat.proxy_port[1] = 1416 PF_NAT_PROXY_PORT_HIGH; 1417 } else if (!nat.proxy_port[1]) 1418 nat.proxy_port[1] = nat.proxy_port[0]; 1419 free($7->address); 1420 free($7); 1421 } 1422 1423 expand_nat(&nat, $3, $5, $6.src.host, $6.src.port, 1424 $6.dst.host, $6.dst.port); 1425 } 1426 ; 1427 1428binatrule : no BINAT interface af proto FROM address TO ipspec redirection 1429 { 1430 struct pf_binat binat; 1431 1432 if (check_rulestate(PFCTL_STATE_NAT)) 1433 YYERROR; 1434 1435 memset(&binat, 0, sizeof(binat)); 1436 1437 binat.no = $1; 1438 if ($3 != NULL) { 1439 memcpy(binat.ifname, $3->ifname, 1440 sizeof(binat.ifname)); 1441 free($3); 1442 } 1443 binat.af = $4; 1444 if ($5 != NULL) { 1445 binat.proto = $5->proto; 1446 free($5); 1447 } 1448 if ($7 != NULL && $9 != NULL && $7->af != $9->af) { 1449 yyerror("binat ip versions must match"); 1450 YYERROR; 1451 } 1452 if ($7 != NULL) { 1453 if ($7->next) { 1454 yyerror("multiple binat ip addresses"); 1455 YYERROR; 1456 } 1457 if ($7->addr.addr_dyn != NULL) { 1458 if (!binat.af) { 1459 yyerror("address family (inet/" 1460 "inet6) undefined"); 1461 YYERROR; 1462 } 1463 $7->af = binat.af; 1464 } 1465 if (binat.af && $7->af != binat.af) { 1466 yyerror("binat ip versions must match"); 1467 YYERROR; 1468 } 1469 binat.af = $7->af; 1470 memcpy(&binat.saddr, &$7->addr, 1471 sizeof(binat.saddr)); 1472 free($7); 1473 } 1474 if ($9 != NULL) { 1475 if ($9->next) { 1476 yyerror("multiple binat ip addresses"); 1477 YYERROR; 1478 } 1479 if ($9->addr.addr_dyn != NULL) { 1480 if (!binat.af) { 1481 yyerror("address family (inet/" 1482 "inet6) undefined"); 1483 YYERROR; 1484 } 1485 $9->af = binat.af; 1486 } 1487 if (binat.af && $9->af != binat.af) { 1488 yyerror("binat ip versions must match"); 1489 YYERROR; 1490 } 1491 binat.af = $9->af; 1492 memcpy(&binat.daddr, &$9->addr, 1493 sizeof(binat.daddr)); 1494 memcpy(&binat.dmask, &$9->mask, 1495 sizeof(binat.dmask)); 1496 binat.dnot = $9->not; 1497 free($9); 1498 } 1499 1500 if (binat.no) { 1501 if ($10 != NULL) { 1502 yyerror("'no binat' rule does not need" 1503 " '->'"); 1504 YYERROR; 1505 } 1506 } else { 1507 struct node_host *n; 1508 1509 if ($10 == NULL || $10->address == NULL) { 1510 yyerror("'binat' rule requires" 1511 " '-> address'"); 1512 YYERROR; 1513 } 1514 n = ifa_pick_ip($10->address, binat.af); 1515 if (n == NULL) 1516 YYERROR; 1517 if (n->addr.addr_dyn != NULL) { 1518 if (!binat.af) { 1519 yyerror("address family (inet/" 1520 "inet6) undefined"); 1521 YYERROR; 1522 } 1523 n->af = binat.af; 1524 } 1525 if (binat.af && n->af != binat.af) { 1526 yyerror("binat ip versions must match"); 1527 YYERROR; 1528 } 1529 binat.af = n->af; 1530 memcpy(&binat.raddr, &n->addr, 1531 sizeof(binat.raddr)); 1532 free($10->address); 1533 free($10); 1534 } 1535 1536 pfctl_add_binat(pf, &binat); 1537 } 1538 1539rdrrule : no RDR interface af proto FROM ipspec TO ipspec dport redirection 1540 { 1541 struct pf_rdr rdr; 1542 1543 if (check_rulestate(PFCTL_STATE_NAT)) 1544 YYERROR; 1545 1546 memset(&rdr, 0, sizeof(rdr)); 1547 1548 rdr.no = $1; 1549 rdr.af = $4; 1550 if ($7 != NULL) { 1551 memcpy(&rdr.saddr, &$7->addr, 1552 sizeof(rdr.saddr)); 1553 memcpy(&rdr.smask, &$7->mask, 1554 sizeof(rdr.smask)); 1555 rdr.snot = $7->not; 1556 if (!rdr.af && !$7->ifindex) 1557 rdr.af = $7->af; 1558 } 1559 if ($9 != NULL) { 1560 memcpy(&rdr.daddr, &$9->addr, 1561 sizeof(rdr.daddr)); 1562 memcpy(&rdr.dmask, &$9->mask, 1563 sizeof(rdr.dmask)); 1564 rdr.dnot = $9->not; 1565 if (!rdr.af && !$9->ifindex) 1566 rdr.af = $9->af; 1567 } 1568 1569 rdr.dport = $10.a; 1570 rdr.dport2 = $10.b; 1571 rdr.opts |= $10.t; 1572 1573 if (rdr.no) { 1574 if ($11 != NULL) { 1575 yyerror("'no rdr' rule does not need '->'"); 1576 YYERROR; 1577 } 1578 } else { 1579 struct node_host *n; 1580 1581 if ($11 == NULL || $11->address == NULL) { 1582 yyerror("'rdr' rule requires '-> " 1583 "address'"); 1584 YYERROR; 1585 } 1586 if (!rdr.af && !$11->address->ifindex) 1587 rdr.af = $11->address->af; 1588 n = ifa_pick_ip($11->address, rdr.af); 1589 if (n == NULL) 1590 YYERROR; 1591 if (!rdr.af) 1592 rdr.af = n->af; 1593 memcpy(&rdr.raddr, &n->addr, 1594 sizeof(rdr.raddr)); 1595 free($11->address); 1596 rdr.rport = $11->rport.a; 1597 rdr.opts |= $11->rport.t; 1598 free($11); 1599 } 1600 1601 expand_rdr(&rdr, $3, $5, $7, $9); 1602 } 1603 ; 1604 1605dport : /* empty */ { 1606 $$.a = $$.b = $$.t = 0; 1607 } 1608 | PORT STRING { 1609 char *p = strchr($2, ':'); 1610 1611 if (p == NULL) { 1612 if (($$.a = getservice($2)) == -1) 1613 YYERROR; 1614 $$.b = $$.t = 0; 1615 } else { 1616 *p++ = 0; 1617 if (($$.a = getservice($2)) == -1 || 1618 ($$.b = getservice(p)) == -1) 1619 YYERROR; 1620 $$.t = PF_DPORT_RANGE; 1621 } 1622 } 1623 ; 1624 1625route : /* empty */ { 1626 $$.string = NULL; 1627 $$.rt = 0; 1628 $$.addr = NULL; 1629 $$.af = 0; 1630 } 1631 | FASTROUTE { 1632 $$.string = NULL; 1633 $$.rt = PF_FASTROUTE; 1634 $$.addr = NULL; 1635 } 1636 | ROUTETO '(' STRING address ')' { 1637 if (($$.string = strdup($3)) == NULL) { 1638 yyerror("routeto: strdup"); 1639 YYERROR; 1640 } 1641 $$.rt = PF_ROUTETO; 1642 if ($4->addr.addr_dyn != NULL) { 1643 yyerror("route-to does not support" 1644 " dynamic addresses"); 1645 YYERROR; 1646 } 1647 if ($4->next) { 1648 yyerror("multiple route-to ip addresses"); 1649 YYERROR; 1650 } 1651 $$.addr = &$4->addr.addr; 1652 $$.af = $4->af; 1653 } 1654 | ROUTETO STRING { 1655 if (($$.string = strdup($2)) == NULL) { 1656 yyerror("routeto: strdup"); 1657 YYERROR; 1658 } 1659 $$.rt = PF_ROUTETO; 1660 $$.addr = NULL; 1661 } 1662 | REPLYTO '(' STRING address ')' { 1663 if (($$.string = strdup($3)) == NULL) { 1664 yyerror("reply-to: strdup"); 1665 YYERROR; 1666 } 1667 $$.rt = PF_REPLYTO; 1668 if ($4->addr.addr_dyn != NULL) { 1669 yyerror("reply-to does not support" 1670 " dynamic addresses"); 1671 YYERROR; 1672 } 1673 if ($4->next) { 1674 yyerror("multiple reply-to ip addresses"); 1675 YYERROR; 1676 } 1677 $$.addr = &$4->addr.addr; 1678 $$.af = $4->af; 1679 } 1680 | REPLYTO STRING { 1681 if (($$.string = strdup($2)) == NULL) { 1682 yyerror("reply-to: strdup"); 1683 YYERROR; 1684 } 1685 $$.rt = PF_REPLYTO; 1686 $$.addr = NULL; 1687 } 1688 | DUPTO '(' STRING address ')' { 1689 if (($$.string = strdup($3)) == NULL) { 1690 yyerror("dupto: strdup"); 1691 YYERROR; 1692 } 1693 $$.rt = PF_DUPTO; 1694 if ($4->addr.addr_dyn != NULL) { 1695 yyerror("dup-to does not support" 1696 " dynamic addresses"); 1697 YYERROR; 1698 } 1699 if ($4->next) { 1700 yyerror("multiple dup-to ip addresses"); 1701 YYERROR; 1702 } 1703 $$.addr = &$4->addr.addr; 1704 $$.af = $4->af; 1705 } 1706 | DUPTO STRING { 1707 if (($$.string = strdup($2)) == NULL) { 1708 yyerror("dupto: strdup"); 1709 YYERROR; 1710 } 1711 $$.rt = PF_DUPTO; 1712 $$.addr = NULL; 1713 } 1714 ; 1715 1716timeout_spec : STRING number 1717 { 1718 if (pf->opts & PF_OPT_VERBOSE) 1719 printf("set timeout %s %us\n", $1, $2); 1720 if (check_rulestate(PFCTL_STATE_OPTION)) 1721 YYERROR; 1722 if (pfctl_set_timeout(pf, $1, $2) != 0) { 1723 yyerror("unknown timeout %s", $1); 1724 YYERROR; 1725 } 1726 } 1727 ; 1728 1729timeout_list : timeout_list comma timeout_spec 1730 | timeout_spec 1731 ; 1732 1733limit_spec : STRING number 1734 { 1735 if (pf->opts & PF_OPT_VERBOSE) 1736 printf("set limit %s %u\n", $1, $2); 1737 if (check_rulestate(PFCTL_STATE_OPTION)) 1738 YYERROR; 1739 if (pfctl_set_limit(pf, $1, $2) != 0) { 1740 yyerror("unable to set limit %s %u", $1, $2); 1741 YYERROR; 1742 } 1743 } 1744 1745limit_list : limit_list comma limit_spec 1746 | limit_spec 1747 ; 1748 1749comma : ',' 1750 | /* empty */ 1751 ; 1752 1753%% 1754 1755int 1756yyerror(char *fmt, ...) 1757{ 1758 va_list ap; 1759 extern char *infile; 1760 errors = 1; 1761 1762 va_start(ap, fmt); 1763 fprintf(stderr, "%s:%d: ", infile, yylval.lineno); 1764 vfprintf(stderr, fmt, ap); 1765 fprintf(stderr, "\n"); 1766 va_end(ap); 1767 return (0); 1768} 1769 1770int 1771rule_consistent(struct pf_rule *r) 1772{ 1773 int problems = 0; 1774 1775 if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP && 1776 (r->src.port_op || r->dst.port_op)) { 1777 yyerror("port only applies to tcp/udp"); 1778 problems++; 1779 } 1780 if (r->proto != IPPROTO_ICMP && r->proto != IPPROTO_ICMPV6 && 1781 (r->type || r->code)) { 1782 yyerror("icmp-type/code only applies to icmp"); 1783 problems++; 1784 } 1785 if (!r->af && (r->type || r->code)) { 1786 yyerror("must indicate address family with icmp-type/code"); 1787 problems++; 1788 } 1789 if ((r->proto == IPPROTO_ICMP && r->af == AF_INET6) || 1790 (r->proto == IPPROTO_ICMPV6 && r->af == AF_INET)) { 1791 yyerror("icmp version does not match address family"); 1792 problems++; 1793 } 1794 if (r->keep_state == PF_STATE_MODULATE && r->proto && 1795 r->proto != IPPROTO_TCP) { 1796 yyerror("modulate state can only be applied to TCP rules"); 1797 problems++; 1798 } 1799 if (r->allow_opts && r->action != PF_PASS) { 1800 yyerror("allow-opts can only be specified for pass rules"); 1801 problems++; 1802 } 1803 if (!r->af && (r->src.addr.addr_dyn != NULL || 1804 r->dst.addr.addr_dyn != NULL)) { 1805 yyerror("dynamic addresses require address family (inet/inet6)"); 1806 problems++; 1807 } 1808 if (r->rule_flag & PFRULE_FRAGMENT && (r->src.port_op || 1809 r->dst.port_op || r->flagset || r->type || r->code)) { 1810 yyerror("fragments can be filtered only on IP header fields"); 1811 problems++; 1812 } 1813 if (r->rule_flag & PFRULE_RETURNRST && r->proto != IPPROTO_TCP) { 1814 yyerror("return-rst can only be applied to TCP rules"); 1815 problems++; 1816 } 1817 if (r->action == PF_DROP && r->keep_state) { 1818 yyerror("keep state on block rules doesn't make sense"); 1819 problems++; 1820 } 1821 return (-problems); 1822} 1823 1824int 1825nat_consistent(struct pf_nat *r) 1826{ 1827 int problems = 0; 1828 1829 if (!r->af && (r->raddr.addr_dyn != NULL)) { 1830 yyerror("dynamic addresses require address family (inet/inet6)"); 1831 problems++; 1832 } 1833 return (-problems); 1834} 1835 1836int 1837rdr_consistent(struct pf_rdr *r) 1838{ 1839 int problems = 0; 1840 1841 if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP && 1842 (r->dport || r->dport2 || r->rport)) { 1843 yyerror("port only applies to tcp/udp"); 1844 problems++; 1845 } 1846 if (!r->af && (r->saddr.addr_dyn != NULL || 1847 r->daddr.addr_dyn != NULL || r->raddr.addr_dyn != NULL)) { 1848 yyerror("dynamic addresses require address family (inet/inet6)"); 1849 problems++; 1850 } 1851 return (-problems); 1852} 1853 1854struct keywords { 1855 const char *k_name; 1856 int k_val; 1857}; 1858 1859/* macro gore, but you should've seen the prior indentation nightmare... */ 1860 1861#define FREE_LIST(T,r) \ 1862 do { \ 1863 T *p, *n = r; \ 1864 while (n != NULL) { \ 1865 p = n; \ 1866 n = n->next; \ 1867 free(p); \ 1868 } \ 1869 } while (0) 1870 1871#define LOOP_THROUGH(T,n,r,C) \ 1872 do { \ 1873 T *n; \ 1874 if (r == NULL) { \ 1875 r = calloc(1, sizeof(T)); \ 1876 if (r == NULL) \ 1877 err(1, "LOOP: calloc"); \ 1878 r->next = NULL; \ 1879 } \ 1880 n = r; \ 1881 while (n != NULL) { \ 1882 do { \ 1883 C; \ 1884 } while (0); \ 1885 n = n->next; \ 1886 } \ 1887 } while (0) 1888 1889void 1890expand_label_addr(const char *name, char *label, u_int8_t af, 1891 struct node_host *host) 1892{ 1893 char tmp[PF_RULE_LABEL_SIZE]; 1894 char *p; 1895 1896 while ((p = strstr(label, name)) != NULL) { 1897 tmp[0] = 0; 1898 1899 strlcat(tmp, label, p-label+1); 1900 1901 if (host->not) 1902 strlcat(tmp, "! ", PF_RULE_LABEL_SIZE); 1903 if (host->addr.addr_dyn != NULL) { 1904 strlcat(tmp, "(", PF_RULE_LABEL_SIZE); 1905 strlcat(tmp, host->addr.addr.pfa.ifname, 1906 PF_RULE_LABEL_SIZE); 1907 strlcat(tmp, ")", PF_RULE_LABEL_SIZE); 1908 } else if (!af || (PF_AZERO(&host->addr.addr, af) && 1909 PF_AZERO(&host->mask, af))) 1910 strlcat(tmp, "any", PF_RULE_LABEL_SIZE); 1911 else { 1912 char a[48]; 1913 int bits; 1914 1915 if (inet_ntop(af, &host->addr.addr, a, 1916 sizeof(a)) == NULL) 1917 strlcat(a, "?", sizeof(a)); 1918 strlcat(tmp, a, PF_RULE_LABEL_SIZE); 1919 bits = unmask(&host->mask, af); 1920 a[0] = 0; 1921 if ((af == AF_INET && bits < 32) || 1922 (af == AF_INET6 && bits < 128)) 1923 snprintf(a, sizeof(a), "/%u", bits); 1924 strlcat(tmp, a, PF_RULE_LABEL_SIZE); 1925 } 1926 strlcat(tmp, p+strlen(name), PF_RULE_LABEL_SIZE); 1927 strncpy(label, tmp, PF_RULE_LABEL_SIZE); 1928 } 1929} 1930 1931void 1932expand_label_port(const char *name, char *label, struct node_port *port) 1933{ 1934 char tmp[PF_RULE_LABEL_SIZE]; 1935 char *p; 1936 char a1[6], a2[6], op[13]; 1937 1938 while ((p = strstr(label, name)) != NULL) { 1939 tmp[0] = 0; 1940 1941 strlcat(tmp, label, p-label+1); 1942 1943 snprintf(a1, sizeof(a1), "%u", ntohs(port->port[0])); 1944 snprintf(a2, sizeof(a2), "%u", ntohs(port->port[1])); 1945 if (!port->op) 1946 op[0] = 0; 1947 else if (port->op == PF_OP_IRG) 1948 snprintf(op, sizeof(op), "%s><%s", a1, a2); 1949 else if (port->op == PF_OP_XRG) 1950 snprintf(op, sizeof(op), "%s<>%s", a1, a2); 1951 else if (port->op == PF_OP_EQ) 1952 snprintf(op, sizeof(op), "%s", a1); 1953 else if (port->op == PF_OP_NE) 1954 snprintf(op, sizeof(op), "!=%s", a1); 1955 else if (port->op == PF_OP_LT) 1956 snprintf(op, sizeof(op), "<%s", a1); 1957 else if (port->op == PF_OP_LE) 1958 snprintf(op, sizeof(op), "<=%s", a1); 1959 else if (port->op == PF_OP_GT) 1960 snprintf(op, sizeof(op), ">%s", a1); 1961 else if (port->op == PF_OP_GE) 1962 snprintf(op, sizeof(op), ">=%s", a1); 1963 strlcat(tmp, op, PF_RULE_LABEL_SIZE); 1964 strlcat(tmp, p+strlen(name), PF_RULE_LABEL_SIZE); 1965 strncpy(label, tmp, PF_RULE_LABEL_SIZE); 1966 } 1967} 1968 1969void 1970expand_label_proto(const char *name, char *label, u_int8_t proto) 1971{ 1972 char tmp[PF_RULE_LABEL_SIZE]; 1973 char *p; 1974 struct protoent *pe; 1975 1976 while ((p = strstr(label, name)) != NULL) { 1977 tmp[0] = 0; 1978 strlcat(tmp, label, p-label+1); 1979 pe = getprotobynumber(proto); 1980 if (pe != NULL) 1981 strlcat(tmp, pe->p_name, PF_RULE_LABEL_SIZE); 1982 else 1983 snprintf(tmp+strlen(tmp), PF_RULE_LABEL_SIZE-strlen(tmp), 1984 "%u", proto); 1985 strlcat(tmp, p+strlen(name), PF_RULE_LABEL_SIZE); 1986 strncpy(label, tmp, PF_RULE_LABEL_SIZE); 1987 } 1988} 1989 1990void 1991expand_label_nr(const char *name, char *label) 1992{ 1993 char tmp[PF_RULE_LABEL_SIZE]; 1994 char *p; 1995 1996 while ((p = strstr(label, name)) != NULL) { 1997 tmp[0] = 0; 1998 strlcat(tmp, label, p-label+1); 1999 snprintf(tmp+strlen(tmp), PF_RULE_LABEL_SIZE-strlen(tmp), 2000 "%u", pf->rule_nr); 2001 strlcat(tmp, p+strlen(name), PF_RULE_LABEL_SIZE); 2002 strncpy(label, tmp, PF_RULE_LABEL_SIZE); 2003 } 2004} 2005 2006void 2007expand_label(char *label, u_int8_t af, 2008 struct node_host *src_host, struct node_port *src_port, 2009 struct node_host *dst_host, struct node_port *dst_port, 2010 u_int8_t proto) 2011{ 2012 expand_label_addr("$srcaddr", label, af, src_host); 2013 expand_label_addr("$dstaddr", label, af, dst_host); 2014 expand_label_port("$srcport", label, src_port); 2015 expand_label_port("$dstport", label, dst_port); 2016 expand_label_proto("$proto", label, proto); 2017 expand_label_nr("$nr", label); 2018} 2019 2020void 2021expand_rule(struct pf_rule *r, 2022 struct node_if *interfaces, struct node_proto *protos, 2023 struct node_host *src_hosts, struct node_port *src_ports, 2024 struct node_host *dst_hosts, struct node_port *dst_ports, 2025 struct node_uid *uids, struct node_gid *gids, 2026 struct node_icmp *icmp_types) 2027{ 2028 int af = r->af, nomatch = 0, added = 0; 2029 char ifname[IF_NAMESIZE]; 2030 char label[PF_RULE_LABEL_SIZE]; 2031 u_int8_t flags, flagset; 2032 2033 strlcpy(label, r->label, sizeof(label)); 2034 flags = r->flags; 2035 flagset = r->flagset; 2036 2037 LOOP_THROUGH(struct node_if, interface, interfaces, 2038 LOOP_THROUGH(struct node_proto, proto, protos, 2039 LOOP_THROUGH(struct node_icmp, icmp_type, icmp_types, 2040 LOOP_THROUGH(struct node_host, src_host, src_hosts, 2041 LOOP_THROUGH(struct node_port, src_port, src_ports, 2042 LOOP_THROUGH(struct node_host, dst_host, dst_hosts, 2043 LOOP_THROUGH(struct node_port, dst_port, dst_ports, 2044 LOOP_THROUGH(struct node_uid, uid, uids, 2045 LOOP_THROUGH(struct node_gid, gid, gids, 2046 2047 r->af = af; 2048 /* for link-local IPv6 address, interface must match up */ 2049 if ((r->af && src_host->af && r->af != src_host->af) || 2050 (r->af && dst_host->af && r->af != dst_host->af) || 2051 (src_host->af && dst_host->af && 2052 src_host->af != dst_host->af) || 2053 (src_host->ifindex && dst_host->ifindex && 2054 src_host->ifindex != dst_host->ifindex) || 2055 (src_host->ifindex && if_nametoindex(interface->ifname) && 2056 src_host->ifindex != if_nametoindex(interface->ifname)) || 2057 (dst_host->ifindex && if_nametoindex(interface->ifname) && 2058 dst_host->ifindex != if_nametoindex(interface->ifname))) 2059 continue; 2060 if (!r->af && src_host->af) 2061 r->af = src_host->af; 2062 else if (!r->af && dst_host->af) 2063 r->af = dst_host->af; 2064 2065 if (if_indextoname(src_host->ifindex, ifname)) 2066 memcpy(r->ifname, ifname, sizeof(r->ifname)); 2067 else if (if_indextoname(dst_host->ifindex, ifname)) 2068 memcpy(r->ifname, ifname, sizeof(r->ifname)); 2069 else 2070 memcpy(r->ifname, interface->ifname, sizeof(r->ifname)); 2071 2072 strlcpy(r->label, label, PF_RULE_LABEL_SIZE); 2073 expand_label(r->label, r->af, src_host, src_port, 2074 dst_host, dst_port, proto->proto); 2075 r->ifnot = interface->not; 2076 r->proto = proto->proto; 2077 r->src.addr = src_host->addr; 2078 r->src.mask = src_host->mask; 2079 r->src.noroute = src_host->noroute; 2080 r->src.not = src_host->not; 2081 r->src.port[0] = src_port->port[0]; 2082 r->src.port[1] = src_port->port[1]; 2083 r->src.port_op = src_port->op; 2084 r->dst.addr = dst_host->addr; 2085 r->dst.mask = dst_host->mask; 2086 r->dst.noroute = dst_host->noroute; 2087 r->dst.not = dst_host->not; 2088 r->dst.port[0] = dst_port->port[0]; 2089 r->dst.port[1] = dst_port->port[1]; 2090 r->dst.port_op = dst_port->op; 2091 r->uid.op = uid->op; 2092 r->uid.uid[0] = uid->uid[0]; 2093 r->uid.uid[1] = uid->uid[1]; 2094 r->gid.op = gid->op; 2095 r->gid.gid[0] = gid->gid[0]; 2096 r->gid.gid[1] = gid->gid[1]; 2097 r->type = icmp_type->type; 2098 r->code = icmp_type->code; 2099 2100 if (r->proto && r->proto != IPPROTO_TCP) { 2101 r->flags = 0; 2102 r->flagset = 0; 2103 } else { 2104 r->flags = flags; 2105 r->flagset = flagset; 2106 } 2107 if (icmp_type->proto && r->proto != icmp_type->proto) { 2108 yyerror("icmp-type mismatch"); 2109 nomatch++; 2110 } 2111 2112 if (rule_consistent(r) < 0 || nomatch) 2113 yyerror("skipping filter rule due to errors"); 2114 else { 2115 r->nr = pf->rule_nr++; 2116 pfctl_add_rule(pf, r); 2117 added++; 2118 } 2119 2120 ))))))))); 2121 2122 FREE_LIST(struct node_if, interfaces); 2123 FREE_LIST(struct node_proto, protos); 2124 FREE_LIST(struct node_host, src_hosts); 2125 FREE_LIST(struct node_port, src_ports); 2126 FREE_LIST(struct node_host, dst_hosts); 2127 FREE_LIST(struct node_port, dst_ports); 2128 FREE_LIST(struct node_uid, uids); 2129 FREE_LIST(struct node_gid, gids); 2130 FREE_LIST(struct node_icmp, icmp_types); 2131 2132 if (!added) 2133 yyerror("rule expands to no valid combination"); 2134} 2135 2136void 2137expand_nat(struct pf_nat *n, 2138 struct node_if *interfaces, struct node_proto *protos, 2139 struct node_host *src_hosts, struct node_port *src_ports, 2140 struct node_host *dst_hosts, struct node_port *dst_ports) 2141{ 2142 char ifname[IF_NAMESIZE]; 2143 int af = n->af, added = 0; 2144 2145 LOOP_THROUGH(struct node_if, interface, interfaces, 2146 LOOP_THROUGH(struct node_proto, proto, protos, 2147 LOOP_THROUGH(struct node_host, src_host, src_hosts, 2148 LOOP_THROUGH(struct node_port, src_port, src_ports, 2149 LOOP_THROUGH(struct node_host, dst_host, dst_hosts, 2150 LOOP_THROUGH(struct node_port, dst_port, dst_ports, 2151 2152 n->af = af; 2153 /* for link-local IPv6 address, interface must match up */ 2154 if ((n->af && src_host->af && n->af != src_host->af) || 2155 (n->af && dst_host->af && n->af != dst_host->af) || 2156 (src_host->af && dst_host->af && 2157 src_host->af != dst_host->af) || 2158 (src_host->ifindex && dst_host->ifindex && 2159 src_host->ifindex != dst_host->ifindex) || 2160 (src_host->ifindex && if_nametoindex(interface->ifname) && 2161 src_host->ifindex != if_nametoindex(interface->ifname)) || 2162 (dst_host->ifindex && if_nametoindex(interface->ifname) && 2163 dst_host->ifindex != if_nametoindex(interface->ifname))) 2164 continue; 2165 if (!n->af && src_host->af) 2166 n->af = src_host->af; 2167 else if (!n->af && dst_host->af) 2168 n->af = dst_host->af; 2169 2170 if (if_indextoname(src_host->ifindex, ifname)) 2171 memcpy(n->ifname, ifname, sizeof(n->ifname)); 2172 else if (if_indextoname(dst_host->ifindex, ifname)) 2173 memcpy(n->ifname, ifname, sizeof(n->ifname)); 2174 else 2175 memcpy(n->ifname, interface->ifname, sizeof(n->ifname)); 2176 2177 if (!n->af && n->raddr.addr_dyn != NULL) { 2178 yyerror("address family (inet/inet6) undefined"); 2179 continue; 2180 } 2181 2182 n->ifnot = interface->not; 2183 n->proto = proto->proto; 2184 n->src.addr = src_host->addr; 2185 n->src.mask = src_host->mask; 2186 n->src.noroute = src_host->noroute; 2187 n->src.not = src_host->not; 2188 n->src.port[0] = src_port->port[0]; 2189 n->src.port[1] = src_port->port[1]; 2190 n->src.port_op = src_port->op; 2191 n->dst.addr = dst_host->addr; 2192 n->dst.mask = dst_host->mask; 2193 n->dst.noroute = dst_host->noroute; 2194 n->dst.not = dst_host->not; 2195 n->dst.port[0] = dst_port->port[0]; 2196 n->dst.port[1] = dst_port->port[1]; 2197 n->dst.port_op = dst_port->op; 2198 2199 if (nat_consistent(n) < 0) 2200 yyerror("skipping nat rule due to errors"); 2201 else { 2202 pfctl_add_nat(pf, n); 2203 added++; 2204 } 2205 2206 )))))); 2207 2208 FREE_LIST(struct node_if, interfaces); 2209 FREE_LIST(struct node_proto, protos); 2210 FREE_LIST(struct node_host, src_hosts); 2211 FREE_LIST(struct node_port, src_ports); 2212 FREE_LIST(struct node_host, dst_hosts); 2213 FREE_LIST(struct node_port, dst_ports); 2214 2215 if (!added) 2216 yyerror("nat rule expands to no valid combinations"); 2217} 2218 2219void 2220expand_rdr(struct pf_rdr *r, struct node_if *interfaces, 2221 struct node_proto *protos, struct node_host *src_hosts, 2222 struct node_host *dst_hosts) 2223{ 2224 int af = r->af, added = 0; 2225 char ifname[IF_NAMESIZE]; 2226 2227 LOOP_THROUGH(struct node_if, interface, interfaces, 2228 LOOP_THROUGH(struct node_proto, proto, protos, 2229 LOOP_THROUGH(struct node_host, src_host, src_hosts, 2230 LOOP_THROUGH(struct node_host, dst_host, dst_hosts, 2231 2232 r->af = af; 2233 if ((r->af && src_host->af && r->af != src_host->af) || 2234 (r->af && dst_host->af && r->af != dst_host->af) || 2235 (src_host->af && dst_host->af && 2236 src_host->af != dst_host->af) || 2237 (src_host->ifindex && dst_host->ifindex && 2238 src_host->ifindex != dst_host->ifindex) || 2239 (src_host->ifindex && if_nametoindex(interface->ifname) && 2240 src_host->ifindex != if_nametoindex(interface->ifname)) || 2241 (dst_host->ifindex && if_nametoindex(interface->ifname) && 2242 dst_host->ifindex != if_nametoindex(interface->ifname))) 2243 continue; 2244 2245 if (!r->af && src_host->af) 2246 r->af = src_host->af; 2247 else if (!r->af && dst_host->af) 2248 r->af = dst_host->af; 2249 if (!r->af && (r->saddr.addr_dyn != NULL || 2250 r->daddr.addr_dyn != NULL || r->raddr.addr_dyn)) { 2251 yyerror("address family (inet/inet6) undefined"); 2252 continue; 2253 } 2254 2255 if (if_indextoname(src_host->ifindex, ifname)) 2256 memcpy(r->ifname, ifname, sizeof(r->ifname)); 2257 else if (if_indextoname(dst_host->ifindex, ifname)) 2258 memcpy(r->ifname, ifname, sizeof(r->ifname)); 2259 else 2260 memcpy(r->ifname, interface->ifname, sizeof(r->ifname)); 2261 2262 r->proto = proto->proto; 2263 r->ifnot = interface->not; 2264 r->saddr = src_host->addr; 2265 r->smask = src_host->mask; 2266 r->daddr = dst_host->addr; 2267 r->dmask = dst_host->mask; 2268 2269 if (rdr_consistent(r) < 0) 2270 yyerror("skipping rdr rule due to errors"); 2271 else { 2272 pfctl_add_rdr(pf, r); 2273 added++; 2274 } 2275 2276 )))); 2277 2278 FREE_LIST(struct node_if, interfaces); 2279 FREE_LIST(struct node_proto, protos); 2280 FREE_LIST(struct node_host, src_hosts); 2281 FREE_LIST(struct node_host, dst_hosts); 2282 2283 if (!added) 2284 yyerror("rdr rule expands to no valid combination"); 2285} 2286 2287#undef FREE_LIST 2288#undef LOOP_THROUGH 2289 2290int 2291check_rulestate(int desired_state) 2292{ 2293 if (rulestate > desired_state) { 2294 yyerror("Rules must be in order: options, normalization, " 2295 "translation, filter"); 2296 return (1); 2297 } 2298 rulestate = desired_state; 2299 return (0); 2300} 2301 2302int 2303kw_cmp(const void *k, const void *e) 2304{ 2305 return (strcmp(k, ((struct keywords *)e)->k_name)); 2306} 2307 2308int 2309lookup(char *s) 2310{ 2311 /* this has to be sorted always */ 2312 static const struct keywords keywords[] = { 2313 { "all", ALL}, 2314 { "allow-opts", ALLOWOPTS}, 2315 { "antispoof", ANTISPOOF}, 2316 { "any", ANY}, 2317 { "binat", BINAT}, 2318 { "block", BLOCK}, 2319 { "code", CODE}, 2320 { "crop", FRAGCROP}, 2321 { "drop-ovl", FRAGDROP}, 2322 { "dup-to", DUPTO}, 2323 { "fastroute", FASTROUTE}, 2324 { "flags", FLAGS}, 2325 { "for", FOR}, 2326 { "fragment", FRAGMENT}, 2327 { "from", FROM}, 2328 { "group", GROUP}, 2329 { "icmp-type", ICMPTYPE}, 2330 { "in", IN}, 2331 { "inet", INET}, 2332 { "inet6", INET6}, 2333 { "ipv6-icmp-type", ICMP6TYPE}, 2334 { "keep", KEEP}, 2335 { "label", LABEL}, 2336 { "limit", LIMIT}, 2337 { "log", LOG}, 2338 { "log-all", LOGALL}, 2339 { "loginterface", LOGINTERFACE}, 2340 { "max", MAXIMUM}, 2341 { "max-mss", MAXMSS}, 2342 { "min-ttl", MINTTL}, 2343 { "modulate", MODULATE}, 2344 { "nat", NAT}, 2345 { "no", NO}, 2346 { "no-df", NODF}, 2347 { "no-route", NOROUTE}, 2348 { "on", ON}, 2349 { "optimization", OPTIMIZATION}, 2350 { "out", OUT}, 2351 { "pass", PASS}, 2352 { "port", PORT}, 2353 { "proto", PROTO}, 2354 { "quick", QUICK}, 2355 { "rdr", RDR}, 2356 { "reassemble", FRAGNORM}, 2357 { "reply-to", REPLYTO}, 2358 { "return", RETURN}, 2359 { "return-icmp",RETURNICMP}, 2360 { "return-icmp6",RETURNICMP6}, 2361 { "return-rst", RETURNRST}, 2362 { "route-to", ROUTETO}, 2363 { "scrub", SCRUB}, 2364 { "set", SET}, 2365 { "state", STATE}, 2366 { "timeout", TIMEOUT}, 2367 { "to", TO}, 2368 { "tos", TOS}, 2369 { "ttl", TTL}, 2370 { "user", USER}, 2371 }; 2372 const struct keywords *p; 2373 2374 p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), 2375 sizeof(keywords[0]), kw_cmp); 2376 2377 if (p) { 2378 if (debug > 1) 2379 fprintf(stderr, "%s: %d\n", s, p->k_val); 2380 return (p->k_val); 2381 } else { 2382 if (debug > 1) 2383 fprintf(stderr, "string: %s\n", s); 2384 return (STRING); 2385 } 2386} 2387 2388#define MAXPUSHBACK 128 2389 2390char *parsebuf; 2391int parseindex; 2392char pushback_buffer[MAXPUSHBACK]; 2393int pushback_index = 0; 2394 2395int 2396lgetc(FILE *fin) 2397{ 2398 int c, next; 2399 2400 if (parsebuf) { 2401 /* Reading characters from the parse buffer, instead of input */ 2402 if (parseindex >= 0) { 2403 c = parsebuf[parseindex++]; 2404 if (c != '\0') 2405 return (c); 2406 parsebuf = NULL; 2407 } else 2408 parseindex++; 2409 } 2410 2411 if (pushback_index) 2412 return (pushback_buffer[--pushback_index]); 2413 2414 while ((c = getc(fin)) == '\\') { 2415 next = getc(fin); 2416 if (next != '\n') { 2417 ungetc(next, fin); 2418 break; 2419 } 2420 yylval.lineno = lineno; 2421 lineno++; 2422 } 2423 return (c); 2424} 2425 2426int 2427lungetc(int c, FILE *fin) 2428{ 2429 if (c == EOF) 2430 return (EOF); 2431 if (parsebuf) { 2432 parseindex--; 2433 if (parseindex >= 0) 2434 return (c); 2435 } 2436 if (pushback_index < MAXPUSHBACK-1) 2437 return (pushback_buffer[pushback_index++] = c); 2438 else 2439 return (EOF); 2440} 2441 2442int 2443findeol(void) 2444{ 2445 int c; 2446 2447 parsebuf = NULL; 2448 pushback_index = 0; 2449 2450 /* skip to either EOF or the first real EOL */ 2451 while (1) { 2452 c = lgetc(fin); 2453 if (c == '\n') { 2454 lineno++; 2455 break; 2456 } 2457 if (c == EOF) 2458 break; 2459 } 2460 return (ERROR); 2461} 2462 2463int 2464yylex(void) 2465{ 2466 char buf[8096], *p, *val; 2467 int endc, c, next; 2468 int token; 2469 2470top: 2471 p = buf; 2472 while ((c = lgetc(fin)) == ' ' || c == '\t') 2473 ; 2474 2475 yylval.lineno = lineno; 2476 if (c == '#') 2477 while ((c = lgetc(fin)) != '\n' && c != EOF) 2478 ; 2479 if (c == '$' && parsebuf == NULL) { 2480 while (1) { 2481 if ((c = lgetc(fin)) == EOF) 2482 return (0); 2483 if (p + 1 >= buf + sizeof(buf) - 1) { 2484 yyerror("string too long"); 2485 return (findeol()); 2486 } 2487 if (isalnum(c) || c == '_') { 2488 *p++ = (char)c; 2489 continue; 2490 } 2491 *p = '\0'; 2492 lungetc(c, fin); 2493 break; 2494 } 2495 val = symget(buf); 2496 if (val == NULL) 2497 return (ERROR); 2498 parsebuf = val; 2499 parseindex = 0; 2500 goto top; 2501 } 2502 2503 switch (c) { 2504 case '\'': 2505 case '"': 2506 endc = c; 2507 while (1) { 2508 if ((c = lgetc(fin)) == EOF) 2509 return (0); 2510 if (c == endc) { 2511 *p = '\0'; 2512 break; 2513 } 2514 if (c == '\n') { 2515 lineno++; 2516 continue; 2517 } 2518 if (p + 1 >= buf + sizeof(buf) - 1) { 2519 yyerror("string too long"); 2520 return (findeol()); 2521 } 2522 *p++ = (char)c; 2523 } 2524 yylval.v.string = strdup(buf); 2525 if (yylval.v.string == NULL) 2526 err(1, "yylex: strdup"); 2527 return (STRING); 2528 case '=': 2529 yylval.v.i = PF_OP_EQ; 2530 return (PORTUNARY); 2531 case '!': 2532 next = lgetc(fin); 2533 if (next == '=') { 2534 yylval.v.i = PF_OP_NE; 2535 return (PORTUNARY); 2536 } 2537 lungetc(next, fin); 2538 break; 2539 case '<': 2540 next = lgetc(fin); 2541 if (next == '>') { 2542 yylval.v.i = PF_OP_XRG; 2543 return (PORTBINARY); 2544 } else if (next == '=') { 2545 yylval.v.i = PF_OP_LE; 2546 } else { 2547 yylval.v.i = PF_OP_LT; 2548 lungetc(next, fin); 2549 } 2550 return (PORTUNARY); 2551 break; 2552 case '>': 2553 next = lgetc(fin); 2554 if (next == '<') { 2555 yylval.v.i = PF_OP_IRG; 2556 return (PORTBINARY); 2557 } else if (next == '=') { 2558 yylval.v.i = PF_OP_GE; 2559 } else { 2560 yylval.v.i = PF_OP_GT; 2561 lungetc(next, fin); 2562 } 2563 return (PORTUNARY); 2564 break; 2565 case '-': 2566 next = lgetc(fin); 2567 if (next == '>') 2568 return (ARROW); 2569 lungetc(next, fin); 2570 break; 2571 } 2572 2573#define allowed_in_string(x) \ 2574 (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ 2575 x != '{' && x != '}' && x != '<' && x != '>' && \ 2576 x != '!' && x != '=' && x != '/' && x != '#' && \ 2577 x != ',')) 2578 2579 if (isalnum(c) || c == ':') { 2580 do { 2581 *p++ = c; 2582 if (p-buf >= sizeof(buf)) { 2583 yyerror("string too long"); 2584 return (findeol()); 2585 } 2586 } while ((c = lgetc(fin)) != EOF && (allowed_in_string(c))); 2587 lungetc(c, fin); 2588 *p = '\0'; 2589 token = lookup(buf); 2590 yylval.v.string = strdup(buf); 2591 if (yylval.v.string == NULL) 2592 err(1, "yylex: strdup"); 2593 return (token); 2594 } 2595 if (c == '\n') { 2596 yylval.lineno = lineno; 2597 lineno++; 2598 } 2599 if (c == EOF) 2600 return (0); 2601 return (c); 2602} 2603 2604int 2605parse_rules(FILE *input, struct pfctl *xpf) 2606{ 2607 fin = input; 2608 pf = xpf; 2609 lineno = 1; 2610 errors = 0; 2611 rulestate = PFCTL_STATE_NONE; 2612 yyparse(); 2613 return (errors ? -1 : 0); 2614} 2615 2616void 2617ipmask(struct pf_addr *m, u_int8_t b) 2618{ 2619 int i, j = 0; 2620 2621 for (i = 0; i < 4; i++) 2622 m->addr32[i] = 0; 2623 2624 while (b >= 32) { 2625 m->addr32[j++] = 0xffffffff; 2626 b -= 32; 2627 } 2628 for (i = 31; i > 31-b; --i) 2629 m->addr32[j] |= (1 << i); 2630 if (b) 2631 m->addr32[j] = htonl(m->addr32[j]); 2632} 2633 2634/* 2635 * Over-designed efficiency is a French and German concept, so how about 2636 * we wait until they discover this ugliness and make it all fancy. 2637 */ 2638int 2639symset(const char *nam, const char *val) 2640{ 2641 struct sym *sym; 2642 2643 sym = calloc(1, sizeof(*sym)); 2644 if (sym == NULL) 2645 return (-1); 2646 sym->nam = strdup(nam); 2647 if (sym->nam == NULL) { 2648 free(sym); 2649 return (-1); 2650 } 2651 sym->val = strdup(val); 2652 if (sym->val == NULL) { 2653 free(sym->nam); 2654 free(sym); 2655 return (-1); 2656 } 2657 sym->next = symhead; 2658 symhead = sym; 2659 return (0); 2660} 2661 2662char * 2663symget(const char *nam) 2664{ 2665 struct sym *sym; 2666 2667 for (sym = symhead; sym; sym = sym->next) 2668 if (strcmp(nam, sym->nam) == 0) 2669 return (sym->val); 2670 return (NULL); 2671} 2672 2673/* interface lookup routines */ 2674 2675struct node_host *iftab; 2676 2677void 2678ifa_load(void) 2679{ 2680 struct ifaddrs *ifap, *ifa; 2681 struct node_host *n = NULL, *h = NULL; 2682 2683 if (getifaddrs(&ifap) < 0) 2684 err(1, "getifaddrs"); 2685 2686 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 2687 if (!(ifa->ifa_addr->sa_family == AF_INET || 2688 ifa->ifa_addr->sa_family == AF_INET6 || 2689 ifa->ifa_addr->sa_family == AF_LINK)) 2690 continue; 2691 n = calloc(1, sizeof(struct node_host)); 2692 if (n == NULL) 2693 err(1, "address: calloc"); 2694 n->af = ifa->ifa_addr->sa_family; 2695 n->addr.addr_dyn = NULL; 2696 n->ifa_flags = ifa->ifa_flags; 2697#ifdef __KAME__ 2698 if (n->af == AF_INET6 && 2699 IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr) && 2700 ((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_scope_id == 0) { 2701 struct sockaddr_in6 *sin6; 2702 2703 sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; 2704 sin6->sin6_scope_id = sin6->sin6_addr.s6_addr[2] << 8 | 2705 sin6->sin6_addr.s6_addr[3]; 2706 sin6->sin6_addr.s6_addr[2] = 0; 2707 sin6->sin6_addr.s6_addr[3] = 0; 2708 } 2709#endif 2710 n->ifindex = 0; 2711 if (n->af == AF_INET) { 2712 memcpy(&n->addr.addr, &((struct sockaddr_in *) 2713 ifa->ifa_addr)->sin_addr.s_addr, 2714 sizeof(struct in_addr)); 2715 memcpy(&n->mask, &((struct sockaddr_in *) 2716 ifa->ifa_netmask)->sin_addr.s_addr, 2717 sizeof(struct in_addr)); 2718 if (ifa->ifa_broadaddr != NULL) 2719 memcpy(&n->bcast, &((struct sockaddr_in *) 2720 ifa->ifa_broadaddr)->sin_addr.s_addr, 2721 sizeof(struct in_addr)); 2722 } else if (n->af == AF_INET6) { 2723 memcpy(&n->addr.addr, &((struct sockaddr_in6 *) 2724 ifa->ifa_addr)->sin6_addr.s6_addr, 2725 sizeof(struct in6_addr)); 2726 memcpy(&n->mask, &((struct sockaddr_in6 *) 2727 ifa->ifa_netmask)->sin6_addr.s6_addr, 2728 sizeof(struct in6_addr)); 2729 if (ifa->ifa_broadaddr != NULL) 2730 memcpy(&n->bcast, &((struct sockaddr_in6 *) 2731 ifa->ifa_broadaddr)->sin6_addr.s6_addr, 2732 sizeof(struct in6_addr)); 2733 n->ifindex = ((struct sockaddr_in6 *) 2734 ifa->ifa_addr)->sin6_scope_id; 2735 } 2736 if ((n->ifname = strdup(ifa->ifa_name)) == NULL) { 2737 yyerror("malloc failed"); 2738 exit(1); 2739 } 2740 n->next = NULL; 2741 n->tail = n; 2742 if (h == NULL) 2743 h = n; 2744 else { 2745 h->tail->next = n; 2746 h->tail = n; 2747 } 2748 } 2749 iftab = h; 2750 freeifaddrs(ifap); 2751} 2752 2753struct node_host * 2754ifa_exists(char *ifa_name) 2755{ 2756 struct node_host *n; 2757 2758 if (iftab == NULL) 2759 ifa_load(); 2760 2761 for (n = iftab; n; n = n->next) { 2762 if (n->af == AF_LINK && !strncmp(n->ifname, ifa_name, IFNAMSIZ)) 2763 return (n); 2764 } 2765 return (NULL); 2766} 2767 2768struct node_host * 2769ifa_lookup(char *ifa_name, enum pfctl_iflookup_mode mode) 2770{ 2771 struct node_host *p = NULL, *h = NULL, *n = NULL; 2772 int return_all = 0; 2773 2774 if (!strncmp(ifa_name, "self", IFNAMSIZ)) 2775 return_all = 1; 2776 2777 if (iftab == NULL) 2778 ifa_load(); 2779 2780 for (p = iftab; p; p = p->next) { 2781 if (!((p->af == AF_INET || p->af == AF_INET6) 2782 && (!strncmp(p->ifname, ifa_name, IFNAMSIZ) || return_all))) 2783 continue; 2784 if (mode == PFCTL_IFLOOKUP_BCAST && p->af != AF_INET) 2785 continue; 2786 if (mode == PFCTL_IFLOOKUP_NET && p->ifindex > 0) 2787 continue; 2788 n = calloc(1, sizeof(struct node_host)); 2789 if (n == NULL) 2790 err(1, "address: calloc"); 2791 n->af = p->af; 2792 n->addr.addr_dyn = NULL; 2793 if (mode == PFCTL_IFLOOKUP_BCAST) { 2794 memcpy(&n->addr.addr, &p->bcast, 2795 sizeof(struct pf_addr)); 2796 } else 2797 memcpy(&n->addr.addr, &p->addr.addr, 2798 sizeof(struct pf_addr)); 2799 if (mode == PFCTL_IFLOOKUP_NET) 2800 memcpy(&n->mask, &p->mask, sizeof(struct pf_addr)); 2801 else { 2802 if (n->af == AF_INET) 2803 ipmask(&n->mask, 32); 2804 else 2805 ipmask(&n->mask, 128); 2806 } 2807 n->ifindex = p->ifindex; 2808 2809 n->next = NULL; 2810 n->tail = n; 2811 if (h == NULL) 2812 h = n; 2813 else { 2814 h->tail->next = n; 2815 h->tail = n; 2816 } 2817 } 2818 if (h == NULL && mode == PFCTL_IFLOOKUP_HOST) { 2819 yyerror("no IP address found for %s", ifa_name); 2820 } 2821 return (h); 2822} 2823 2824struct node_host * 2825ifa_pick_ip(struct node_host *nh, u_int8_t af) 2826{ 2827 struct node_host *h, *n = NULL; 2828 2829 if (af == 0 && nh && nh->next) { 2830 yyerror("address family not given and translation address " 2831 "expands to multiple IPs"); 2832 return (NULL); 2833 } 2834 for (h = nh; h; h = h->next) { 2835 if (h->af == af || h->af == 0 || af == 0) { 2836 if (n != NULL) { 2837 yyerror("translation address expands to " 2838 "multiple IPs of this address family"); 2839 return (NULL); 2840 } 2841 n = h; 2842 } 2843 } 2844 if (n == NULL) 2845 yyerror("no translation address with matching address family " 2846 "found."); 2847 else { 2848 n->next = NULL; 2849 n->tail = n; 2850 } 2851 2852 return (n); 2853} 2854 2855struct node_host * 2856host(char *s) 2857{ 2858 struct node_host *h = NULL, *n; 2859 struct in_addr ina; 2860 struct addrinfo hints, *res0, *res; 2861 int error; 2862 2863 if (ifa_exists(s) || !strncmp(s, "self", IFNAMSIZ)) { 2864 /* interface with this name exists */ 2865 if ((h = ifa_lookup(s, PFCTL_IFLOOKUP_HOST)) == NULL) 2866 return (NULL); 2867 else { 2868 h->next = NULL; 2869 h->tail = h; 2870 return (h); 2871 } 2872 } 2873 2874 if (inet_aton(s, &ina) == 1) { 2875 h = calloc(1, sizeof(struct node_host)); 2876 if (h == NULL) 2877 err(1, "address: calloc"); 2878 h->af = AF_INET; 2879 h->addr.addr_dyn = NULL; 2880 h->addr.addr.addr32[0] = ina.s_addr; 2881 ipmask(&h->mask, 32); 2882 h->next = NULL; 2883 h->tail = h; 2884 return (h); 2885 } 2886 2887 memset(&hints, 0, sizeof(hints)); 2888 hints.ai_family = AF_INET6; 2889 hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 2890 hints.ai_flags = AI_NUMERICHOST; 2891 if (getaddrinfo(s, "0", &hints, &res) == 0) { 2892 n = calloc(1, sizeof(struct node_host)); 2893 if (n == NULL) 2894 err(1, "address: calloc"); 2895 n->af = AF_INET6; 2896 n->addr.addr_dyn = NULL; 2897 memcpy(&n->addr.addr, 2898 &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr, 2899 sizeof(n->addr.addr)); 2900 n->ifindex = ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id; 2901 ipmask(&n->mask, 128); 2902 freeaddrinfo(res); 2903 n->next = NULL; 2904 n->tail = n; 2905 return (n); 2906 } 2907 2908 memset(&hints, 0, sizeof(hints)); 2909 hints.ai_family = PF_UNSPEC; 2910 hints.ai_socktype = SOCK_STREAM; /* DUMMY */ 2911 error = getaddrinfo(s, NULL, &hints, &res0); 2912 if (error) { 2913 yyerror("cannot resolve %s: %s", 2914 s, gai_strerror(error)); 2915 return (NULL); 2916 } 2917 for (res = res0; res; res = res->ai_next) { 2918 if (res->ai_family != AF_INET && 2919 res->ai_family != AF_INET6) 2920 continue; 2921 n = calloc(1, sizeof(struct node_host)); 2922 if (n == NULL) 2923 err(1, "address: calloc"); 2924 n->af = res->ai_family; 2925 n->addr.addr_dyn = NULL; 2926 if (res->ai_family == AF_INET) { 2927 memcpy(&n->addr.addr, 2928 &((struct sockaddr_in *)res->ai_addr)->sin_addr.s_addr, 2929 sizeof(struct in_addr)); 2930 ipmask(&n->mask, 32); 2931 } else { 2932 memcpy(&n->addr.addr, 2933 &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr.s6_addr, 2934 sizeof(struct in6_addr)); 2935 n->ifindex = 2936 ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id; 2937 ipmask(&n->mask, 128); 2938 } 2939 n->next = NULL; 2940 n->tail = n; 2941 if (h == NULL) 2942 h = n; 2943 else { 2944 h->tail->next = n; 2945 h->tail = n; 2946 } 2947 } 2948 freeaddrinfo(res0); 2949 if (h == NULL) { 2950 yyerror("no IP address found for %s", s); 2951 return (NULL); 2952 } 2953 return (h); 2954} 2955 2956int 2957atoul(char *s, u_long *ulvalp) 2958{ 2959 u_long ulval; 2960 char *ep; 2961 2962 errno = 0; 2963 ulval = strtoul(s, &ep, 0); 2964 if (s[0] == '\0' || *ep != '\0') 2965 return (-1); 2966 if (errno == ERANGE && ulval == ULONG_MAX) 2967 return (-1); 2968 *ulvalp = ulval; 2969 return (0); 2970} 2971 2972int 2973getservice(char *n) 2974{ 2975 struct servent *s; 2976 u_long ulval; 2977 2978 if (atoul(n, &ulval) == 0) { 2979 if (ulval < 0 || ulval > 65535) { 2980 yyerror("illegal port value %d", ulval); 2981 return (-1); 2982 } 2983 return (htons(ulval)); 2984 } else { 2985 s = getservbyname(n, "tcp"); 2986 if (s == NULL) 2987 s = getservbyname(n, "udp"); 2988 if (s == NULL) { 2989 yyerror("unknown port %s", n); 2990 return (-1); 2991 } 2992 return (s->s_port); 2993 } 2994} 2995 2996u_int16_t 2997parseicmpspec(char *w, u_int8_t af) 2998{ 2999 const struct icmpcodeent *p; 3000 u_long ulval; 3001 u_int8_t icmptype; 3002 3003 if (af == AF_INET) 3004 icmptype = returnicmpdefault >> 8; 3005 else 3006 icmptype = returnicmp6default >> 8; 3007 3008 if (atoul(w, &ulval) == -1) { 3009 if ((p = geticmpcodebyname(icmptype, w, af)) == NULL) { 3010 yyerror("unknown icmp code %s", w); 3011 return (0); 3012 } 3013 ulval = p->code; 3014 } 3015 return (icmptype << 8 | ulval); 3016} 3017