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