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