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