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