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