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