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