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