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