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