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