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