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