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