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