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