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