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