parse.y revision 1.433
1/* $OpenBSD: parse.y,v 1.433 2003/12/31 11:18:24 cedric 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 free($4); 3043 } 3044 if ($11 != NULL) 3045 if (strlcpy(binat.tagname, $11, 3046 PF_TAG_NAME_SIZE) > PF_TAG_NAME_SIZE) { 3047 yyerror("tag too long, max %u chars", 3048 PF_TAG_NAME_SIZE - 1); 3049 YYERROR; 3050 } 3051 3052 if ($6 != NULL) { 3053 binat.proto = $6->proto; 3054 free($6); 3055 } 3056 3057 if ($8 != NULL && disallow_table($8, "invalid use of " 3058 "table <%s> as the source address of a binat rule")) 3059 YYERROR; 3060 if ($8 != NULL && disallow_alias($8, "invalid use of " 3061 "interface (%s) as the source address of a binat " 3062 "rule")) 3063 YYERROR; 3064 if ($12 != NULL && $12->host != NULL && disallow_table( 3065 $12->host, "invalid use of table <%s> as the " 3066 "redirect address of a binat rule")) 3067 YYERROR; 3068 if ($12 != NULL && $12->host != NULL && disallow_alias( 3069 $12->host, "invalid use of interface (%s) as the " 3070 "redirect address of a binat rule")) 3071 YYERROR; 3072 3073 if ($8 != NULL) { 3074 if ($8->next) { 3075 yyerror("multiple binat ip addresses"); 3076 YYERROR; 3077 } 3078 if ($8->addr.type == PF_ADDR_DYNIFTL) 3079 $8->af = binat.af; 3080 if ($8->af != binat.af) { 3081 yyerror("binat ip versions must match"); 3082 YYERROR; 3083 } 3084 if (check_netmask($8, binat.af)) 3085 YYERROR; 3086 memcpy(&binat.src.addr, &$8->addr, 3087 sizeof(binat.src.addr)); 3088 free($8); 3089 } 3090 if ($10 != NULL) { 3091 if ($10->next) { 3092 yyerror("multiple binat ip addresses"); 3093 YYERROR; 3094 } 3095 if ($10->af != binat.af && $10->af) { 3096 yyerror("binat ip versions must match"); 3097 YYERROR; 3098 } 3099 if (check_netmask($10, binat.af)) 3100 YYERROR; 3101 memcpy(&binat.dst.addr, &$10->addr, 3102 sizeof(binat.dst.addr)); 3103 binat.dst.not = $10->not; 3104 free($10); 3105 } 3106 3107 if (binat.action == PF_NOBINAT) { 3108 if ($12 != NULL) { 3109 yyerror("'no binat' rule does not need" 3110 " '->'"); 3111 YYERROR; 3112 } 3113 } else { 3114 if ($12 == NULL || $12->host == NULL) { 3115 yyerror("'binat' rule requires" 3116 " '-> address'"); 3117 YYERROR; 3118 } 3119 3120 remove_invalid_hosts(&$12->host, &binat.af); 3121 if (invalid_redirect($12->host, binat.af)) 3122 YYERROR; 3123 if ($12->host->next != NULL) { 3124 yyerror("binat rule must redirect to " 3125 "a single address"); 3126 YYERROR; 3127 } 3128 if (check_netmask($12->host, binat.af)) 3129 YYERROR; 3130 3131 if (!PF_AZERO(&binat.src.addr.v.a.mask, 3132 binat.af) && 3133 !PF_AEQ(&binat.src.addr.v.a.mask, 3134 &$12->host->addr.v.a.mask, binat.af)) { 3135 yyerror("'binat' source mask and " 3136 "redirect mask must be the same"); 3137 YYERROR; 3138 } 3139 3140 TAILQ_INIT(&binat.rpool.list); 3141 pa = calloc(1, sizeof(struct pf_pooladdr)); 3142 if (pa == NULL) 3143 err(1, "binat: calloc"); 3144 pa->addr = $12->host->addr; 3145 pa->ifname[0] = 0; 3146 TAILQ_INSERT_TAIL(&binat.rpool.list, 3147 pa, entries); 3148 3149 free($12); 3150 } 3151 3152 pfctl_add_rule(pf, &binat); 3153 } 3154 ; 3155 3156tag : /* empty */ { $$ = NULL; } 3157 | TAG STRING { $$ = $2; } 3158 ; 3159 3160route_host : STRING { 3161 $$ = calloc(1, sizeof(struct node_host)); 3162 if ($$ == NULL) 3163 err(1, "route_host: calloc"); 3164 if (($$->ifname = strdup($1)) == NULL) 3165 err(1, "routeto: strdup"); 3166 if (ifa_exists($$->ifname, 0) == NULL) { 3167 yyerror("routeto: unknown interface %s", 3168 $$->ifname); 3169 YYERROR; 3170 } 3171 set_ipmask($$, 128); 3172 $$->next = NULL; 3173 $$->tail = $$; 3174 } 3175 | '(' STRING host ')' { 3176 $$ = $3; 3177 if (($$->ifname = strdup($2)) == NULL) 3178 err(1, "routeto: strdup"); 3179 if (ifa_exists($$->ifname, 0) == NULL) { 3180 yyerror("routeto: unknown interface %s", 3181 $$->ifname); 3182 YYERROR; 3183 } 3184 } 3185 ; 3186 3187route_host_list : route_host { $$ = $1; } 3188 | route_host_list comma route_host { 3189 if ($1->af == 0) 3190 $1->af = $3->af; 3191 if ($1->af != $3->af) { 3192 yyerror("all pool addresses must be in the " 3193 "same address family"); 3194 YYERROR; 3195 } 3196 $1->tail->next = $3; 3197 $1->tail = $3->tail; 3198 $$ = $1; 3199 } 3200 ; 3201 3202routespec : route_host { $$ = $1; } 3203 | '{' route_host_list '}' { $$ = $2; } 3204 ; 3205 3206route : /* empty */ { 3207 $$.host = NULL; 3208 $$.rt = 0; 3209 $$.pool_opts = 0; 3210 } 3211 | FASTROUTE { 3212 $$.host = NULL; 3213 $$.rt = PF_FASTROUTE; 3214 $$.pool_opts = 0; 3215 } 3216 | ROUTETO routespec pool_opts { 3217 $$.host = $2; 3218 $$.rt = PF_ROUTETO; 3219 $$.pool_opts = $3.type | $3.opts; 3220 if ($3.key != NULL) 3221 $$.key = $3.key; 3222 } 3223 | REPLYTO routespec pool_opts { 3224 $$.host = $2; 3225 $$.rt = PF_REPLYTO; 3226 $$.pool_opts = $3.type | $3.opts; 3227 if ($3.key != NULL) 3228 $$.key = $3.key; 3229 } 3230 | DUPTO routespec pool_opts { 3231 $$.host = $2; 3232 $$.rt = PF_DUPTO; 3233 $$.pool_opts = $3.type | $3.opts; 3234 if ($3.key != NULL) 3235 $$.key = $3.key; 3236 } 3237 ; 3238 3239timeout_spec : STRING number 3240 { 3241 if (check_rulestate(PFCTL_STATE_OPTION)) 3242 YYERROR; 3243 if (pfctl_set_timeout(pf, $1, $2, 0) != 0) { 3244 yyerror("unknown timeout %s", $1); 3245 YYERROR; 3246 } 3247 3248 } 3249 ; 3250 3251timeout_list : timeout_list comma timeout_spec 3252 | timeout_spec 3253 ; 3254 3255limit_spec : STRING number 3256 { 3257 if (check_rulestate(PFCTL_STATE_OPTION)) 3258 YYERROR; 3259 if (pfctl_set_limit(pf, $1, $2) != 0) { 3260 yyerror("unable to set limit %s %u", $1, $2); 3261 YYERROR; 3262 } 3263 } 3264 ; 3265 3266limit_list : limit_list comma limit_spec 3267 | limit_spec 3268 ; 3269 3270comma : ',' 3271 | /* empty */ 3272 ; 3273 3274yesno : NO { $$ = 0; } 3275 | STRING { 3276 if (!strcmp($1, "yes")) 3277 $$ = 1; 3278 else 3279 YYERROR; 3280 } 3281 ; 3282 3283unaryop : '=' { $$ = PF_OP_EQ; } 3284 | '!' '=' { $$ = PF_OP_NE; } 3285 | '<' '=' { $$ = PF_OP_LE; } 3286 | '<' { $$ = PF_OP_LT; } 3287 | '>' '=' { $$ = PF_OP_GE; } 3288 | '>' { $$ = PF_OP_GT; } 3289 ; 3290 3291%% 3292 3293int 3294yyerror(const char *fmt, ...) 3295{ 3296 va_list ap; 3297 extern char *infile; 3298 3299 errors = 1; 3300 va_start(ap, fmt); 3301 fprintf(stderr, "%s:%d: ", infile, yylval.lineno); 3302 vfprintf(stderr, fmt, ap); 3303 fprintf(stderr, "\n"); 3304 va_end(ap); 3305 return (0); 3306} 3307 3308int 3309disallow_table(struct node_host *h, const char *fmt) 3310{ 3311 for (; h != NULL; h = h->next) 3312 if (h->addr.type == PF_ADDR_TABLE) { 3313 yyerror(fmt, h->addr.v.tblname); 3314 return (1); 3315 } 3316 return (0); 3317} 3318 3319int 3320disallow_alias(struct node_host *h, const char *fmt) 3321{ 3322 for (; h != NULL; h = h->next) 3323 if (DYNIF_MULTIADDR(h->addr)) { 3324 yyerror(fmt, h->addr.v.tblname); 3325 return (1); 3326 } 3327 return (0); 3328} 3329 3330int 3331rule_consistent(struct pf_rule *r) 3332{ 3333 int problems = 0; 3334 3335 switch (r->action) { 3336 case PF_PASS: 3337 case PF_DROP: 3338 case PF_SCRUB: 3339 problems = filter_consistent(r); 3340 break; 3341 case PF_NAT: 3342 case PF_NONAT: 3343 problems = nat_consistent(r); 3344 break; 3345 case PF_RDR: 3346 case PF_NORDR: 3347 problems = rdr_consistent(r); 3348 break; 3349 case PF_BINAT: 3350 case PF_NOBINAT: 3351 default: 3352 break; 3353 } 3354 return (problems); 3355} 3356 3357int 3358filter_consistent(struct pf_rule *r) 3359{ 3360 int problems = 0; 3361 3362 if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP && 3363 (r->src.port_op || r->dst.port_op)) { 3364 yyerror("port only applies to tcp/udp"); 3365 problems++; 3366 } 3367 if (r->proto != IPPROTO_ICMP && r->proto != IPPROTO_ICMPV6 && 3368 (r->type || r->code)) { 3369 yyerror("icmp-type/code only applies to icmp"); 3370 problems++; 3371 } 3372 if (!r->af && (r->type || r->code)) { 3373 yyerror("must indicate address family with icmp-type/code"); 3374 problems++; 3375 } 3376 if ((r->proto == IPPROTO_ICMP && r->af == AF_INET6) || 3377 (r->proto == IPPROTO_ICMPV6 && r->af == AF_INET)) { 3378 yyerror("proto %s doesn't match address family %s", 3379 r->proto == IPPROTO_ICMP ? "icmp" : "icmp6", 3380 r->af == AF_INET ? "inet" : "inet6"); 3381 problems++; 3382 } 3383 if ((r->keep_state == PF_STATE_MODULATE || r->keep_state == 3384 PF_STATE_SYNPROXY) && r->proto && r->proto != IPPROTO_TCP) { 3385 yyerror("modulate/synproxy state can only be applied to " 3386 "TCP rules"); 3387 problems++; 3388 } 3389 if (r->allow_opts && r->action != PF_PASS) { 3390 yyerror("allow-opts can only be specified for pass rules"); 3391 problems++; 3392 } 3393 if (r->rule_flag & PFRULE_FRAGMENT && (r->src.port_op || 3394 r->dst.port_op || r->flagset || r->type || r->code)) { 3395 yyerror("fragments can be filtered only on IP header fields"); 3396 problems++; 3397 } 3398 if (r->rule_flag & PFRULE_RETURNRST && r->proto != IPPROTO_TCP) { 3399 yyerror("return-rst can only be applied to TCP rules"); 3400 problems++; 3401 } 3402 if (r->action == PF_DROP && r->keep_state) { 3403 yyerror("keep state on block rules doesn't make sense"); 3404 problems++; 3405 } 3406 if ((r->tagname[0] || r->match_tagname[0]) && !r->keep_state && 3407 r->action == PF_PASS) { 3408 yyerror("tags cannot be used without keep state"); 3409 problems++; 3410 } 3411 return (-problems); 3412} 3413 3414int 3415nat_consistent(struct pf_rule *r) 3416{ 3417 return (0); /* yeah! */ 3418} 3419 3420int 3421rdr_consistent(struct pf_rule *r) 3422{ 3423 int problems = 0; 3424 3425 if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP) { 3426 if (r->src.port_op) { 3427 yyerror("src port only applies to tcp/udp"); 3428 problems++; 3429 } 3430 if (r->dst.port_op) { 3431 yyerror("dst port only applies to tcp/udp"); 3432 problems++; 3433 } 3434 if (r->rpool.proxy_port[0]) { 3435 yyerror("rpool port only applies to tcp/udp"); 3436 problems++; 3437 } 3438 } 3439 if (r->dst.port_op && 3440 r->dst.port_op != PF_OP_EQ && r->dst.port_op != PF_OP_RRG) { 3441 yyerror("invalid port operator for rdr destination port"); 3442 problems++; 3443 } 3444 return (-problems); 3445} 3446 3447int 3448process_tabledef(char *name, struct table_opts *opts) 3449{ 3450 struct pfr_buffer ab; 3451 struct node_tinit *ti; 3452 3453 bzero(&ab, sizeof(ab)); 3454 ab.pfrb_type = PFRB_ADDRS; 3455 SIMPLEQ_FOREACH(ti, &opts->init_nodes, entries) { 3456 if (ti->file) 3457 if (pfr_buf_load(&ab, ti->file, 0, append_addr)) { 3458 if (errno) 3459 yyerror("cannot load \"%s\": %s", 3460 ti->file, strerror(errno)); 3461 else 3462 yyerror("file \"%s\" contains bad data", 3463 ti->file); 3464 goto _error; 3465 } 3466 if (ti->host) 3467 if (append_addr_host(&ab, ti->host, 0, 0)) { 3468 yyerror("cannot create address buffer: %s", 3469 strerror(errno)); 3470 goto _error; 3471 } 3472 } 3473 if (pf->opts & PF_OPT_VERBOSE) 3474 print_tabledef(name, opts->flags, opts->init_addr, 3475 &opts->init_nodes); 3476 if (!(pf->opts & PF_OPT_NOACTION) && 3477 pfctl_define_table(name, opts->flags, opts->init_addr, 3478 pf->anchor, pf->ruleset, &ab, pf->tticket)) { 3479 yyerror("cannot define table %s: %s", name, 3480 pfr_strerror(errno)); 3481 goto _error; 3482 } 3483 pf->tdirty = 1; 3484 pfr_buf_clear(&ab); 3485 return (0); 3486_error: 3487 pfr_buf_clear(&ab); 3488 return (-1); 3489} 3490 3491struct keywords { 3492 const char *k_name; 3493 int k_val; 3494}; 3495 3496/* macro gore, but you should've seen the prior indentation nightmare... */ 3497 3498#define FREE_LIST(T,r) \ 3499 do { \ 3500 T *p, *node = r; \ 3501 while (node != NULL) { \ 3502 p = node; \ 3503 node = node->next; \ 3504 free(p); \ 3505 } \ 3506 } while (0) 3507 3508#define LOOP_THROUGH(T,n,r,C) \ 3509 do { \ 3510 T *n; \ 3511 if (r == NULL) { \ 3512 r = calloc(1, sizeof(T)); \ 3513 if (r == NULL) \ 3514 err(1, "LOOP: calloc"); \ 3515 r->next = NULL; \ 3516 } \ 3517 n = r; \ 3518 while (n != NULL) { \ 3519 do { \ 3520 C; \ 3521 } while (0); \ 3522 n = n->next; \ 3523 } \ 3524 } while (0) 3525 3526void 3527expand_label_str(char *label, size_t len, const char *srch, const char *repl) 3528{ 3529 char *tmp; 3530 char *p, *q; 3531 3532 if ((tmp = calloc(1, len)) == NULL) 3533 err(1, "expand_label_str: calloc"); 3534 p = q = label; 3535 while ((q = strstr(p, srch)) != NULL) { 3536 *q = '\0'; 3537 if ((strlcat(tmp, p, len) >= len) || 3538 (strlcat(tmp, repl, len) >= len)) 3539 errx(1, "expand_label: label too long"); 3540 q += strlen(srch); 3541 p = q; 3542 } 3543 if (strlcat(tmp, p, len) >= len) 3544 errx(1, "expand_label: label too long"); 3545 strlcpy(label, tmp, len); /* always fits */ 3546 free(tmp); 3547} 3548 3549void 3550expand_label_if(const char *name, char *label, size_t len, const char *ifname) 3551{ 3552 if (strstr(label, name) != NULL) { 3553 if (!*ifname) 3554 expand_label_str(label, len, name, "any"); 3555 else 3556 expand_label_str(label, len, name, ifname); 3557 } 3558} 3559 3560void 3561expand_label_addr(const char *name, char *label, size_t len, sa_family_t af, 3562 struct node_host *h) 3563{ 3564 char tmp[64], tmp_not[66]; 3565 3566 if (strstr(label, name) != NULL) { 3567 switch (h->addr.type) { 3568 case PF_ADDR_DYNIFTL: 3569 snprintf(tmp, sizeof(tmp), "(%s)", h->addr.v.ifname); 3570 break; 3571 case PF_ADDR_TABLE: 3572 snprintf(tmp, sizeof(tmp), "<%s>", h->addr.v.tblname); 3573 break; 3574 case PF_ADDR_NOROUTE: 3575 snprintf(tmp, sizeof(tmp), "no-route"); 3576 break; 3577 case PF_ADDR_ADDRMASK: 3578 if (!af || (PF_AZERO(&h->addr.v.a.addr, af) && 3579 PF_AZERO(&h->addr.v.a.mask, af))) 3580 snprintf(tmp, sizeof(tmp), "any"); 3581 else { 3582 char a[48]; 3583 int bits; 3584 3585 if (inet_ntop(af, &h->addr.v.a.addr, a, 3586 sizeof(a)) == NULL) 3587 snprintf(tmp, sizeof(tmp), "?"); 3588 else { 3589 bits = unmask(&h->addr.v.a.mask, af); 3590 if ((af == AF_INET && bits < 32) || 3591 (af == AF_INET6 && bits < 128)) 3592 snprintf(tmp, sizeof(tmp), 3593 "%s/%d", a, bits); 3594 else 3595 snprintf(tmp, sizeof(tmp), 3596 "%s", a); 3597 } 3598 } 3599 break; 3600 default: 3601 snprintf(tmp, sizeof(tmp), "?"); 3602 break; 3603 } 3604 3605 if (h->not) { 3606 snprintf(tmp_not, sizeof(tmp_not), "! %s", tmp); 3607 expand_label_str(label, len, name, tmp_not); 3608 } else 3609 expand_label_str(label, len, name, tmp); 3610 } 3611} 3612 3613void 3614expand_label_port(const char *name, char *label, size_t len, 3615 struct node_port *port) 3616{ 3617 char a1[6], a2[6], op[13] = ""; 3618 3619 if (strstr(label, name) != NULL) { 3620 snprintf(a1, sizeof(a1), "%u", ntohs(port->port[0])); 3621 snprintf(a2, sizeof(a2), "%u", ntohs(port->port[1])); 3622 if (!port->op) 3623 ; 3624 else if (port->op == PF_OP_IRG) 3625 snprintf(op, sizeof(op), "%s><%s", a1, a2); 3626 else if (port->op == PF_OP_XRG) 3627 snprintf(op, sizeof(op), "%s<>%s", a1, a2); 3628 else if (port->op == PF_OP_EQ) 3629 snprintf(op, sizeof(op), "%s", a1); 3630 else if (port->op == PF_OP_NE) 3631 snprintf(op, sizeof(op), "!=%s", a1); 3632 else if (port->op == PF_OP_LT) 3633 snprintf(op, sizeof(op), "<%s", a1); 3634 else if (port->op == PF_OP_LE) 3635 snprintf(op, sizeof(op), "<=%s", a1); 3636 else if (port->op == PF_OP_GT) 3637 snprintf(op, sizeof(op), ">%s", a1); 3638 else if (port->op == PF_OP_GE) 3639 snprintf(op, sizeof(op), ">=%s", a1); 3640 expand_label_str(label, len, name, op); 3641 } 3642} 3643 3644void 3645expand_label_proto(const char *name, char *label, size_t len, u_int8_t proto) 3646{ 3647 struct protoent *pe; 3648 char n[4]; 3649 3650 if (strstr(label, name) != NULL) { 3651 pe = getprotobynumber(proto); 3652 if (pe != NULL) 3653 expand_label_str(label, len, name, pe->p_name); 3654 else { 3655 snprintf(n, sizeof(n), "%u", proto); 3656 expand_label_str(label, len, name, n); 3657 } 3658 } 3659} 3660 3661void 3662expand_label_nr(const char *name, char *label, size_t len) 3663{ 3664 char n[11]; 3665 3666 if (strstr(label, name) != NULL) { 3667 snprintf(n, sizeof(n), "%u", pf->rule_nr); 3668 expand_label_str(label, len, name, n); 3669 } 3670} 3671 3672void 3673expand_label(char *label, size_t len, const char *ifname, sa_family_t af, 3674 struct node_host *src_host, struct node_port *src_port, 3675 struct node_host *dst_host, struct node_port *dst_port, 3676 u_int8_t proto) 3677{ 3678 expand_label_if("$if", label, len, ifname); 3679 expand_label_addr("$srcaddr", label, len, af, src_host); 3680 expand_label_addr("$dstaddr", label, len, af, dst_host); 3681 expand_label_port("$srcport", label, len, src_port); 3682 expand_label_port("$dstport", label, len, dst_port); 3683 expand_label_proto("$proto", label, len, proto); 3684 expand_label_nr("$nr", label, len); 3685} 3686 3687int 3688expand_altq(struct pf_altq *a, struct node_if *interfaces, 3689 struct node_queue *nqueues, struct node_queue_bw bwspec, 3690 struct node_queue_opt *opts) 3691{ 3692 struct pf_altq pa, pb; 3693 char qname[PF_QNAME_SIZE]; 3694 struct node_queue *n; 3695 struct node_queue_bw bw; 3696 int errs = 0; 3697 3698 if ((pf->loadopt & PFCTL_FLAG_ALTQ) == 0) { 3699 FREE_LIST(struct node_if, interfaces); 3700 FREE_LIST(struct node_queue, nqueues); 3701 return (0); 3702 } 3703 3704 LOOP_THROUGH(struct node_if, interface, interfaces, 3705 memcpy(&pa, a, sizeof(struct pf_altq)); 3706 if (strlcpy(pa.ifname, interface->ifname, 3707 sizeof(pa.ifname)) >= sizeof(pa.ifname)) 3708 errx(1, "expand_altq: strlcpy"); 3709 3710 if (interface->not) { 3711 yyerror("altq on ! <interface> is not supported"); 3712 errs++; 3713 } else { 3714 if (eval_pfaltq(pf, &pa, &bwspec, opts)) 3715 errs++; 3716 else 3717 if (pfctl_add_altq(pf, &pa)) 3718 errs++; 3719 3720 if (pf->opts & PF_OPT_VERBOSE) { 3721 print_altq(&pf->paltq->altq, 0, 3722 &bwspec, opts); 3723 if (nqueues && nqueues->tail) { 3724 printf("queue { "); 3725 LOOP_THROUGH(struct node_queue, queue, 3726 nqueues, 3727 printf("%s ", 3728 queue->queue); 3729 ); 3730 printf("}"); 3731 } 3732 printf("\n"); 3733 } 3734 3735 if (pa.scheduler == ALTQT_CBQ || 3736 pa.scheduler == ALTQT_HFSC) { 3737 /* now create a root queue */ 3738 memset(&pb, 0, sizeof(struct pf_altq)); 3739 if (strlcpy(qname, "root_", sizeof(qname)) >= 3740 sizeof(qname)) 3741 errx(1, "expand_altq: strlcpy"); 3742 if (strlcat(qname, interface->ifname, 3743 sizeof(qname)) >= sizeof(qname)) 3744 errx(1, "expand_altq: strlcat"); 3745 if (strlcpy(pb.qname, qname, 3746 sizeof(pb.qname)) >= sizeof(pb.qname)) 3747 errx(1, "expand_altq: strlcpy"); 3748 if (strlcpy(pb.ifname, interface->ifname, 3749 sizeof(pb.ifname)) >= sizeof(pb.ifname)) 3750 errx(1, "expand_altq: strlcpy"); 3751 pb.qlimit = pa.qlimit; 3752 pb.scheduler = pa.scheduler; 3753 bw.bw_absolute = pa.ifbandwidth; 3754 bw.bw_percent = 0; 3755 if (eval_pfqueue(pf, &pb, &bw, opts)) 3756 errs++; 3757 else 3758 if (pfctl_add_altq(pf, &pb)) 3759 errs++; 3760 } 3761 3762 LOOP_THROUGH(struct node_queue, queue, nqueues, 3763 n = calloc(1, sizeof(struct node_queue)); 3764 if (n == NULL) 3765 err(1, "expand_altq: calloc"); 3766 if (pa.scheduler == ALTQT_CBQ || 3767 pa.scheduler == ALTQT_HFSC) 3768 if (strlcpy(n->parent, qname, 3769 sizeof(n->parent)) >= 3770 sizeof(n->parent)) 3771 errx(1, "expand_altq: strlcpy"); 3772 if (strlcpy(n->queue, queue->queue, 3773 sizeof(n->queue)) >= sizeof(n->queue)) 3774 errx(1, "expand_altq: strlcpy"); 3775 if (strlcpy(n->ifname, interface->ifname, 3776 sizeof(n->ifname)) >= sizeof(n->ifname)) 3777 errx(1, "expand_altq: strlcpy"); 3778 n->scheduler = pa.scheduler; 3779 n->next = NULL; 3780 n->tail = n; 3781 if (queues == NULL) 3782 queues = n; 3783 else { 3784 queues->tail->next = n; 3785 queues->tail = n; 3786 } 3787 ); 3788 } 3789 ); 3790 FREE_LIST(struct node_if, interfaces); 3791 FREE_LIST(struct node_queue, nqueues); 3792 3793 return (errs); 3794} 3795 3796int 3797expand_queue(struct pf_altq *a, struct node_if *interfaces, 3798 struct node_queue *nqueues, struct node_queue_bw bwspec, 3799 struct node_queue_opt *opts) 3800{ 3801 struct node_queue *n, *nq; 3802 struct pf_altq pa; 3803 u_int8_t found = 0; 3804 u_int8_t errs = 0; 3805 3806 if ((pf->loadopt & PFCTL_FLAG_ALTQ) == 0) { 3807 FREE_LIST(struct node_queue, nqueues); 3808 return (0); 3809 } 3810 3811 if (queues == NULL) { 3812 yyerror("queue %s has no parent", a->qname); 3813 FREE_LIST(struct node_queue, nqueues); 3814 return (1); 3815 } 3816 3817 LOOP_THROUGH(struct node_if, interface, interfaces, 3818 LOOP_THROUGH(struct node_queue, tqueue, queues, 3819 if (!strncmp(a->qname, tqueue->queue, PF_QNAME_SIZE) && 3820 (interface->ifname[0] == 0 || 3821 (!interface->not && !strncmp(interface->ifname, 3822 tqueue->ifname, IFNAMSIZ)) || 3823 (interface->not && strncmp(interface->ifname, 3824 tqueue->ifname, IFNAMSIZ)))) { 3825 /* found ourself in queues */ 3826 found++; 3827 3828 memcpy(&pa, a, sizeof(struct pf_altq)); 3829 3830 if (pa.scheduler != ALTQT_NONE && 3831 pa.scheduler != tqueue->scheduler) { 3832 yyerror("exactly one scheduler type " 3833 "per interface allowed"); 3834 return (1); 3835 } 3836 pa.scheduler = tqueue->scheduler; 3837 3838 /* scheduler dependent error checking */ 3839 switch (pa.scheduler) { 3840 case ALTQT_PRIQ: 3841 if (nqueues != NULL) { 3842 yyerror("priq queues cannot " 3843 "have child queues"); 3844 return (1); 3845 } 3846 if (bwspec.bw_absolute > 0 || 3847 bwspec.bw_percent < 100) { 3848 yyerror("priq doesn't take " 3849 "bandwidth"); 3850 return (1); 3851 } 3852 break; 3853 default: 3854 break; 3855 } 3856 3857 if (strlcpy(pa.ifname, tqueue->ifname, 3858 sizeof(pa.ifname)) >= sizeof(pa.ifname)) 3859 errx(1, "expand_queue: strlcpy"); 3860 if (strlcpy(pa.parent, tqueue->parent, 3861 sizeof(pa.parent)) >= sizeof(pa.parent)) 3862 errx(1, "expand_queue: strlcpy"); 3863 3864 if (eval_pfqueue(pf, &pa, &bwspec, opts)) 3865 errs++; 3866 else 3867 if (pfctl_add_altq(pf, &pa)) 3868 errs++; 3869 3870 for (nq = nqueues; nq != NULL; nq = nq->next) { 3871 if (!strcmp(a->qname, nq->queue)) { 3872 yyerror("queue cannot have " 3873 "itself as child"); 3874 errs++; 3875 continue; 3876 } 3877 n = calloc(1, 3878 sizeof(struct node_queue)); 3879 if (n == NULL) 3880 err(1, "expand_queue: calloc"); 3881 if (strlcpy(n->parent, a->qname, 3882 sizeof(n->parent)) >= 3883 sizeof(n->parent)) 3884 errx(1, "expand_queue strlcpy"); 3885 if (strlcpy(n->queue, nq->queue, 3886 sizeof(n->queue)) >= 3887 sizeof(n->queue)) 3888 errx(1, "expand_queue strlcpy"); 3889 if (strlcpy(n->ifname, tqueue->ifname, 3890 sizeof(n->ifname)) >= 3891 sizeof(n->ifname)) 3892 errx(1, "expand_queue strlcpy"); 3893 n->scheduler = tqueue->scheduler; 3894 n->next = NULL; 3895 n->tail = n; 3896 if (queues == NULL) 3897 queues = n; 3898 else { 3899 queues->tail->next = n; 3900 queues->tail = n; 3901 } 3902 } 3903 if ((pf->opts & PF_OPT_VERBOSE) && ( 3904 (found == 1 && interface->ifname[0] == 0) || 3905 (found > 0 && interface->ifname[0] != 0))) { 3906 print_queue(&pf->paltq->altq, 0, 3907 &bwspec, interface->ifname[0] != 0, 3908 opts); 3909 if (nqueues && nqueues->tail) { 3910 printf("{ "); 3911 LOOP_THROUGH(struct node_queue, 3912 queue, nqueues, 3913 printf("%s ", 3914 queue->queue); 3915 ); 3916 printf("}"); 3917 } 3918 printf("\n"); 3919 } 3920 } 3921 ); 3922 ); 3923 3924 FREE_LIST(struct node_queue, nqueues); 3925 FREE_LIST(struct node_if, interfaces); 3926 3927 if (!found) { 3928 yyerror("queue %s has no parent", a->qname); 3929 errs++; 3930 } 3931 3932 if (errs) 3933 return (1); 3934 else 3935 return (0); 3936} 3937 3938void 3939expand_rule(struct pf_rule *r, 3940 struct node_if *interfaces, struct node_host *rpool_hosts, 3941 struct node_proto *protos, struct node_os *src_oses, 3942 struct node_host *src_hosts, struct node_port *src_ports, 3943 struct node_host *dst_hosts, struct node_port *dst_ports, 3944 struct node_uid *uids, struct node_gid *gids, struct node_icmp *icmp_types) 3945{ 3946 sa_family_t af = r->af; 3947 int added = 0, error = 0; 3948 char ifname[IF_NAMESIZE]; 3949 char label[PF_RULE_LABEL_SIZE]; 3950 struct pf_pooladdr *pa; 3951 struct node_host *h; 3952 u_int8_t flags, flagset; 3953 3954 if (strlcpy(label, r->label, sizeof(label)) >= sizeof(label)) 3955 errx(1, "expand_rule: strlcpy"); 3956 flags = r->flags; 3957 flagset = r->flagset; 3958 3959 LOOP_THROUGH(struct node_if, interface, interfaces, 3960 LOOP_THROUGH(struct node_proto, proto, protos, 3961 LOOP_THROUGH(struct node_icmp, icmp_type, icmp_types, 3962 LOOP_THROUGH(struct node_host, src_host, src_hosts, 3963 LOOP_THROUGH(struct node_port, src_port, src_ports, 3964 LOOP_THROUGH(struct node_os, src_os, src_oses, 3965 LOOP_THROUGH(struct node_host, dst_host, dst_hosts, 3966 LOOP_THROUGH(struct node_port, dst_port, dst_ports, 3967 LOOP_THROUGH(struct node_uid, uid, uids, 3968 LOOP_THROUGH(struct node_gid, gid, gids, 3969 3970 r->af = af; 3971 /* for link-local IPv6 address, interface must match up */ 3972 if ((r->af && src_host->af && r->af != src_host->af) || 3973 (r->af && dst_host->af && r->af != dst_host->af) || 3974 (src_host->af && dst_host->af && 3975 src_host->af != dst_host->af) || 3976 (src_host->ifindex && dst_host->ifindex && 3977 src_host->ifindex != dst_host->ifindex) || 3978 (src_host->ifindex && if_nametoindex(interface->ifname) && 3979 src_host->ifindex != if_nametoindex(interface->ifname)) || 3980 (dst_host->ifindex && if_nametoindex(interface->ifname) && 3981 dst_host->ifindex != if_nametoindex(interface->ifname))) 3982 continue; 3983 if (!r->af && src_host->af) 3984 r->af = src_host->af; 3985 else if (!r->af && dst_host->af) 3986 r->af = dst_host->af; 3987 3988 if (if_indextoname(src_host->ifindex, ifname)) 3989 memcpy(r->ifname, ifname, sizeof(r->ifname)); 3990 else if (if_indextoname(dst_host->ifindex, ifname)) 3991 memcpy(r->ifname, ifname, sizeof(r->ifname)); 3992 else 3993 memcpy(r->ifname, interface->ifname, sizeof(r->ifname)); 3994 3995 if (strlcpy(r->label, label, sizeof(r->label)) >= 3996 sizeof(r->label)) 3997 errx(1, "expand_rule: strlcpy"); 3998 expand_label(r->label, PF_RULE_LABEL_SIZE, r->ifname, r->af, 3999 src_host, src_port, dst_host, dst_port, proto->proto); 4000 expand_label(r->tagname, PF_TAG_NAME_SIZE, r->ifname, r->af, 4001 src_host, src_port, dst_host, dst_port, proto->proto); 4002 expand_label(r->match_tagname, PF_TAG_NAME_SIZE, r->ifname, 4003 r->af, src_host, src_port, dst_host, dst_port, 4004 proto->proto); 4005 4006 error += check_netmask(src_host, r->af); 4007 error += check_netmask(dst_host, r->af); 4008 4009 r->ifnot = interface->not; 4010 r->proto = proto->proto; 4011 r->src.addr = src_host->addr; 4012 r->src.not = src_host->not; 4013 r->src.port[0] = src_port->port[0]; 4014 r->src.port[1] = src_port->port[1]; 4015 r->src.port_op = src_port->op; 4016 r->dst.addr = dst_host->addr; 4017 r->dst.not = dst_host->not; 4018 r->dst.port[0] = dst_port->port[0]; 4019 r->dst.port[1] = dst_port->port[1]; 4020 r->dst.port_op = dst_port->op; 4021 r->uid.op = uid->op; 4022 r->uid.uid[0] = uid->uid[0]; 4023 r->uid.uid[1] = uid->uid[1]; 4024 r->gid.op = gid->op; 4025 r->gid.gid[0] = gid->gid[0]; 4026 r->gid.gid[1] = gid->gid[1]; 4027 r->type = icmp_type->type; 4028 r->code = icmp_type->code; 4029 4030 if (r->proto && r->proto != IPPROTO_TCP) { 4031 r->flags = 0; 4032 r->flagset = 0; 4033 } else { 4034 r->flags = flags; 4035 r->flagset = flagset; 4036 } 4037 if (icmp_type->proto && r->proto != icmp_type->proto) { 4038 yyerror("icmp-type mismatch"); 4039 error++; 4040 } 4041 4042 if (src_os && src_os->os) { 4043 r->os_fingerprint = pfctl_get_fingerprint(src_os->os); 4044 if ((pf->opts & PF_OPT_VERBOSE2) && 4045 r->os_fingerprint == PF_OSFP_NOMATCH) 4046 fprintf(stderr, 4047 "warning: unknown '%s' OS fingerprint\n", 4048 src_os->os); 4049 } else { 4050 r->os_fingerprint = PF_OSFP_ANY; 4051 } 4052 4053 TAILQ_INIT(&r->rpool.list); 4054 for (h = rpool_hosts; h != NULL; h = h->next) { 4055 pa = calloc(1, sizeof(struct pf_pooladdr)); 4056 if (pa == NULL) 4057 err(1, "expand_rule: calloc"); 4058 pa->addr = h->addr; 4059 if (h->ifname != NULL) { 4060 if (strlcpy(pa->ifname, h->ifname, 4061 sizeof(pa->ifname)) >= 4062 sizeof(pa->ifname)) 4063 errx(1, "expand_rule: strlcpy"); 4064 } else 4065 pa->ifname[0] = 0; 4066 TAILQ_INSERT_TAIL(&r->rpool.list, pa, entries); 4067 } 4068 4069 if (rule_consistent(r) < 0 || error) 4070 yyerror("skipping rule due to errors"); 4071 else { 4072 r->nr = pf->rule_nr++; 4073 pfctl_add_rule(pf, r); 4074 added++; 4075 } 4076 4077 )))))))))); 4078 4079 FREE_LIST(struct node_if, interfaces); 4080 FREE_LIST(struct node_proto, protos); 4081 FREE_LIST(struct node_host, src_hosts); 4082 FREE_LIST(struct node_port, src_ports); 4083 FREE_LIST(struct node_os, src_oses); 4084 FREE_LIST(struct node_host, dst_hosts); 4085 FREE_LIST(struct node_port, dst_ports); 4086 FREE_LIST(struct node_uid, uids); 4087 FREE_LIST(struct node_gid, gids); 4088 FREE_LIST(struct node_icmp, icmp_types); 4089 FREE_LIST(struct node_host, rpool_hosts); 4090 4091 if (!added) 4092 yyerror("rule expands to no valid combination"); 4093} 4094 4095#undef FREE_LIST 4096#undef LOOP_THROUGH 4097 4098int 4099check_rulestate(int desired_state) 4100{ 4101 if (require_order && (rulestate > desired_state)) { 4102 yyerror("Rules must be in order: options, normalization, " 4103 "queueing, translation, filtering"); 4104 return (1); 4105 } 4106 rulestate = desired_state; 4107 return (0); 4108} 4109 4110int 4111kw_cmp(const void *k, const void *e) 4112{ 4113 return (strcmp(k, ((const struct keywords *)e)->k_name)); 4114} 4115 4116int 4117lookup(char *s) 4118{ 4119 /* this has to be sorted always */ 4120 static const struct keywords keywords[] = { 4121 { "all", ALL}, 4122 { "allow-opts", ALLOWOPTS}, 4123 { "altq", ALTQ}, 4124 { "anchor", ANCHOR}, 4125 { "antispoof", ANTISPOOF}, 4126 { "any", ANY}, 4127 { "bandwidth", BANDWIDTH}, 4128 { "binat", BINAT}, 4129 { "binat-anchor", BINATANCHOR}, 4130 { "bitmask", BITMASK}, 4131 { "block", BLOCK}, 4132 { "block-policy", BLOCKPOLICY}, 4133 { "cbq", CBQ}, 4134 { "code", CODE}, 4135 { "crop", FRAGCROP}, 4136 { "debug", DEBUG}, 4137 { "drop", DROP}, 4138 { "drop-ovl", FRAGDROP}, 4139 { "dup-to", DUPTO}, 4140 { "fastroute", FASTROUTE}, 4141 { "file", FILENAME}, 4142 { "fingerprints", FINGERPRINTS}, 4143 { "flags", FLAGS}, 4144 { "floating", FLOATING}, 4145 { "for", FOR}, 4146 { "fragment", FRAGMENT}, 4147 { "from", FROM}, 4148 { "global", GLOBAL}, 4149 { "group", GROUP}, 4150 { "group-bound", GRBOUND}, 4151 { "hfsc", HFSC}, 4152 { "hostid", HOSTID}, 4153 { "icmp-type", ICMPTYPE}, 4154 { "icmp6-type", ICMP6TYPE}, 4155 { "if-bound", IFBOUND}, 4156 { "in", IN}, 4157 { "inet", INET}, 4158 { "inet6", INET6}, 4159 { "keep", KEEP}, 4160 { "label", LABEL}, 4161 { "limit", LIMIT}, 4162 { "linkshare", LINKSHARE}, 4163 { "load", LOAD}, 4164 { "log", LOG}, 4165 { "log-all", LOGALL}, 4166 { "loginterface", LOGINTERFACE}, 4167 { "max", MAXIMUM}, 4168 { "max-mss", MAXMSS}, 4169 { "max-src-nodes", MAXSRCNODES}, 4170 { "max-src-states", MAXSRCSTATES}, 4171 { "min-ttl", MINTTL}, 4172 { "modulate", MODULATE}, 4173 { "nat", NAT}, 4174 { "nat-anchor", NATANCHOR}, 4175 { "no", NO}, 4176 { "no-df", NODF}, 4177 { "no-route", NOROUTE}, 4178 { "no-sync", NOSYNC}, 4179 { "on", ON}, 4180 { "optimization", OPTIMIZATION}, 4181 { "os", OS}, 4182 { "out", OUT}, 4183 { "pass", PASS}, 4184 { "port", PORT}, 4185 { "priority", PRIORITY}, 4186 { "priq", PRIQ}, 4187 { "proto", PROTO}, 4188 { "qlimit", QLIMIT}, 4189 { "queue", QUEUE}, 4190 { "quick", QUICK}, 4191 { "random", RANDOM}, 4192 { "random-id", RANDOMID}, 4193 { "rdr", RDR}, 4194 { "rdr-anchor", RDRANCHOR}, 4195 { "realtime", REALTIME}, 4196 { "reassemble", REASSEMBLE}, 4197 { "reply-to", REPLYTO}, 4198 { "require-order", REQUIREORDER}, 4199 { "return", RETURN}, 4200 { "return-icmp", RETURNICMP}, 4201 { "return-icmp6", RETURNICMP6}, 4202 { "return-rst", RETURNRST}, 4203 { "round-robin", ROUNDROBIN}, 4204 { "route-to", ROUTETO}, 4205 { "rule", RULE}, 4206 { "scrub", SCRUB}, 4207 { "set", SET}, 4208 { "source-hash", SOURCEHASH}, 4209 { "source-track", SOURCETRACK}, 4210 { "state", STATE}, 4211 { "state-policy", STATEPOLICY}, 4212 { "static-port", STATICPORT}, 4213 { "sticky-address", STICKYADDRESS}, 4214 { "synproxy", SYNPROXY}, 4215 { "table", TABLE}, 4216 { "tag", TAG}, 4217 { "tagged", TAGGED}, 4218 { "tbrsize", TBRSIZE}, 4219 { "timeout", TIMEOUT}, 4220 { "to", TO}, 4221 { "tos", TOS}, 4222 { "ttl", TTL}, 4223 { "upperlimit", UPPERLIMIT}, 4224 { "user", USER}, 4225 }; 4226 const struct keywords *p; 4227 4228 p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), 4229 sizeof(keywords[0]), kw_cmp); 4230 4231 if (p) { 4232 if (debug > 1) 4233 fprintf(stderr, "%s: %d\n", s, p->k_val); 4234 return (p->k_val); 4235 } else { 4236 if (debug > 1) 4237 fprintf(stderr, "string: %s\n", s); 4238 return (STRING); 4239 } 4240} 4241 4242#define MAXPUSHBACK 128 4243 4244char *parsebuf; 4245int parseindex; 4246char pushback_buffer[MAXPUSHBACK]; 4247int pushback_index = 0; 4248 4249int 4250lgetc(FILE *f) 4251{ 4252 int c, next; 4253 4254 if (parsebuf) { 4255 /* Read character from the parsebuffer instead of input. */ 4256 if (parseindex >= 0) { 4257 c = parsebuf[parseindex++]; 4258 if (c != '\0') 4259 return (c); 4260 parsebuf = NULL; 4261 } else 4262 parseindex++; 4263 } 4264 4265 if (pushback_index) 4266 return (pushback_buffer[--pushback_index]); 4267 4268 while ((c = getc(f)) == '\\') { 4269 next = getc(f); 4270 if (next != '\n') { 4271 if (isspace(next)) 4272 yyerror("whitespace after \\"); 4273 ungetc(next, f); 4274 break; 4275 } 4276 yylval.lineno = lineno; 4277 lineno++; 4278 } 4279 if (c == '\t' || c == ' ') { 4280 /* Compress blanks to a single space. */ 4281 do { 4282 c = getc(f); 4283 } while (c == '\t' || c == ' '); 4284 ungetc(c, f); 4285 c = ' '; 4286 } 4287 4288 return (c); 4289} 4290 4291int 4292lungetc(int c) 4293{ 4294 if (c == EOF) 4295 return (EOF); 4296 if (parsebuf) { 4297 parseindex--; 4298 if (parseindex >= 0) 4299 return (c); 4300 } 4301 if (pushback_index < MAXPUSHBACK-1) 4302 return (pushback_buffer[pushback_index++] = c); 4303 else 4304 return (EOF); 4305} 4306 4307int 4308findeol(void) 4309{ 4310 int c; 4311 4312 parsebuf = NULL; 4313 pushback_index = 0; 4314 4315 /* skip to either EOF or the first real EOL */ 4316 while (1) { 4317 c = lgetc(fin); 4318 if (c == '\n') { 4319 lineno++; 4320 break; 4321 } 4322 if (c == EOF) 4323 break; 4324 } 4325 return (ERROR); 4326} 4327 4328int 4329yylex(void) 4330{ 4331 char buf[8096]; 4332 char *p, *val; 4333 int endc, c, next; 4334 int token; 4335 4336top: 4337 p = buf; 4338 while ((c = lgetc(fin)) == ' ') 4339 ; /* nothing */ 4340 4341 yylval.lineno = lineno; 4342 if (c == '#') 4343 while ((c = lgetc(fin)) != '\n' && c != EOF) 4344 ; /* nothing */ 4345 if (c == '$' && parsebuf == NULL) { 4346 while (1) { 4347 if ((c = lgetc(fin)) == EOF) 4348 return (0); 4349 4350 if (p + 1 >= buf + sizeof(buf) - 1) { 4351 yyerror("string too long"); 4352 return (findeol()); 4353 } 4354 if (isalnum(c) || c == '_') { 4355 *p++ = (char)c; 4356 continue; 4357 } 4358 *p = '\0'; 4359 lungetc(c); 4360 break; 4361 } 4362 val = symget(buf); 4363 if (val == NULL) { 4364 yyerror("macro '%s' not defined", buf); 4365 return (findeol()); 4366 } 4367 parsebuf = val; 4368 parseindex = 0; 4369 goto top; 4370 } 4371 4372 switch (c) { 4373 case '\'': 4374 case '"': 4375 endc = c; 4376 while (1) { 4377 if ((c = lgetc(fin)) == EOF) 4378 return (0); 4379 if (c == endc) { 4380 *p = '\0'; 4381 break; 4382 } 4383 if (c == '\n') { 4384 lineno++; 4385 continue; 4386 } 4387 if (p + 1 >= buf + sizeof(buf) - 1) { 4388 yyerror("string too long"); 4389 return (findeol()); 4390 } 4391 *p++ = (char)c; 4392 } 4393 yylval.v.string = strdup(buf); 4394 if (yylval.v.string == NULL) 4395 err(1, "yylex: strdup"); 4396 return (STRING); 4397 case '<': 4398 next = lgetc(fin); 4399 if (next == '>') { 4400 yylval.v.i = PF_OP_XRG; 4401 return (PORTBINARY); 4402 } 4403 lungetc(next); 4404 break; 4405 case '>': 4406 next = lgetc(fin); 4407 if (next == '<') { 4408 yylval.v.i = PF_OP_IRG; 4409 return (PORTBINARY); 4410 } 4411 lungetc(next); 4412 break; 4413 case '-': 4414 next = lgetc(fin); 4415 if (next == '>') 4416 return (ARROW); 4417 lungetc(next); 4418 break; 4419 } 4420 4421#define allowed_in_string(x) \ 4422 (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ 4423 x != '{' && x != '}' && x != '<' && x != '>' && \ 4424 x != '!' && x != '=' && x != '/' && x != '#' && \ 4425 x != ',')) 4426 4427 if (isalnum(c) || c == ':' || c == '_') { 4428 do { 4429 *p++ = c; 4430 if ((unsigned)(p-buf) >= sizeof(buf)) { 4431 yyerror("string too long"); 4432 return (findeol()); 4433 } 4434 } while ((c = lgetc(fin)) != EOF && (allowed_in_string(c))); 4435 lungetc(c); 4436 *p = '\0'; 4437 token = lookup(buf); 4438 yylval.v.string = strdup(buf); 4439 if (yylval.v.string == NULL) 4440 err(1, "yylex: strdup"); 4441 return (token); 4442 } 4443 if (c == '\n') { 4444 yylval.lineno = lineno; 4445 lineno++; 4446 } 4447 if (c == EOF) 4448 return (0); 4449 return (c); 4450} 4451 4452int 4453parse_rules(FILE *input, struct pfctl *xpf) 4454{ 4455 struct sym *sym, *next; 4456 4457 fin = input; 4458 pf = xpf; 4459 lineno = 1; 4460 errors = 0; 4461 rulestate = PFCTL_STATE_NONE; 4462 returnicmpdefault = (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT; 4463 returnicmp6default = 4464 (ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT; 4465 blockpolicy = PFRULE_DROP; 4466 require_order = 1; 4467 4468 yyparse(); 4469 4470 /* Free macros and check which have not been used. */ 4471 for (sym = TAILQ_FIRST(&symhead); sym != NULL; sym = next) { 4472 next = TAILQ_NEXT(sym, entries); 4473 if ((pf->opts & PF_OPT_VERBOSE2) && !sym->used) 4474 fprintf(stderr, "warning: macro '%s' not " 4475 "used\n", sym->nam); 4476 free(sym->nam); 4477 free(sym->val); 4478 TAILQ_REMOVE(&symhead, sym, entries); 4479 free(sym); 4480 } 4481 4482 return (errors ? -1 : 0); 4483} 4484 4485/* 4486 * Over-designed efficiency is a French and German concept, so how about 4487 * we wait until they discover this ugliness and make it all fancy. 4488 */ 4489int 4490symset(const char *nam, const char *val, int persist) 4491{ 4492 struct sym *sym; 4493 4494 for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam); 4495 sym = TAILQ_NEXT(sym, entries)) 4496 ; /* nothing */ 4497 4498 if (sym != NULL) { 4499 if (sym->persist == 1) 4500 return (0); 4501 else { 4502 free(sym->nam); 4503 free(sym->val); 4504 TAILQ_REMOVE(&symhead, sym, entries); 4505 free(sym); 4506 } 4507 } 4508 if ((sym = calloc(1, sizeof(*sym))) == NULL) 4509 return (-1); 4510 4511 sym->nam = strdup(nam); 4512 if (sym->nam == NULL) { 4513 free(sym); 4514 return (-1); 4515 } 4516 sym->val = strdup(val); 4517 if (sym->val == NULL) { 4518 free(sym->nam); 4519 free(sym); 4520 return (-1); 4521 } 4522 sym->used = 0; 4523 sym->persist = persist; 4524 TAILQ_INSERT_TAIL(&symhead, sym, entries); 4525 return (0); 4526} 4527 4528int 4529pfctl_cmdline_symset(char *s) 4530{ 4531 char *sym, *val; 4532 int ret; 4533 4534 if ((val = strrchr(s, '=')) == NULL) 4535 return (-1); 4536 4537 if ((sym = malloc(strlen(s) - strlen(val) + 1)) == NULL) 4538 err(1, "pfctl_cmdline_symset: malloc"); 4539 4540 strlcpy(sym, s, strlen(s) - strlen(val) + 1); 4541 4542 ret = symset(sym, val + 1, 1); 4543 free(sym); 4544 4545 return (ret); 4546} 4547 4548char * 4549symget(const char *nam) 4550{ 4551 struct sym *sym; 4552 4553 TAILQ_FOREACH(sym, &symhead, entries) 4554 if (strcmp(nam, sym->nam) == 0) { 4555 sym->used = 1; 4556 return (sym->val); 4557 } 4558 return (NULL); 4559} 4560 4561void 4562decide_address_family(struct node_host *n, sa_family_t *af) 4563{ 4564 sa_family_t target_af = 0; 4565 4566 while (!*af && n != NULL) { 4567 if (n->af) { 4568 if (target_af == 0) 4569 target_af = n->af; 4570 if (target_af != n->af) 4571 return; 4572 } 4573 n = n->next; 4574 } 4575 if (!*af && target_af) 4576 *af = target_af; 4577} 4578 4579void 4580remove_invalid_hosts(struct node_host **nh, sa_family_t *af) 4581{ 4582 struct node_host *n = *nh, *prev = NULL; 4583 4584 while (n != NULL) { 4585 if (*af && n->af && n->af != *af) { 4586 /* unlink and free n */ 4587 struct node_host *next = n->next; 4588 4589 /* adjust tail pointer */ 4590 if (n == (*nh)->tail) 4591 (*nh)->tail = prev; 4592 /* adjust previous node's next pointer */ 4593 if (prev == NULL) 4594 *nh = next; 4595 else 4596 prev->next = next; 4597 /* free node */ 4598 if (n->ifname != NULL) 4599 free(n->ifname); 4600 free(n); 4601 n = next; 4602 } else { 4603 if (n->af && !*af) 4604 *af = n->af; 4605 prev = n; 4606 n = n->next; 4607 } 4608 } 4609} 4610 4611int 4612invalid_redirect(struct node_host *nh, sa_family_t af) 4613{ 4614 if (!af) { 4615 struct node_host *n; 4616 4617 /* tables and dyniftl are ok without an address family */ 4618 for (n = nh; n != NULL; n = n->next) { 4619 if (n->addr.type != PF_ADDR_TABLE && 4620 n->addr.type != PF_ADDR_DYNIFTL) { 4621 yyerror("address family not given and " 4622 "translation address expands to multiple " 4623 "address families"); 4624 return (1); 4625 } 4626 } 4627 } 4628 if (nh == NULL) { 4629 yyerror("no translation address with matching address family " 4630 "found."); 4631 return (1); 4632 } 4633 return (0); 4634} 4635 4636int 4637atoul(char *s, u_long *ulvalp) 4638{ 4639 u_long ulval; 4640 char *ep; 4641 4642 errno = 0; 4643 ulval = strtoul(s, &ep, 0); 4644 if (s[0] == '\0' || *ep != '\0') 4645 return (-1); 4646 if (errno == ERANGE && ulval == ULONG_MAX) 4647 return (-1); 4648 *ulvalp = ulval; 4649 return (0); 4650} 4651 4652int 4653getservice(char *n) 4654{ 4655 struct servent *s; 4656 u_long ulval; 4657 4658 if (atoul(n, &ulval) == 0) { 4659 if (ulval > 65535) { 4660 yyerror("illegal port value %d", ulval); 4661 return (-1); 4662 } 4663 return (htons(ulval)); 4664 } else { 4665 s = getservbyname(n, "tcp"); 4666 if (s == NULL) 4667 s = getservbyname(n, "udp"); 4668 if (s == NULL) { 4669 yyerror("unknown port %s", n); 4670 return (-1); 4671 } 4672 return (s->s_port); 4673 } 4674} 4675 4676int 4677rule_label(struct pf_rule *r, char *s) 4678{ 4679 if (s) { 4680 if (strlcpy(r->label, s, sizeof(r->label)) >= 4681 sizeof(r->label)) { 4682 yyerror("rule label too long (max %d chars)", 4683 sizeof(r->label)-1); 4684 return (-1); 4685 } 4686 } 4687 return (0); 4688} 4689 4690u_int16_t 4691parseicmpspec(char *w, sa_family_t af) 4692{ 4693 const struct icmpcodeent *p; 4694 u_long ulval; 4695 u_int8_t icmptype; 4696 4697 if (af == AF_INET) 4698 icmptype = returnicmpdefault >> 8; 4699 else 4700 icmptype = returnicmp6default >> 8; 4701 4702 if (atoul(w, &ulval) == -1) { 4703 if ((p = geticmpcodebyname(icmptype, w, af)) == NULL) { 4704 yyerror("unknown icmp code %s", w); 4705 return (0); 4706 } 4707 ulval = p->code; 4708 } 4709 if (ulval > 255) { 4710 yyerror("invalid icmp code %ld", ulval); 4711 return (0); 4712 } 4713 return (icmptype << 8 | ulval); 4714} 4715 4716int 4717pfctl_load_anchors(int dev, int opts, struct pfr_buffer *trans) 4718{ 4719 struct loadanchors *la; 4720 4721 TAILQ_FOREACH(la, &loadanchorshead, entries) { 4722 if (opts & PF_OPT_VERBOSE) 4723 fprintf(stderr, "\nLoading anchor %s:%s from %s\n", 4724 la->anchorname, la->rulesetname, la->filename); 4725 if (pfctl_rules(dev, la->filename, opts, la->anchorname, 4726 la->rulesetname, trans) == -1) 4727 return (-1); 4728 } 4729 4730 return (0); 4731} 4732 4733