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