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