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