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