parse.y revision 1.405
1/* $OpenBSD: parse.y,v 1.405 2003/08/09 14:56:48 cedric Exp $ */ 2 3/* 4 * Copyright (c) 2001 Markus Friedl. All rights reserved. 5 * Copyright (c) 2001 Daniel Hartmeier. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27%{ 28#include <sys/types.h> 29#include <sys/socket.h> 30#include <net/if.h> 31#include <netinet/in.h> 32#include <netinet/in_systm.h> 33#include <netinet/ip.h> 34#include <netinet/ip_icmp.h> 35#include <netinet/icmp6.h> 36#include <net/pfvar.h> 37#include <arpa/inet.h> 38#include <altq/altq.h> 39#include <altq/altq_cbq.h> 40#include <altq/altq_priq.h> 41#include <altq/altq_hfsc.h> 42 43#include <stdio.h> 44#include <stdlib.h> 45#include <netdb.h> 46#include <stdarg.h> 47#include <errno.h> 48#include <string.h> 49#include <ctype.h> 50#include <err.h> 51#include <pwd.h> 52#include <grp.h> 53#include <md5.h> 54 55#include "pfctl_parser.h" 56#include "pfctl.h" 57 58static struct pfctl *pf = NULL; 59static FILE *fin = NULL; 60static int debug = 0; 61static int lineno = 1; 62static int errors = 0; 63static int rulestate = 0; 64static u_int16_t returnicmpdefault = 65 (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT; 66static u_int16_t returnicmp6default = 67 (ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT; 68static int blockpolicy = PFRULE_DROP; 69static int require_order = 1; 70 71enum { 72 PFCTL_STATE_NONE, 73 PFCTL_STATE_OPTION, 74 PFCTL_STATE_SCRUB, 75 PFCTL_STATE_QUEUE, 76 PFCTL_STATE_NAT, 77 PFCTL_STATE_FILTER 78}; 79 80struct node_proto { 81 u_int8_t proto; 82 struct node_proto *next; 83 struct node_proto *tail; 84}; 85 86struct node_port { 87 u_int16_t port[2]; 88 u_int8_t op; 89 struct node_port *next; 90 struct node_port *tail; 91}; 92 93struct node_uid { 94 uid_t uid[2]; 95 u_int8_t op; 96 struct node_uid *next; 97 struct node_uid *tail; 98}; 99 100struct node_gid { 101 gid_t gid[2]; 102 u_int8_t op; 103 struct node_gid *next; 104 struct node_gid *tail; 105}; 106 107struct node_icmp { 108 u_int8_t code; 109 u_int8_t type; 110 u_int8_t proto; 111 struct node_icmp *next; 112 struct node_icmp *tail; 113}; 114 115enum { PF_STATE_OPT_MAX=0, PF_STATE_OPT_TIMEOUT=1 }; 116struct node_state_opt { 117 int type; 118 union { 119 u_int32_t max_states; 120 struct { 121 int number; 122 u_int32_t seconds; 123 } timeout; 124 } data; 125 struct node_state_opt *next; 126 struct node_state_opt *tail; 127}; 128 129struct peer { 130 struct node_host *host; 131 struct node_port *port; 132}; 133 134struct node_queue { 135 char queue[PF_QNAME_SIZE]; 136 char parent[PF_QNAME_SIZE]; 137 char ifname[IFNAMSIZ]; 138 int scheduler; 139 struct node_queue *next; 140 struct node_queue *tail; 141} *queues = NULL; 142 143struct node_qassign { 144 char *qname; 145 char *pqname; 146}; 147 148struct filter_opts { 149 int marker; 150#define FOM_FLAGS 0x01 151#define FOM_ICMP 0x02 152#define FOM_TOS 0x04 153#define FOM_KEEP 0x08 154 struct node_uid *uid; 155 struct node_gid *gid; 156 struct { 157 u_int8_t b1; 158 u_int8_t b2; 159 u_int16_t w; 160 u_int16_t w2; 161 } flags; 162 struct node_icmp *icmpspec; 163 u_int32_t tos; 164 struct { 165 int action; 166 struct node_state_opt *options; 167 } keep; 168 int fragment; 169 int allowopts; 170 char *label; 171 struct node_qassign queues; 172 char *tag; 173 char *match_tag; 174 u_int8_t match_tag_not; 175} filter_opts; 176 177struct antispoof_opts { 178 char *label; 179} antispoof_opts; 180 181struct scrub_opts { 182 int marker; 183#define SOM_MINTTL 0x01 184#define SOM_MAXMSS 0x02 185#define SOM_FRAGCACHE 0x04 186 int nodf; 187 int minttl; 188 int maxmss; 189 int fragcache; 190 int randomid; 191 int reassemble_tcp; 192} scrub_opts; 193 194struct queue_opts { 195 int marker; 196#define QOM_BWSPEC 0x01 197#define QOM_SCHEDULER 0x02 198#define QOM_PRIORITY 0x04 199#define QOM_TBRSIZE 0x08 200#define QOM_QLIMIT 0x10 201 struct node_queue_bw queue_bwspec; 202 struct node_queue_opt scheduler; 203 int priority; 204 int tbrsize; 205 int qlimit; 206} queue_opts; 207 208struct table_opts { 209 int flags; 210 int init_addr; 211 struct node_tinithead init_nodes; 212} table_opts; 213 214struct node_hfsc_opts hfsc_opts; 215 216int yyerror(const char *, ...); 217int disallow_table(struct node_host *, const char *); 218int rule_consistent(struct pf_rule *); 219int filter_consistent(struct pf_rule *); 220int nat_consistent(struct pf_rule *); 221int rdr_consistent(struct pf_rule *); 222int process_tabledef(char *, struct table_opts *); 223int yyparse(void); 224void expand_label_str(char *, const char *, const char *); 225void expand_label_if(const char *, char *, const char *); 226void expand_label_addr(const char *, char *, u_int8_t, struct node_host *); 227void expand_label_port(const char *, char *, struct node_port *); 228void expand_label_proto(const char *, char *, u_int8_t); 229void expand_label_nr(const char *, char *); 230void expand_label(char *, const char *, u_int8_t, struct node_host *, 231 struct node_port *, struct node_host *, struct node_port *, 232 u_int8_t); 233void expand_rule(struct pf_rule *, struct node_if *, struct node_host *, 234 struct node_proto *, struct node_host *, struct node_port *, 235 struct node_host *, struct node_port *, struct node_uid *, 236 struct node_gid *, struct node_icmp *); 237int expand_altq(struct pf_altq *, struct node_if *, struct node_queue *, 238 struct node_queue_bw bwspec, struct node_queue_opt *); 239int expand_queue(struct pf_altq *, struct node_if *, struct node_queue *, 240 struct node_queue_bw, struct node_queue_opt *); 241 242int check_rulestate(int); 243int kw_cmp(const void *, const void *); 244int lookup(char *); 245int lgetc(FILE *); 246int lungetc(int); 247int findeol(void); 248int yylex(void); 249int atoul(char *, u_long *); 250int getservice(char *); 251int rule_label(struct pf_rule *, char *); 252 253TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead); 254struct sym { 255 TAILQ_ENTRY(sym) entries; 256 int used; 257 int persist; 258 char *nam; 259 char *val; 260}; 261 262 263int symset(const char *, const char *, int); 264char *symget(const char *); 265 266void decide_address_family(struct node_host *, sa_family_t *); 267void remove_invalid_hosts(struct node_host **, sa_family_t *); 268int invalid_redirect(struct node_host *, sa_family_t); 269u_int16_t parseicmpspec(char *, sa_family_t); 270 271TAILQ_HEAD(loadanchorshead, loadanchors) loadanchorshead = 272 TAILQ_HEAD_INITIALIZER(loadanchorshead); 273struct loadanchors { 274 TAILQ_ENTRY(loadanchors) entries; 275 char *anchorname; 276 char *rulesetname; 277 char *filename; 278}; 279 280typedef struct { 281 union { 282 u_int32_t number; 283 int i; 284 char *string; 285 struct { 286 u_int8_t b1; 287 u_int8_t b2; 288 u_int16_t w; 289 u_int16_t w2; 290 } b; 291 struct range { 292 int a; 293 int b; 294 int t; 295 } range; 296 struct node_if *interface; 297 struct node_proto *proto; 298 struct node_icmp *icmp; 299 struct node_host *host; 300 struct node_port *port; 301 struct node_uid *uid; 302 struct node_gid *gid; 303 struct node_state_opt *state_opt; 304 struct peer peer; 305 struct { 306 struct peer src, dst; 307 } fromto; 308 struct pf_poolhashkey *hashkey; 309 struct { 310 struct node_host *host; 311 u_int8_t rt; 312 u_int8_t pool_opts; 313 sa_family_t af; 314 struct pf_poolhashkey *key; 315 } route; 316 struct redirection { 317 struct node_host *host; 318 struct range rport; 319 } *redirection; 320 struct { 321 int type; 322 struct pf_poolhashkey *key; 323 } pooltype; 324 struct { 325 int action; 326 struct node_state_opt *options; 327 } keep_state; 328 struct { 329 u_int8_t log; 330 u_int8_t quick; 331 } logquick; 332 struct node_queue *queue; 333 struct node_queue_opt queue_options; 334 struct node_queue_bw queue_bwspec; 335 struct node_qassign qassign; 336 struct filter_opts filter_opts; 337 struct antispoof_opts antispoof_opts; 338 struct queue_opts queue_opts; 339 struct scrub_opts scrub_opts; 340 struct table_opts table_opts; 341 struct node_hfsc_opts hfsc_opts; 342 } v; 343 int lineno; 344} YYSTYPE; 345 346#define PREPARE_ANCHOR_RULE(r, a) \ 347 do { \ 348 memset(&(r), 0, sizeof(r)); \ 349 if (strlcpy(r.anchorname, (a), \ 350 sizeof(r.anchorname)) >= \ 351 sizeof(r.anchorname)) { \ 352 yyerror("anchor name '%s' too long", \ 353 (a)); \ 354 YYERROR; \ 355 } \ 356 } while (0) 357 358%} 359 360%token PASS BLOCK SCRUB RETURN IN OUT LOG LOGALL QUICK ON FROM TO FLAGS 361%token RETURNRST RETURNICMP RETURNICMP6 PROTO INET INET6 ALL ANY ICMPTYPE 362%token ICMP6TYPE CODE KEEP MODULATE STATE PORT RDR NAT BINAT ARROW NODF 363%token MINTTL ERROR ALLOWOPTS FASTROUTE FILENAME ROUTETO DUPTO REPLYTO NO LABEL 364%token NOROUTE FRAGMENT USER GROUP MAXMSS MAXIMUM TTL TOS DROP TABLE 365%token REASSEMBLE FRAGDROP FRAGCROP ANCHOR NATANCHOR RDRANCHOR BINATANCHOR 366%token SET OPTIMIZATION TIMEOUT LIMIT LOGINTERFACE BLOCKPOLICY RANDOMID 367%token REQUIREORDER SYNPROXY 368%token ANTISPOOF FOR 369%token BITMASK RANDOM SOURCEHASH ROUNDROBIN STATICPORT 370%token ALTQ CBQ PRIQ HFSC BANDWIDTH TBRSIZE LINKSHARE REALTIME UPPERLIMIT 371%token QUEUE PRIORITY QLIMIT 372%token LOAD 373%token TAGGED TAG 374%token <v.string> STRING 375%token <v.i> PORTBINARY 376%type <v.interface> interface if_list if_item_not if_item 377%type <v.number> number icmptype icmp6type uid gid 378%type <v.number> tos not yesno natpass 379%type <v.i> no dir log af fragcache 380%type <v.i> staticport unaryop 381%type <v.b> action nataction flags flag blockspec 382%type <v.range> port rport 383%type <v.hashkey> hashkey 384%type <v.pooltype> pooltype 385%type <v.proto> proto proto_list proto_item 386%type <v.icmp> icmpspec 387%type <v.icmp> icmp_list icmp_item 388%type <v.icmp> icmp6_list icmp6_item 389%type <v.fromto> fromto 390%type <v.peer> ipportspec from to 391%type <v.host> ipspec xhost host dynaddr host_list 392%type <v.host> redir_host_list redirspec 393%type <v.host> route_host route_host_list routespec 394%type <v.port> portspec port_list port_item 395%type <v.uid> uids uid_list uid_item 396%type <v.gid> gids gid_list gid_item 397%type <v.route> route 398%type <v.redirection> redirection redirpool 399%type <v.string> label string tag 400%type <v.keep_state> keep 401%type <v.state_opt> state_opt_spec state_opt_list state_opt_item 402%type <v.logquick> logquick 403%type <v.interface> antispoof_ifspc antispoof_iflst 404%type <v.qassign> qname 405%type <v.queue> qassign qassign_list qassign_item 406%type <v.queue_options> scheduler 407%type <v.number> cbqflags_list cbqflags_item 408%type <v.number> priqflags_list priqflags_item 409%type <v.hfsc_opts> hfscopts_list hfscopts_item hfsc_opts 410%type <v.queue_bwspec> bandwidth 411%type <v.filter_opts> filter_opts filter_opt filter_opts_l 412%type <v.antispoof_opts> antispoof_opts antispoof_opt antispoof_opts_l 413%type <v.queue_opts> queue_opts queue_opt queue_opts_l 414%type <v.scrub_opts> scrub_opts scrub_opt scrub_opts_l 415%type <v.table_opts> table_opts table_opt table_opts_l 416%% 417 418ruleset : /* empty */ 419 | ruleset '\n' 420 | ruleset option '\n' 421 | ruleset scrubrule '\n' 422 | ruleset natrule '\n' 423 | ruleset binatrule '\n' 424 | ruleset pfrule '\n' 425 | ruleset anchorrule '\n' 426 | ruleset loadrule '\n' 427 | ruleset altqif '\n' 428 | ruleset queuespec '\n' 429 | ruleset varset '\n' 430 | ruleset antispoof '\n' 431 | ruleset tabledef '\n' 432 | ruleset error '\n' { errors++; } 433 ; 434 435option : SET OPTIMIZATION STRING { 436 if (check_rulestate(PFCTL_STATE_OPTION)) 437 YYERROR; 438 if (pfctl_set_optimization(pf, $3) != 0) { 439 yyerror("unknown optimization %s", $3); 440 YYERROR; 441 } 442 } 443 | SET TIMEOUT timeout_spec 444 | SET TIMEOUT '{' timeout_list '}' 445 | SET LIMIT limit_spec 446 | SET LIMIT '{' limit_list '}' 447 | SET LOGINTERFACE STRING { 448 if (check_rulestate(PFCTL_STATE_OPTION)) 449 YYERROR; 450 if ((ifa_exists($3) == NULL) && strcmp($3, "none")) { 451 yyerror("interface %s doesn't exist", $3); 452 YYERROR; 453 } 454 if (pfctl_set_logif(pf, $3) != 0) { 455 yyerror("error setting loginterface %s", $3); 456 YYERROR; 457 } 458 } 459 | SET BLOCKPOLICY DROP { 460 if (pf->opts & PF_OPT_VERBOSE) 461 printf("set block-policy drop\n"); 462 if (check_rulestate(PFCTL_STATE_OPTION)) 463 YYERROR; 464 blockpolicy = PFRULE_DROP; 465 } 466 | SET BLOCKPOLICY RETURN { 467 if (pf->opts & PF_OPT_VERBOSE) 468 printf("set block-policy return\n"); 469 if (check_rulestate(PFCTL_STATE_OPTION)) 470 YYERROR; 471 blockpolicy = PFRULE_RETURN; 472 } 473 | SET REQUIREORDER yesno { 474 if (pf->opts & PF_OPT_VERBOSE) 475 printf("set require-order %s\n", 476 $3 == 1 ? "yes" : "no"); 477 require_order = $3; 478 } 479 ; 480 481string : string STRING { 482 if (asprintf(&$$, "%s %s", $1, $2) == -1) 483 err(1, "string: asprintf"); 484 free($1); 485 free($2); 486 } 487 | STRING 488 ; 489 490varset : STRING '=' string { 491 if (pf->opts & PF_OPT_VERBOSE) 492 printf("%s = \"%s\"\n", $1, $3); 493 if (symset($1, $3, 0) == -1) 494 err(1, "cannot store variable %s", $1); 495 } 496 ; 497 498anchorrule : ANCHOR string dir interface af proto fromto { 499 struct pf_rule r; 500 501 if (check_rulestate(PFCTL_STATE_FILTER)) 502 YYERROR; 503 504 PREPARE_ANCHOR_RULE(r, $2); 505 r.direction = $3; 506 r.af = $5; 507 508 decide_address_family($7.src.host, &r.af); 509 decide_address_family($7.dst.host, &r.af); 510 511 expand_rule(&r, $4, NULL, $6, 512 $7.src.host, $7.src.port, $7.dst.host, $7.dst.port, 513 0, 0, 0); 514 } 515 | NATANCHOR string interface af proto fromto { 516 struct pf_rule r; 517 518 if (check_rulestate(PFCTL_STATE_NAT)) 519 YYERROR; 520 521 PREPARE_ANCHOR_RULE(r, $2); 522 r.action = PF_NAT; 523 r.af = $4; 524 525 decide_address_family($6.src.host, &r.af); 526 decide_address_family($6.dst.host, &r.af); 527 528 expand_rule(&r, $3, NULL, $5, 529 $6.src.host, $6.src.port, $6.dst.host, $6.dst.port, 530 0, 0, 0); 531 } 532 | RDRANCHOR string interface af proto fromto { 533 struct pf_rule r; 534 535 if (check_rulestate(PFCTL_STATE_NAT)) 536 YYERROR; 537 538 PREPARE_ANCHOR_RULE(r, $2); 539 r.action = PF_RDR; 540 r.af = $4; 541 542 decide_address_family($6.src.host, &r.af); 543 decide_address_family($6.dst.host, &r.af); 544 545 if ($6.src.port != NULL) { 546 yyerror("source port parameter not supported" 547 " in rdr-anchor"); 548 YYERROR; 549 } 550 if ($6.dst.port != NULL) { 551 if ($6.dst.port->next != NULL) { 552 yyerror("destination port list " 553 "expansion not supported in " 554 "rdr-anchor"); 555 YYERROR; 556 } else if ($6.dst.port->op != PF_OP_EQ) { 557 yyerror("destination port operators" 558 " not supported in rdr-anchor"); 559 YYERROR; 560 } 561 r.dst.port[0] = $6.dst.port->port[0]; 562 r.dst.port[1] = $6.dst.port->port[1]; 563 r.dst.port_op = $6.dst.port->op; 564 } 565 566 expand_rule(&r, $3, NULL, $5, 567 $6.src.host, $6.src.port, $6.dst.host, $6.dst.port, 568 0, 0, 0); 569 } 570 | BINATANCHOR string interface af proto fromto { 571 struct pf_rule r; 572 573 if (check_rulestate(PFCTL_STATE_NAT)) 574 YYERROR; 575 576 PREPARE_ANCHOR_RULE(r, $2); 577 r.action = PF_BINAT; 578 r.af = $4; 579 if ($5 != NULL) { 580 if ($5->next != NULL) { 581 yyerror("proto list expansion" 582 " not supported in binat-anchor"); 583 YYERROR; 584 } 585 r.proto = $5->proto; 586 free($5); 587 } 588 589 if ($6.src.host != NULL || $6.src.port != NULL || 590 $6.dst.host != NULL || $6.dst.port != NULL) { 591 yyerror("fromto parameter not supported" 592 " in binat-anchor"); 593 YYERROR; 594 } 595 596 decide_address_family($6.src.host, &r.af); 597 decide_address_family($6.dst.host, &r.af); 598 599 pfctl_add_rule(pf, &r); 600 } 601 ; 602 603loadrule : LOAD ANCHOR string FROM string { 604 char *t; 605 struct loadanchors *loadanchor; 606 607 t = strsep(&$3, ":"); 608 if (*t == '\0' || *$3 == '\0') { 609 yyerror("anchor '%s' invalid\n", $3); 610 YYERROR; 611 } 612 if (strlen(t) >= PF_ANCHOR_NAME_SIZE) { 613 yyerror("anchorname %s too long, max %u\n", 614 t, PF_ANCHOR_NAME_SIZE - 1); 615 YYERROR; 616 } 617 if (strlen($3) >= PF_RULESET_NAME_SIZE) { 618 yyerror("rulesetname %s too long, max %u\n", 619 $3, PF_RULESET_NAME_SIZE - 1); 620 YYERROR; 621 } 622 623 loadanchor = calloc(1, sizeof(struct loadanchors)); 624 if (loadanchor == NULL) 625 err(1, "loadrule: calloc"); 626 if ((loadanchor->anchorname = strdup(t)) == NULL) 627 err(1, "loadrule: strdup"); 628 if ((loadanchor->rulesetname = strdup($3)) == NULL) 629 err(1, "loadrule: strdup"); 630 if ((loadanchor->filename = strdup($5)) == NULL) 631 err(1, "loadrule: strdup"); 632 633 TAILQ_INSERT_TAIL(&loadanchorshead, loadanchor, 634 entries); 635 636 free(t); /* not $3 */ 637 free($5); 638 }; 639 640scrubrule : SCRUB dir logquick interface af proto fromto scrub_opts 641 { 642 struct pf_rule r; 643 644 if (check_rulestate(PFCTL_STATE_SCRUB)) 645 YYERROR; 646 647 memset(&r, 0, sizeof(r)); 648 649 r.action = PF_SCRUB; 650 r.direction = $2; 651 652 r.log = $3.log; 653 if ($3.quick) { 654 yyerror("scrub rules do not support 'quick'"); 655 YYERROR; 656 } 657 658 if ($4) { 659 if ($4->not) { 660 yyerror("scrub rules do not support " 661 "'! <if>'"); 662 YYERROR; 663 } 664 } 665 r.af = $5; 666 if ($8.nodf) 667 r.rule_flag |= PFRULE_NODF; 668 if ($8.randomid) 669 r.rule_flag |= PFRULE_RANDOMID; 670 if ($8.reassemble_tcp) { 671 if (r.direction != PF_INOUT) { 672 yyerror("reassemble tcp rules can not " 673 "specify direction"); 674 YYERROR; 675 } 676 r.rule_flag |= PFRULE_REASSEMBLE_TCP; 677 } 678 if ($8.minttl) 679 r.min_ttl = $8.minttl; 680 if ($8.maxmss) 681 r.max_mss = $8.maxmss; 682 if ($8.fragcache) 683 r.rule_flag |= $8.fragcache; 684 685 expand_rule(&r, $4, NULL, $6, 686 $7.src.host, $7.src.port, $7.dst.host, $7.dst.port, 687 NULL, NULL, NULL); 688 } 689 ; 690 691scrub_opts : { 692 bzero(&scrub_opts, sizeof scrub_opts); 693 } 694 scrub_opts_l 695 { $$ = scrub_opts; } 696 | /* empty */ { 697 bzero(&scrub_opts, sizeof scrub_opts); 698 $$ = scrub_opts; 699 } 700 ; 701 702scrub_opts_l : scrub_opts_l scrub_opt 703 | scrub_opt 704 ; 705 706scrub_opt : NODF { 707 if (scrub_opts.nodf) { 708 yyerror("no-df cannot be respecified"); 709 YYERROR; 710 } 711 scrub_opts.nodf = 1; 712 } 713 | MINTTL number { 714 if (scrub_opts.marker & SOM_MINTTL) { 715 yyerror("min-ttl cannot be respecified"); 716 YYERROR; 717 } 718 if ($2 > 255) { 719 yyerror("illegal min-ttl value %d", $2); 720 YYERROR; 721 } 722 scrub_opts.marker |= SOM_MINTTL; 723 scrub_opts.minttl = $2; 724 } 725 | MAXMSS number { 726 if (scrub_opts.marker & SOM_MAXMSS) { 727 yyerror("max-mss cannot be respecified"); 728 YYERROR; 729 } 730 scrub_opts.marker |= SOM_MAXMSS; 731 scrub_opts.maxmss = $2; 732 } 733 | fragcache { 734 if (scrub_opts.marker & SOM_FRAGCACHE) { 735 yyerror("fragcache cannot be respecified"); 736 YYERROR; 737 } 738 scrub_opts.marker |= SOM_FRAGCACHE; 739 scrub_opts.fragcache = $1; 740 } 741 | REASSEMBLE STRING { 742 if (strcasecmp($2, "tcp") != 0) 743 YYERROR; 744 if (scrub_opts.reassemble_tcp) { 745 yyerror("reassemble tcp cannot be respecified"); 746 YYERROR; 747 } 748 scrub_opts.reassemble_tcp = 1; 749 } 750 | RANDOMID { 751 if (scrub_opts.randomid) { 752 yyerror("random-id cannot be respecified"); 753 YYERROR; 754 } 755 scrub_opts.randomid = 1; 756 } 757 ; 758 759fragcache : FRAGMENT REASSEMBLE { $$ = 0; /* default */ } 760 | FRAGMENT FRAGCROP { $$ = PFRULE_FRAGCROP; } 761 | FRAGMENT FRAGDROP { $$ = PFRULE_FRAGDROP; } 762 ; 763 764antispoof : ANTISPOOF logquick antispoof_ifspc af antispoof_opts { 765 struct pf_rule r; 766 struct node_host *h = NULL; 767 struct node_if *i, *j; 768 769 if (check_rulestate(PFCTL_STATE_FILTER)) 770 YYERROR; 771 772 for (i = $3; i; i = i->next) { 773 bzero(&r, sizeof(r)); 774 775 r.action = PF_DROP; 776 r.direction = PF_IN; 777 r.log = $2.log; 778 r.quick = $2.quick; 779 r.af = $4; 780 if (rule_label(&r, $5.label)) 781 YYERROR; 782 j = calloc(1, sizeof(struct node_if)); 783 if (j == NULL) 784 err(1, "antispoof: calloc"); 785 if (strlcpy(j->ifname, i->ifname, 786 sizeof(j->ifname)) >= sizeof(j->ifname)) { 787 free(j); 788 yyerror("interface name too long"); 789 YYERROR; 790 } 791 j->not = 1; 792 h = ifa_lookup(j->ifname, PFCTL_IFLOOKUP_NET); 793 794 expand_rule(&r, j, NULL, NULL, h, NULL, NULL, 795 NULL, NULL, NULL, NULL); 796 797 if ((i->ifa_flags & IFF_LOOPBACK) == 0) { 798 bzero(&r, sizeof(r)); 799 800 r.action = PF_DROP; 801 r.direction = PF_IN; 802 r.log = $2.log; 803 r.quick = $2.quick; 804 r.af = $4; 805 if (rule_label(&r, $5.label)) 806 YYERROR; 807 h = ifa_lookup(i->ifname, 808 PFCTL_IFLOOKUP_HOST); 809 expand_rule(&r, NULL, NULL, NULL, h, 810 NULL, NULL, NULL, NULL, NULL, NULL); 811 } 812 } 813 free($5.label); 814 } 815 ; 816 817antispoof_ifspc : FOR if_item { $$ = $2; } 818 | FOR '{' antispoof_iflst '}' { $$ = $3; } 819 ; 820 821antispoof_iflst : if_item { $$ = $1; } 822 | antispoof_iflst comma if_item { 823 $1->tail->next = $3; 824 $1->tail = $3; 825 $$ = $1; 826 } 827 ; 828 829antispoof_opts : { bzero(&antispoof_opts, sizeof antispoof_opts); } 830 antispoof_opts_l 831 { $$ = antispoof_opts; } 832 | /* empty */ { 833 bzero(&antispoof_opts, sizeof antispoof_opts); 834 $$ = antispoof_opts; 835 } 836 ; 837 838antispoof_opts_l : antispoof_opts_l antispoof_opt 839 | antispoof_opt 840 ; 841 842antispoof_opt : label { 843 if (antispoof_opts.label) { 844 yyerror("label cannot be redefined"); 845 YYERROR; 846 } 847 antispoof_opts.label = $1; 848 } 849 ; 850 851not : '!' { $$ = 1; } 852 | /* empty */ { $$ = 0; } 853 854tabledef : TABLE '<' STRING '>' table_opts { 855 struct node_host *h, *nh; 856 struct node_tinit *ti, *nti; 857 858 if (strlen($3) >= PF_TABLE_NAME_SIZE) { 859 yyerror("table name too long, max %d chars", 860 PF_TABLE_NAME_SIZE - 1); 861 YYERROR; 862 } 863 if (pf->loadopt & PFCTL_FLAG_TABLE) 864 if (process_tabledef($3, &$5)) 865 YYERROR; 866 for (ti = SIMPLEQ_FIRST(&$5.init_nodes); 867 ti != SIMPLEQ_END(&$5.init_nodes); ti = nti) { 868 if (ti->file) 869 free(ti->file); 870 for (h = ti->host; h != NULL; h = nh) { 871 nh = h->next; 872 free(h); 873 } 874 nti = SIMPLEQ_NEXT(ti, entries); 875 free (ti); 876 } 877 } 878 ; 879 880table_opts : { 881 bzero(&table_opts, sizeof table_opts); 882 SIMPLEQ_INIT(&table_opts.init_nodes); 883 } 884 table_opts_l 885 { $$ = table_opts; } 886 | /* empty */ 887 { 888 bzero(&table_opts, sizeof table_opts); 889 SIMPLEQ_INIT(&table_opts.init_nodes); 890 $$ = table_opts; 891 } 892 ; 893 894table_opts_l : table_opts_l table_opt 895 | table_opt 896 ; 897 898table_opt : STRING { 899 if (!strcmp($1, "const")) 900 table_opts.flags |= PFR_TFLAG_CONST; 901 else if (!strcmp($1, "persist")) 902 table_opts.flags |= PFR_TFLAG_PERSIST; 903 else 904 YYERROR; 905 } 906 | '{' '}' { table_opts.init_addr = 1; } 907 | '{' host_list '}' { 908 struct node_host *n; 909 struct node_tinit *ti; 910 911 for (n = $2; n != NULL; n = n->next) { 912 switch(n->addr.type) { 913 case PF_ADDR_ADDRMASK: 914 continue; /* ok */ 915 case PF_ADDR_DYNIFTL: 916 yyerror("dynamic addresses are not " 917 "permitted inside tables"); 918 break; 919 case PF_ADDR_TABLE: 920 yyerror("tables cannot contain tables"); 921 break; 922 case PF_ADDR_NOROUTE: 923 yyerror("\"no-route\" is not permitted " 924 "inside tables"); 925 break; 926 default: 927 yyerror("unknown address type %d", 928 n->addr.type); 929 } 930 YYERROR; 931 } 932 if (!(ti = calloc(1, sizeof(*ti)))) 933 err(1, "table_opt: calloc"); 934 ti->host = $2; 935 SIMPLEQ_INSERT_TAIL(&table_opts.init_nodes, ti, 936 entries); 937 table_opts.init_addr = 1; 938 } 939 | FILENAME STRING { 940 struct node_tinit *ti; 941 942 if (!(ti = calloc(1, sizeof(*ti)))) 943 err(1, "table_opt: calloc"); 944 ti->file = $2; 945 SIMPLEQ_INSERT_TAIL(&table_opts.init_nodes, ti, 946 entries); 947 table_opts.init_addr = 1; 948 } 949 ; 950 951altqif : ALTQ interface queue_opts QUEUE qassign { 952 struct pf_altq a; 953 954 if (check_rulestate(PFCTL_STATE_QUEUE)) 955 YYERROR; 956 957 memset(&a, 0, sizeof(a)); 958 if ($3.scheduler.qtype == ALTQT_NONE) { 959 yyerror("no scheduler specified!"); 960 YYERROR; 961 } 962 a.scheduler = $3.scheduler.qtype; 963 a.qlimit = $3.qlimit; 964 a.tbrsize = $3.tbrsize; 965 if ($5 == NULL) { 966 yyerror("no child queues specified"); 967 YYERROR; 968 } 969 if (expand_altq(&a, $2, $5, $3.queue_bwspec, 970 &$3.scheduler)) 971 YYERROR; 972 } 973 ; 974 975queuespec : QUEUE STRING interface queue_opts qassign { 976 struct pf_altq a; 977 978 if (check_rulestate(PFCTL_STATE_QUEUE)) 979 YYERROR; 980 981 memset(&a, 0, sizeof(a)); 982 983 if (strlcpy(a.qname, $2, sizeof(a.qname)) >= 984 sizeof(a.qname)) { 985 yyerror("queue name too long (max " 986 "%d chars)", PF_QNAME_SIZE-1); 987 YYERROR; 988 } 989 if ($4.tbrsize) { 990 yyerror("cannot specify tbrsize for queue"); 991 YYERROR; 992 } 993 if ($4.priority > 255) { 994 yyerror("priority out of range: max 255"); 995 YYERROR; 996 } 997 a.priority = $4.priority; 998 a.qlimit = $4.qlimit; 999 a.scheduler = $4.scheduler.qtype; 1000 if (expand_queue(&a, $3, $5, $4.queue_bwspec, 1001 &$4.scheduler)) 1002 YYERROR; 1003 } 1004 ; 1005 1006queue_opts : { 1007 bzero(&queue_opts, sizeof queue_opts); 1008 queue_opts.priority = DEFAULT_PRIORITY; 1009 queue_opts.qlimit = DEFAULT_QLIMIT; 1010 queue_opts.scheduler.qtype = ALTQT_NONE; 1011 queue_opts.queue_bwspec.bw_percent = 100; 1012 } 1013 queue_opts_l 1014 { $$ = queue_opts; } 1015 | /* empty */ { 1016 bzero(&queue_opts, sizeof queue_opts); 1017 queue_opts.priority = DEFAULT_PRIORITY; 1018 queue_opts.qlimit = DEFAULT_QLIMIT; 1019 queue_opts.scheduler.qtype = ALTQT_NONE; 1020 queue_opts.queue_bwspec.bw_percent = 100; 1021 $$ = queue_opts; 1022 } 1023 ; 1024 1025queue_opts_l : queue_opts_l queue_opt 1026 | queue_opt 1027 ; 1028 1029queue_opt : BANDWIDTH bandwidth { 1030 if (queue_opts.marker & QOM_BWSPEC) { 1031 yyerror("bandwidth cannot be respecified"); 1032 YYERROR; 1033 } 1034 queue_opts.marker |= QOM_BWSPEC; 1035 queue_opts.queue_bwspec = $2; 1036 } 1037 | PRIORITY number { 1038 if (queue_opts.marker & QOM_PRIORITY) { 1039 yyerror("priority cannot be respecified"); 1040 YYERROR; 1041 } 1042 if ($2 > 255) { 1043 yyerror("priority out of range: max 255"); 1044 YYERROR; 1045 } 1046 queue_opts.marker |= QOM_PRIORITY; 1047 queue_opts.priority = $2; 1048 } 1049 | QLIMIT number { 1050 if (queue_opts.marker & QOM_QLIMIT) { 1051 yyerror("qlimit cannot be respecified"); 1052 YYERROR; 1053 } 1054 if ($2 > 65535) { 1055 yyerror("qlimit out of range: max 65535"); 1056 YYERROR; 1057 } 1058 queue_opts.marker |= QOM_QLIMIT; 1059 queue_opts.qlimit = $2; 1060 } 1061 | scheduler { 1062 if (queue_opts.marker & QOM_SCHEDULER) { 1063 yyerror("scheduler cannot be respecified"); 1064 YYERROR; 1065 } 1066 queue_opts.marker |= QOM_SCHEDULER; 1067 queue_opts.scheduler = $1; 1068 } 1069 | TBRSIZE number { 1070 if (queue_opts.marker & QOM_TBRSIZE) { 1071 yyerror("tbrsize cannot be respecified"); 1072 YYERROR; 1073 } 1074 if ($2 > 65535) { 1075 yyerror("tbrsize too big: max 65535"); 1076 YYERROR; 1077 } 1078 queue_opts.marker |= QOM_TBRSIZE; 1079 queue_opts.tbrsize = $2; 1080 } 1081 ; 1082 1083bandwidth : STRING { 1084 double bps; 1085 char *cp; 1086 1087 $$.bw_percent = 0; 1088 1089 bps = strtod($1, &cp); 1090 if (cp != NULL) { 1091 if (!strcmp(cp, "b")) 1092 ; /* nothing */ 1093 else if (!strcmp(cp, "Kb")) 1094 bps *= 1000; 1095 else if (!strcmp(cp, "Mb")) 1096 bps *= 1000 * 1000; 1097 else if (!strcmp(cp, "Gb")) 1098 bps *= 1000 * 1000 * 1000; 1099 else if (!strcmp(cp, "%")) { 1100 if (bps < 0 || bps > 100) { 1101 yyerror("bandwidth spec " 1102 "out of range"); 1103 YYERROR; 1104 } 1105 $$.bw_percent = bps; 1106 bps = 0; 1107 } else { 1108 yyerror("unknown unit %s", cp); 1109 YYERROR; 1110 } 1111 } 1112 $$.bw_absolute = (u_int32_t)bps; 1113 } 1114 1115scheduler : CBQ { 1116 $$.qtype = ALTQT_CBQ; 1117 $$.data.cbq_opts.flags = 0; 1118 } 1119 | CBQ '(' cbqflags_list ')' { 1120 $$.qtype = ALTQT_CBQ; 1121 $$.data.cbq_opts.flags = $3; 1122 } 1123 | PRIQ { 1124 $$.qtype = ALTQT_PRIQ; 1125 $$.data.priq_opts.flags = 0; 1126 } 1127 | PRIQ '(' priqflags_list ')' { 1128 $$.qtype = ALTQT_PRIQ; 1129 $$.data.priq_opts.flags = $3; 1130 } 1131 | HFSC { 1132 $$.qtype = ALTQT_HFSC; 1133 bzero(&$$.data.hfsc_opts, 1134 sizeof(struct node_hfsc_opts)); 1135 } 1136 | HFSC '(' hfsc_opts ')' { 1137 $$.qtype = ALTQT_HFSC; 1138 $$.data.hfsc_opts = $3; 1139 } 1140 ; 1141 1142cbqflags_list : cbqflags_item { $$ |= $1; } 1143 | cbqflags_list comma cbqflags_item { $$ |= $3; } 1144 ; 1145 1146cbqflags_item : STRING { 1147 if (!strcmp($1, "default")) 1148 $$ = CBQCLF_DEFCLASS; 1149 else if (!strcmp($1, "borrow")) 1150 $$ = CBQCLF_BORROW; 1151 else if (!strcmp($1, "red")) 1152 $$ = CBQCLF_RED; 1153 else if (!strcmp($1, "ecn")) 1154 $$ = CBQCLF_RED|CBQCLF_ECN; 1155 else if (!strcmp($1, "rio")) 1156 $$ = CBQCLF_RIO; 1157 else { 1158 yyerror("unknown cbq flag \"%s\"", $1); 1159 YYERROR; 1160 } 1161 } 1162 ; 1163 1164priqflags_list : priqflags_item { $$ |= $1; } 1165 | priqflags_list comma priqflags_item { $$ |= $3; } 1166 ; 1167 1168priqflags_item : STRING { 1169 if (!strcmp($1, "default")) 1170 $$ = PRCF_DEFAULTCLASS; 1171 else if (!strcmp($1, "red")) 1172 $$ = PRCF_RED; 1173 else if (!strcmp($1, "ecn")) 1174 $$ = PRCF_RED|PRCF_ECN; 1175 else if (!strcmp($1, "rio")) 1176 $$ = PRCF_RIO; 1177 else { 1178 yyerror("unknown priq flag \"%s\"", $1); 1179 YYERROR; 1180 } 1181 } 1182 ; 1183 1184hfsc_opts : { 1185 bzero(&hfsc_opts, 1186 sizeof(struct node_hfsc_opts)); 1187 } 1188 hfscopts_list { 1189 $$ = hfsc_opts; 1190 } 1191 ; 1192 1193hfscopts_list : hfscopts_item 1194 | hfscopts_list comma hfscopts_item 1195 ; 1196 1197hfscopts_item : LINKSHARE bandwidth { 1198 if (hfsc_opts.linkshare.used) { 1199 yyerror("linkshare already specified"); 1200 YYERROR; 1201 } 1202 hfsc_opts.linkshare.m2 = $2; 1203 hfsc_opts.linkshare.used = 1; 1204 } 1205 | LINKSHARE '(' bandwidth number bandwidth ')' { 1206 if (hfsc_opts.linkshare.used) { 1207 yyerror("linkshare already specified"); 1208 YYERROR; 1209 } 1210 hfsc_opts.linkshare.m1 = $3; 1211 hfsc_opts.linkshare.d = $4; 1212 hfsc_opts.linkshare.m2 = $5; 1213 hfsc_opts.linkshare.used = 1; 1214 } 1215 | REALTIME bandwidth { 1216 if (hfsc_opts.realtime.used) { 1217 yyerror("realtime already specified"); 1218 YYERROR; 1219 } 1220 hfsc_opts.realtime.m2 = $2; 1221 hfsc_opts.realtime.used = 1; 1222 } 1223 | REALTIME '(' bandwidth number bandwidth ')' { 1224 if (hfsc_opts.realtime.used) { 1225 yyerror("realtime already specified"); 1226 YYERROR; 1227 } 1228 hfsc_opts.realtime.m1 = $3; 1229 hfsc_opts.realtime.d = $4; 1230 hfsc_opts.realtime.m2 = $5; 1231 hfsc_opts.realtime.used = 1; 1232 } 1233 | UPPERLIMIT bandwidth { 1234 if (hfsc_opts.upperlimit.used) { 1235 yyerror("upperlimit already specified"); 1236 YYERROR; 1237 } 1238 hfsc_opts.upperlimit.m2 = $2; 1239 hfsc_opts.upperlimit.used = 1; 1240 } 1241 | UPPERLIMIT '(' bandwidth number bandwidth ')' { 1242 if (hfsc_opts.upperlimit.used) { 1243 yyerror("upperlimit already specified"); 1244 YYERROR; 1245 } 1246 hfsc_opts.upperlimit.m1 = $3; 1247 hfsc_opts.upperlimit.d = $4; 1248 hfsc_opts.upperlimit.m2 = $5; 1249 hfsc_opts.upperlimit.used = 1; 1250 } 1251 | STRING { 1252 if (!strcmp($1, "default")) 1253 hfsc_opts.flags |= HFCF_DEFAULTCLASS; 1254 else if (!strcmp($1, "red")) 1255 hfsc_opts.flags |= HFCF_RED; 1256 else if (!strcmp($1, "ecn")) 1257 hfsc_opts.flags |= HFCF_RED|HFCF_ECN; 1258 else if (!strcmp($1, "rio")) 1259 hfsc_opts.flags |= HFCF_RIO; 1260 else { 1261 yyerror("unknown hfsc flag \"%s\"", $1); 1262 YYERROR; 1263 } 1264 } 1265 ; 1266 1267qassign : /* empty */ { $$ = NULL; } 1268 | qassign_item { $$ = $1; } 1269 | '{' qassign_list '}' { $$ = $2; } 1270 ; 1271 1272qassign_list : qassign_item { $$ = $1; } 1273 | qassign_list comma qassign_item { 1274 $1->tail->next = $3; 1275 $1->tail = $3; 1276 $$ = $1; 1277 } 1278 ; 1279 1280qassign_item : STRING { 1281 $$ = calloc(1, sizeof(struct node_queue)); 1282 if ($$ == NULL) 1283 err(1, "qassign_item: calloc"); 1284 if (strlcpy($$->queue, $1, sizeof($$->queue)) >= 1285 sizeof($$->queue)) { 1286 free($$); 1287 yyerror("queue name '%s' too long (max " 1288 "%d chars)", $1, sizeof($$->queue)-1); 1289 YYERROR; 1290 } 1291 $$->next = NULL; 1292 $$->tail = $$; 1293 } 1294 ; 1295 1296pfrule : action dir logquick interface route af proto fromto 1297 filter_opts 1298 { 1299 struct pf_rule r; 1300 struct node_state_opt *o; 1301 struct node_proto *proto; 1302 1303 if (check_rulestate(PFCTL_STATE_FILTER)) 1304 YYERROR; 1305 1306 memset(&r, 0, sizeof(r)); 1307 1308 r.action = $1.b1; 1309 switch ($1.b2) { 1310 case PFRULE_RETURNRST: 1311 r.rule_flag |= PFRULE_RETURNRST; 1312 r.return_ttl = $1.w; 1313 break; 1314 case PFRULE_RETURNICMP: 1315 r.rule_flag |= PFRULE_RETURNICMP; 1316 r.return_icmp = $1.w; 1317 r.return_icmp6 = $1.w2; 1318 break; 1319 case PFRULE_RETURN: 1320 r.rule_flag |= PFRULE_RETURN; 1321 r.return_icmp = $1.w; 1322 r.return_icmp6 = $1.w2; 1323 break; 1324 } 1325 r.direction = $2; 1326 r.log = $3.log; 1327 r.quick = $3.quick; 1328 1329 r.af = $6; 1330 if ($9.tag) 1331 if (strlcpy(r.tagname, $9.tag, 1332 PF_TAG_NAME_SIZE) > PF_TAG_NAME_SIZE) { 1333 yyerror("tag too long, max %u chars", 1334 PF_TAG_NAME_SIZE - 1); 1335 YYERROR; 1336 } 1337 if ($9.match_tag) 1338 if (strlcpy(r.match_tagname, $9.match_tag, 1339 PF_TAG_NAME_SIZE) > PF_TAG_NAME_SIZE) { 1340 yyerror("tag too long, max %u chars", 1341 PF_TAG_NAME_SIZE - 1); 1342 YYERROR; 1343 } 1344 r.match_tag_not = $9.match_tag_not; 1345 r.flags = $9.flags.b1; 1346 r.flagset = $9.flags.b2; 1347 if (rule_label(&r, $9.label)) 1348 YYERROR; 1349 free($9.label); 1350 if ($9.flags.b1 || $9.flags.b2) { 1351 for (proto = $7; proto != NULL && 1352 proto->proto != IPPROTO_TCP; 1353 proto = proto->next) 1354 ; /* nothing */ 1355 if (proto == NULL && $7 != NULL) { 1356 yyerror("flags only apply to tcp"); 1357 YYERROR; 1358 } 1359 } 1360 1361 r.tos = $9.tos; 1362 r.keep_state = $9.keep.action; 1363 o = $9.keep.options; 1364 while (o) { 1365 struct node_state_opt *p = o; 1366 1367 switch (o->type) { 1368 case PF_STATE_OPT_MAX: 1369 if (r.max_states) { 1370 yyerror("state option 'max' " 1371 "multiple definitions"); 1372 YYERROR; 1373 } 1374 r.max_states = o->data.max_states; 1375 break; 1376 case PF_STATE_OPT_TIMEOUT: 1377 if (r.timeout[o->data.timeout.number]) { 1378 yyerror("state timeout %s " 1379 "multiple definitions", 1380 pf_timeouts[o->data. 1381 timeout.number].name); 1382 YYERROR; 1383 } 1384 r.timeout[o->data.timeout.number] = 1385 o->data.timeout.seconds; 1386 } 1387 o = o->next; 1388 free(p); 1389 } 1390 1391 if ($9.fragment) 1392 r.rule_flag |= PFRULE_FRAGMENT; 1393 r.allow_opts = $9.allowopts; 1394 1395 decide_address_family($8.src.host, &r.af); 1396 decide_address_family($8.dst.host, &r.af); 1397 1398 if ($5.rt) { 1399 if (!r.direction) { 1400 yyerror("direction must be explicit " 1401 "with rules that specify routing"); 1402 YYERROR; 1403 } 1404 r.rt = $5.rt; 1405 r.rpool.opts = $5.pool_opts; 1406 if ($5.key != NULL) 1407 memcpy(&r.rpool.key, $5.key, 1408 sizeof(struct pf_poolhashkey)); 1409 } 1410 if (r.rt && r.rt != PF_FASTROUTE) { 1411 decide_address_family($5.host, &r.af); 1412 remove_invalid_hosts(&$5.host, &r.af); 1413 if ($5.host == NULL) { 1414 yyerror("no routing address with " 1415 "matching address family found."); 1416 YYERROR; 1417 } 1418 if ($5.host->next != NULL) { 1419 if (r.rpool.opts == PF_POOL_NONE) 1420 r.rpool.opts = 1421 PF_POOL_ROUNDROBIN; 1422 if (r.rpool.opts != 1423 PF_POOL_ROUNDROBIN) { 1424 yyerror("r.rpool.opts must " 1425 "be PF_POOL_ROUNDROBIN"); 1426 YYERROR; 1427 } 1428 } 1429 } 1430 if ($9.queues.qname != NULL) { 1431 if (strlcpy(r.qname, $9.queues.qname, 1432 sizeof(r.qname)) >= sizeof(r.qname)) { 1433 yyerror("rule qname too long (max " 1434 "%d chars)", sizeof(r.qname)-1); 1435 YYERROR; 1436 } 1437 free($9.queues.qname); 1438 } 1439 if ($9.queues.pqname != NULL) { 1440 if (strlcpy(r.pqname, $9.queues.pqname, 1441 sizeof(r.pqname)) >= sizeof(r.pqname)) { 1442 yyerror("rule pqname too long (max " 1443 "%d chars)", sizeof(r.pqname)-1); 1444 YYERROR; 1445 } 1446 free($9.queues.pqname); 1447 } 1448 1449 expand_rule(&r, $4, $5.host, $7, 1450 $8.src.host, $8.src.port, $8.dst.host, $8.dst.port, 1451 $9.uid, $9.gid, $9.icmpspec); 1452 } 1453 ; 1454 1455filter_opts : { bzero(&filter_opts, sizeof filter_opts); } 1456 filter_opts_l 1457 { $$ = filter_opts; } 1458 | /* empty */ { 1459 bzero(&filter_opts, sizeof filter_opts); 1460 $$ = filter_opts; 1461 } 1462 ; 1463 1464filter_opts_l : filter_opts_l filter_opt 1465 | filter_opt 1466 ; 1467 1468filter_opt : USER uids { 1469 if (filter_opts.uid) 1470 $2->tail->next = filter_opts.uid; 1471 filter_opts.uid = $2; 1472 } 1473 | GROUP gids { 1474 if (filter_opts.gid) 1475 $2->tail->next = filter_opts.gid; 1476 filter_opts.gid = $2; 1477 } 1478 | flags { 1479 if (filter_opts.marker & FOM_FLAGS) { 1480 yyerror("flags cannot be redefined"); 1481 YYERROR; 1482 } 1483 filter_opts.marker |= FOM_FLAGS; 1484 filter_opts.flags.b1 |= $1.b1; 1485 filter_opts.flags.b2 |= $1.b2; 1486 filter_opts.flags.w |= $1.w; 1487 filter_opts.flags.w2 |= $1.w2; 1488 } 1489 | icmpspec { 1490 if (filter_opts.marker & FOM_ICMP) { 1491 yyerror("icmp-type cannot be redefined"); 1492 YYERROR; 1493 } 1494 filter_opts.marker |= FOM_ICMP; 1495 filter_opts.icmpspec = $1; 1496 } 1497 | tos { 1498 if (filter_opts.marker & FOM_TOS) { 1499 yyerror("tos cannot be redefined"); 1500 YYERROR; 1501 } 1502 filter_opts.marker |= FOM_TOS; 1503 filter_opts.tos = $1; 1504 } 1505 | keep { 1506 if (filter_opts.marker & FOM_KEEP) { 1507 yyerror("modulate or keep cannot be redefined"); 1508 YYERROR; 1509 } 1510 filter_opts.marker |= FOM_KEEP; 1511 filter_opts.keep.action = $1.action; 1512 filter_opts.keep.options = $1.options; 1513 } 1514 | FRAGMENT { 1515 filter_opts.fragment = 1; 1516 } 1517 | ALLOWOPTS { 1518 filter_opts.allowopts = 1; 1519 } 1520 | label { 1521 if (filter_opts.label) { 1522 yyerror("label cannot be redefined"); 1523 YYERROR; 1524 } 1525 filter_opts.label = $1; 1526 } 1527 | qname { 1528 if (filter_opts.queues.qname) { 1529 yyerror("queue cannot be redefined"); 1530 YYERROR; 1531 } 1532 filter_opts.queues = $1; 1533 } 1534 | TAG string { 1535 filter_opts.tag = $2; 1536 } 1537 | not TAGGED string { 1538 filter_opts.match_tag = $3; 1539 filter_opts.match_tag_not = $1; 1540 } 1541 ; 1542 1543action : PASS { $$.b1 = PF_PASS; $$.b2 = $$.w = 0; } 1544 | BLOCK blockspec { $$ = $2; $$.b1 = PF_DROP; } 1545 ; 1546 1547blockspec : /* empty */ { 1548 $$.b2 = blockpolicy; 1549 $$.w = returnicmpdefault; 1550 $$.w2 = returnicmp6default; 1551 } 1552 | DROP { 1553 $$.b2 = PFRULE_DROP; 1554 $$.w = 0; 1555 $$.w2 = 0; 1556 } 1557 | RETURNRST { 1558 $$.b2 = PFRULE_RETURNRST; 1559 $$.w = 0; 1560 $$.w2 = 0; 1561 } 1562 | RETURNRST '(' TTL number ')' { 1563 $$.b2 = PFRULE_RETURNRST; 1564 $$.w = $4; 1565 $$.w2 = 0; 1566 } 1567 | RETURNICMP { 1568 $$.b2 = PFRULE_RETURNICMP; 1569 $$.w = returnicmpdefault; 1570 $$.w2 = returnicmp6default; 1571 } 1572 | RETURNICMP6 { 1573 $$.b2 = PFRULE_RETURNICMP; 1574 $$.w = returnicmpdefault; 1575 $$.w2 = returnicmp6default; 1576 } 1577 | RETURNICMP '(' STRING ')' { 1578 $$.b2 = PFRULE_RETURNICMP; 1579 if (!($$.w = parseicmpspec($3, AF_INET))) 1580 YYERROR; 1581 $$.w2 = returnicmp6default; 1582 } 1583 | RETURNICMP6 '(' STRING ')' { 1584 $$.b2 = PFRULE_RETURNICMP; 1585 $$.w = returnicmpdefault; 1586 if (!($$.w2 = parseicmpspec($3, AF_INET6))) 1587 YYERROR; 1588 } 1589 | RETURNICMP '(' STRING comma STRING ')' { 1590 $$.b2 = PFRULE_RETURNICMP; 1591 if (!($$.w = parseicmpspec($3, AF_INET))) 1592 YYERROR; 1593 if (!($$.w2 = parseicmpspec($5, AF_INET6))) 1594 YYERROR; 1595 } 1596 | RETURN { 1597 $$.b2 = PFRULE_RETURN; 1598 $$.w = returnicmpdefault; 1599 $$.w2 = returnicmp6default; 1600 } 1601 ; 1602 1603dir : /* empty */ { $$ = 0; } 1604 | IN { $$ = PF_IN; } 1605 | OUT { $$ = PF_OUT; } 1606 ; 1607 1608logquick : /* empty */ { $$.log = 0; $$.quick = 0; } 1609 | log { $$.log = $1; $$.quick = 0; } 1610 | QUICK { $$.log = 0; $$.quick = 1; } 1611 | log QUICK { $$.log = $1; $$.quick = 1; } 1612 | QUICK log { $$.log = $2; $$.quick = 1; } 1613 ; 1614 1615log : LOG { $$ = 1; } 1616 | LOGALL { $$ = 2; } 1617 ; 1618 1619interface : /* empty */ { $$ = NULL; } 1620 | ON if_item_not { $$ = $2; } 1621 | ON '{' if_list '}' { $$ = $3; } 1622 ; 1623 1624if_list : if_item_not { $$ = $1; } 1625 | if_list comma if_item_not { 1626 $1->tail->next = $3; 1627 $1->tail = $3; 1628 $$ = $1; 1629 } 1630 ; 1631 1632if_item_not : not if_item { $$ = $2; $$->not = $1; } 1633 ; 1634 1635if_item : STRING { 1636 struct node_host *n; 1637 1638 if ((n = ifa_exists($1)) == NULL) { 1639 yyerror("unknown interface %s", $1); 1640 YYERROR; 1641 } 1642 $$ = calloc(1, sizeof(struct node_if)); 1643 if ($$ == NULL) 1644 err(1, "if_item: calloc"); 1645 if (strlcpy($$->ifname, $1, sizeof($$->ifname)) >= 1646 sizeof($$->ifname)) { 1647 free($$); 1648 yyerror("interface name too long"); 1649 YYERROR; 1650 } 1651 $$->ifa_flags = n->ifa_flags; 1652 $$->not = 0; 1653 $$->next = NULL; 1654 $$->tail = $$; 1655 } 1656 ; 1657 1658af : /* empty */ { $$ = 0; } 1659 | INET { $$ = AF_INET; } 1660 | INET6 { $$ = AF_INET6; } 1661 1662proto : /* empty */ { $$ = NULL; } 1663 | PROTO proto_item { $$ = $2; } 1664 | PROTO '{' proto_list '}' { $$ = $3; } 1665 ; 1666 1667proto_list : proto_item { $$ = $1; } 1668 | proto_list comma proto_item { 1669 $1->tail->next = $3; 1670 $1->tail = $3; 1671 $$ = $1; 1672 } 1673 ; 1674 1675proto_item : STRING { 1676 u_int8_t pr; 1677 u_long ulval; 1678 1679 if (atoul($1, &ulval) == 0) { 1680 if (ulval > 255) { 1681 yyerror("protocol outside range"); 1682 YYERROR; 1683 } 1684 pr = (u_int8_t)ulval; 1685 } else { 1686 struct protoent *p; 1687 1688 p = getprotobyname($1); 1689 if (p == NULL) { 1690 yyerror("unknown protocol %s", $1); 1691 YYERROR; 1692 } 1693 pr = p->p_proto; 1694 } 1695 if (pr == 0) { 1696 yyerror("proto 0 cannot be used"); 1697 YYERROR; 1698 } 1699 $$ = calloc(1, sizeof(struct node_proto)); 1700 if ($$ == NULL) 1701 err(1, "proto_item: calloc"); 1702 $$->proto = pr; 1703 $$->next = NULL; 1704 $$->tail = $$; 1705 } 1706 ; 1707 1708fromto : ALL { 1709 $$.src.host = NULL; 1710 $$.src.port = NULL; 1711 $$.dst.host = NULL; 1712 $$.dst.port = NULL; 1713 } 1714 | from to { 1715 $$.src = $1; 1716 $$.dst = $2; 1717 } 1718 ; 1719 1720from : /* empty */ { 1721 $$.host = NULL; 1722 $$.port = NULL; 1723 } 1724 | FROM ipportspec { 1725 $$ = $2; 1726 } 1727 ; 1728 1729to : /* empty */ { 1730 $$.host = NULL; 1731 $$.port = NULL; 1732 } 1733 | TO ipportspec { 1734 $$ = $2; 1735 } 1736 ; 1737 1738ipportspec : ipspec { 1739 $$.host = $1; 1740 $$.port = NULL; 1741 } 1742 | ipspec PORT portspec { 1743 $$.host = $1; 1744 $$.port = $3; 1745 } 1746 | PORT portspec { 1747 $$.host = NULL; 1748 $$.port = $2; 1749 } 1750 ; 1751 1752ipspec : ANY { $$ = NULL; } 1753 | xhost { $$ = $1; } 1754 | '{' host_list '}' { $$ = $2; } 1755 ; 1756 1757host_list : xhost { $$ = $1; } 1758 | host_list comma xhost { 1759 if ($3 == NULL) 1760 $$ = $1; 1761 else if ($1 == NULL) 1762 $$ = $3; 1763 else { 1764 $1->tail->next = $3; 1765 $1->tail = $3->tail; 1766 $$ = $1; 1767 } 1768 } 1769 ; 1770 1771xhost : not host { 1772 struct node_host *n; 1773 1774 for (n = $2; n != NULL; n = n->next) 1775 n->not = $1; 1776 $$ = $2; 1777 } 1778 | NOROUTE { 1779 $$ = calloc(1, sizeof(struct node_host)); 1780 if ($$ == NULL) 1781 err(1, "xhost: calloc"); 1782 $$->addr.type = PF_ADDR_NOROUTE; 1783 $$->next = NULL; 1784 $$->tail = $$; 1785 } 1786 ; 1787 1788host : STRING { 1789 if (($$ = host($1)) == NULL) { 1790 /* error. "any" is handled elsewhere */ 1791 yyerror("could not parse host specification"); 1792 YYERROR; 1793 } 1794 1795 } 1796 | STRING '/' number { 1797 char *buf; 1798 1799 if (asprintf(&buf, "%s/%u", $1, $3) == -1) 1800 err(1, "host: asprintf"); 1801 if (($$ = host(buf)) == NULL) { 1802 /* error. "any" is handled elsewhere */ 1803 free(buf); 1804 yyerror("could not parse host specification"); 1805 YYERROR; 1806 } 1807 free(buf); 1808 } 1809 | dynaddr 1810 | dynaddr '/' number { 1811 struct node_host *n; 1812 1813 $$ = $1; 1814 for (n = $1; n != NULL; n = n->next) 1815 set_ipmask(n, $3); 1816 } 1817 | '<' STRING '>' { 1818 if (strlen($2) >= PF_TABLE_NAME_SIZE) { 1819 yyerror("table name '%s' too long"); 1820 YYERROR; 1821 } 1822 $$ = calloc(1, sizeof(struct node_host)); 1823 if ($$ == NULL) 1824 err(1, "host: calloc"); 1825 $$->addr.type = PF_ADDR_TABLE; 1826 if (strlcpy($$->addr.v.tblname, $2, 1827 sizeof($$->addr.v.tblname)) >= 1828 sizeof($$->addr.v.tblname)) 1829 errx(1, "host: strlcpy"); 1830 $$->next = NULL; 1831 $$->tail = $$; 1832 } 1833 ; 1834 1835number : STRING { 1836 u_long ulval; 1837 1838 if (atoul($1, &ulval) == -1) { 1839 yyerror("%s is not a number", $1); 1840 YYERROR; 1841 } else 1842 $$ = ulval; 1843 } 1844 ; 1845 1846dynaddr : '(' STRING ')' { 1847 if (ifa_exists($2) == NULL) { 1848 yyerror("interface %s does not exist", $2); 1849 YYERROR; 1850 } 1851 $$ = calloc(1, sizeof(struct node_host)); 1852 if ($$ == NULL) 1853 err(1, "address: calloc"); 1854 $$->af = 0; 1855 set_ipmask($$, 128); 1856 $$->addr.type = PF_ADDR_DYNIFTL; 1857 if (strlcpy($$->addr.v.ifname, $2, 1858 sizeof($$->addr.v.ifname)) >= 1859 sizeof($$->addr.v.ifname)) { 1860 free($$); 1861 yyerror("interface name too long"); 1862 YYERROR; 1863 } 1864 $$->next = NULL; 1865 $$->tail = $$; 1866 } 1867 ; 1868 1869portspec : port_item { $$ = $1; } 1870 | '{' port_list '}' { $$ = $2; } 1871 ; 1872 1873port_list : port_item { $$ = $1; } 1874 | port_list comma port_item { 1875 $1->tail->next = $3; 1876 $1->tail = $3; 1877 $$ = $1; 1878 } 1879 ; 1880 1881port_item : port { 1882 $$ = calloc(1, sizeof(struct node_port)); 1883 if ($$ == NULL) 1884 err(1, "port_item: calloc"); 1885 $$->port[0] = $1.a; 1886 $$->port[1] = $1.b; 1887 if ($1.t) 1888 $$->op = PF_OP_RRG; 1889 else 1890 $$->op = PF_OP_EQ; 1891 $$->next = NULL; 1892 $$->tail = $$; 1893 } 1894 | unaryop port { 1895 if ($2.t) { 1896 yyerror("':' cannot be used with an other " 1897 "port operator"); 1898 YYERROR; 1899 } 1900 $$ = calloc(1, sizeof(struct node_port)); 1901 if ($$ == NULL) 1902 err(1, "port_item: calloc"); 1903 $$->port[0] = $2.a; 1904 $$->port[1] = $2.b; 1905 $$->op = $1; 1906 $$->next = NULL; 1907 $$->tail = $$; 1908 } 1909 | port PORTBINARY port { 1910 if ($1.t || $3.t) { 1911 yyerror("':' cannot be used with an other " 1912 "port operator"); 1913 YYERROR; 1914 } 1915 $$ = calloc(1, sizeof(struct node_port)); 1916 if ($$ == NULL) 1917 err(1, "port_item: calloc"); 1918 $$->port[0] = $1.a; 1919 $$->port[1] = $3.a; 1920 $$->op = $2; 1921 $$->next = NULL; 1922 $$->tail = $$; 1923 } 1924 ; 1925 1926port : STRING { 1927 char *p = strchr($1, ':'); 1928 struct servent *s = NULL; 1929 u_long ulval; 1930 1931 if (p == NULL) { 1932 if (atoul($1, &ulval) == 0) { 1933 if (ulval > 65535) { 1934 yyerror("illegal port value %d", 1935 ulval); 1936 YYERROR; 1937 } 1938 $$.a = htons(ulval); 1939 } else { 1940 s = getservbyname($1, "tcp"); 1941 if (s == NULL) 1942 s = getservbyname($1, "udp"); 1943 if (s == NULL) { 1944 yyerror("unknown port %s", $1); 1945 YYERROR; 1946 } 1947 $$.a = s->s_port; 1948 } 1949 $$.b = 0; 1950 $$.t = 0; 1951 } else { 1952 int port[2]; 1953 1954 *p++ = 0; 1955 if ((port[0] = getservice($1)) == -1 || 1956 (port[1] = getservice(p)) == -1) 1957 YYERROR; 1958 $$.a = port[0]; 1959 $$.b = port[1]; 1960 $$.t = PF_OP_RRG; 1961 } 1962 } 1963 ; 1964 1965uids : uid_item { $$ = $1; } 1966 | '{' uid_list '}' { $$ = $2; } 1967 ; 1968 1969uid_list : uid_item { $$ = $1; } 1970 | uid_list comma uid_item { 1971 $1->tail->next = $3; 1972 $1->tail = $3; 1973 $$ = $1; 1974 } 1975 ; 1976 1977uid_item : uid { 1978 $$ = calloc(1, sizeof(struct node_uid)); 1979 if ($$ == NULL) 1980 err(1, "uid_item: calloc"); 1981 $$->uid[0] = $1; 1982 $$->uid[1] = $1; 1983 $$->op = PF_OP_EQ; 1984 $$->next = NULL; 1985 $$->tail = $$; 1986 } 1987 | unaryop uid { 1988 if ($2 == UID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) { 1989 yyerror("user unknown requires operator = or " 1990 "!="); 1991 YYERROR; 1992 } 1993 $$ = calloc(1, sizeof(struct node_uid)); 1994 if ($$ == NULL) 1995 err(1, "uid_item: calloc"); 1996 $$->uid[0] = $2; 1997 $$->uid[1] = $2; 1998 $$->op = $1; 1999 $$->next = NULL; 2000 $$->tail = $$; 2001 } 2002 | uid PORTBINARY uid { 2003 if ($1 == UID_MAX || $3 == UID_MAX) { 2004 yyerror("user unknown requires operator = or " 2005 "!="); 2006 YYERROR; 2007 } 2008 $$ = calloc(1, sizeof(struct node_uid)); 2009 if ($$ == NULL) 2010 err(1, "uid_item: calloc"); 2011 $$->uid[0] = $1; 2012 $$->uid[1] = $3; 2013 $$->op = $2; 2014 $$->next = NULL; 2015 $$->tail = $$; 2016 } 2017 ; 2018 2019uid : STRING { 2020 u_long ulval; 2021 2022 if (atoul($1, &ulval) == -1) { 2023 if (!strcmp($1, "unknown")) 2024 $$ = UID_MAX; 2025 else { 2026 struct passwd *pw; 2027 2028 if ((pw = getpwnam($1)) == NULL) { 2029 yyerror("unknown user %s", $1); 2030 YYERROR; 2031 } 2032 $$ = pw->pw_uid; 2033 } 2034 } else { 2035 if (ulval >= UID_MAX) { 2036 yyerror("illegal uid value %lu", ulval); 2037 YYERROR; 2038 } 2039 $$ = ulval; 2040 } 2041 } 2042 ; 2043 2044gids : gid_item { $$ = $1; } 2045 | '{' gid_list '}' { $$ = $2; } 2046 ; 2047 2048gid_list : gid_item { $$ = $1; } 2049 | gid_list comma gid_item { 2050 $1->tail->next = $3; 2051 $1->tail = $3; 2052 $$ = $1; 2053 } 2054 ; 2055 2056gid_item : gid { 2057 $$ = calloc(1, sizeof(struct node_gid)); 2058 if ($$ == NULL) 2059 err(1, "gid_item: calloc"); 2060 $$->gid[0] = $1; 2061 $$->gid[1] = $1; 2062 $$->op = PF_OP_EQ; 2063 $$->next = NULL; 2064 $$->tail = $$; 2065 } 2066 | unaryop gid { 2067 if ($2 == GID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) { 2068 yyerror("group unknown requires operator = or " 2069 "!="); 2070 YYERROR; 2071 } 2072 $$ = calloc(1, sizeof(struct node_gid)); 2073 if ($$ == NULL) 2074 err(1, "gid_item: calloc"); 2075 $$->gid[0] = $2; 2076 $$->gid[1] = $2; 2077 $$->op = $1; 2078 $$->next = NULL; 2079 $$->tail = $$; 2080 } 2081 | gid PORTBINARY gid { 2082 if ($1 == GID_MAX || $3 == GID_MAX) { 2083 yyerror("group unknown requires operator = or " 2084 "!="); 2085 YYERROR; 2086 } 2087 $$ = calloc(1, sizeof(struct node_gid)); 2088 if ($$ == NULL) 2089 err(1, "gid_item: calloc"); 2090 $$->gid[0] = $1; 2091 $$->gid[1] = $3; 2092 $$->op = $2; 2093 $$->next = NULL; 2094 $$->tail = $$; 2095 } 2096 ; 2097 2098gid : STRING { 2099 u_long ulval; 2100 2101 if (atoul($1, &ulval) == -1) { 2102 if (!strcmp($1, "unknown")) 2103 $$ = GID_MAX; 2104 else { 2105 struct group *grp; 2106 2107 if ((grp = getgrnam($1)) == NULL) { 2108 yyerror("unknown group %s", $1); 2109 YYERROR; 2110 } 2111 $$ = grp->gr_gid; 2112 } 2113 } else { 2114 if (ulval >= GID_MAX) { 2115 yyerror("illegal gid value %lu", ulval); 2116 YYERROR; 2117 } 2118 $$ = ulval; 2119 } 2120 } 2121 ; 2122 2123flag : STRING { 2124 int f; 2125 2126 if ((f = parse_flags($1)) < 0) { 2127 yyerror("bad flags %s", $1); 2128 YYERROR; 2129 } 2130 $$.b1 = f; 2131 } 2132 ; 2133 2134flags : FLAGS flag '/' flag { $$.b1 = $2.b1; $$.b2 = $4.b1; } 2135 | FLAGS '/' flag { $$.b1 = 0; $$.b2 = $3.b1; } 2136 ; 2137 2138icmpspec : ICMPTYPE icmp_item { $$ = $2; } 2139 | ICMPTYPE '{' icmp_list '}' { $$ = $3; } 2140 | ICMP6TYPE icmp6_item { $$ = $2; } 2141 | ICMP6TYPE '{' icmp6_list '}' { $$ = $3; } 2142 ; 2143 2144icmp_list : icmp_item { $$ = $1; } 2145 | icmp_list comma icmp_item { 2146 $1->tail->next = $3; 2147 $1->tail = $3; 2148 $$ = $1; 2149 } 2150 ; 2151 2152icmp6_list : icmp6_item { $$ = $1; } 2153 | icmp6_list comma icmp6_item { 2154 $1->tail->next = $3; 2155 $1->tail = $3; 2156 $$ = $1; 2157 } 2158 ; 2159 2160icmp_item : icmptype { 2161 $$ = calloc(1, sizeof(struct node_icmp)); 2162 if ($$ == NULL) 2163 err(1, "icmp_item: calloc"); 2164 $$->type = $1; 2165 $$->code = 0; 2166 $$->proto = IPPROTO_ICMP; 2167 $$->next = NULL; 2168 $$->tail = $$; 2169 } 2170 | icmptype CODE STRING { 2171 const struct icmpcodeent *p; 2172 u_long ulval; 2173 2174 if (atoul($3, &ulval) == 0) { 2175 if (ulval > 255) { 2176 yyerror("illegal icmp-code %d", ulval); 2177 YYERROR; 2178 } 2179 } else { 2180 if ((p = geticmpcodebyname($1-1, $3, 2181 AF_INET)) == NULL) { 2182 yyerror("unknown icmp-code %s", $3); 2183 YYERROR; 2184 } 2185 ulval = p->code; 2186 } 2187 $$ = calloc(1, sizeof(struct node_icmp)); 2188 if ($$ == NULL) 2189 err(1, "icmp_item: calloc"); 2190 $$->type = $1; 2191 $$->code = ulval + 1; 2192 $$->proto = IPPROTO_ICMP; 2193 $$->next = NULL; 2194 $$->tail = $$; 2195 } 2196 ; 2197 2198icmp6_item : icmp6type { 2199 $$ = calloc(1, sizeof(struct node_icmp)); 2200 if ($$ == NULL) 2201 err(1, "icmp_item: calloc"); 2202 $$->type = $1; 2203 $$->code = 0; 2204 $$->proto = IPPROTO_ICMPV6; 2205 $$->next = NULL; 2206 $$->tail = $$; 2207 } 2208 | icmp6type CODE STRING { 2209 const struct icmpcodeent *p; 2210 u_long ulval; 2211 2212 if (atoul($3, &ulval) == 0) { 2213 if (ulval > 255) { 2214 yyerror("illegal icmp6-code %ld", 2215 ulval); 2216 YYERROR; 2217 } 2218 } else { 2219 if ((p = geticmpcodebyname($1-1, $3, 2220 AF_INET6)) == NULL) { 2221 yyerror("unknown icmp6-code %s", $3); 2222 YYERROR; 2223 } 2224 ulval = p->code; 2225 } 2226 $$ = calloc(1, sizeof(struct node_icmp)); 2227 if ($$ == NULL) 2228 err(1, "icmp_item: calloc"); 2229 $$->type = $1; 2230 $$->code = ulval + 1; 2231 $$->proto = IPPROTO_ICMPV6; 2232 $$->next = NULL; 2233 $$->tail = $$; 2234 } 2235 ; 2236 2237icmptype : STRING { 2238 const struct icmptypeent *p; 2239 u_long ulval; 2240 2241 if (atoul($1, &ulval) == 0) { 2242 if (ulval > 255) { 2243 yyerror("illegal icmp-type %d", ulval); 2244 YYERROR; 2245 } 2246 $$ = ulval + 1; 2247 } else { 2248 if ((p = geticmptypebyname($1, AF_INET)) == 2249 NULL) { 2250 yyerror("unknown icmp-type %s", $1); 2251 YYERROR; 2252 } 2253 $$ = p->type + 1; 2254 } 2255 } 2256 ; 2257 2258icmp6type : STRING { 2259 const struct icmptypeent *p; 2260 u_long ulval; 2261 2262 if (atoul($1, &ulval) == 0) { 2263 if (ulval > 255) { 2264 yyerror("illegal icmp6-type %d", ulval); 2265 YYERROR; 2266 } 2267 $$ = ulval + 1; 2268 } else { 2269 if ((p = geticmptypebyname($1, AF_INET6)) == 2270 NULL) { 2271 yyerror("unknown icmp6-type %s", $1); 2272 YYERROR; 2273 } 2274 $$ = p->type + 1; 2275 } 2276 } 2277 ; 2278 2279tos : TOS STRING { 2280 if (!strcmp($2, "lowdelay")) 2281 $$ = IPTOS_LOWDELAY; 2282 else if (!strcmp($2, "throughput")) 2283 $$ = IPTOS_THROUGHPUT; 2284 else if (!strcmp($2, "reliability")) 2285 $$ = IPTOS_RELIABILITY; 2286 else if ($2[0] == '0' && $2[1] == 'x') 2287 $$ = strtoul($2, NULL, 16); 2288 else 2289 $$ = strtoul($2, NULL, 10); 2290 if (!$$ || $$ > 255) { 2291 yyerror("illegal tos value %s", $2); 2292 YYERROR; 2293 } 2294 } 2295 ; 2296 2297keep : KEEP STATE state_opt_spec { 2298 $$.action = PF_STATE_NORMAL; 2299 $$.options = $3; 2300 } 2301 | MODULATE STATE state_opt_spec { 2302 $$.action = PF_STATE_MODULATE; 2303 $$.options = $3; 2304 } 2305 | SYNPROXY STATE state_opt_spec { 2306 $$.action = PF_STATE_SYNPROXY; 2307 $$.options = $3; 2308 } 2309 ; 2310 2311state_opt_spec : '(' state_opt_list ')' { $$ = $2; } 2312 | /* empty */ { $$ = NULL; } 2313 ; 2314 2315state_opt_list : state_opt_item { $$ = $1; } 2316 | state_opt_list comma state_opt_item { 2317 $1->tail->next = $3; 2318 $1->tail = $3; 2319 $$ = $1; 2320 } 2321 ; 2322 2323state_opt_item : MAXIMUM number { 2324 $$ = calloc(1, sizeof(struct node_state_opt)); 2325 if ($$ == NULL) 2326 err(1, "state_opt_item: calloc"); 2327 $$->type = PF_STATE_OPT_MAX; 2328 $$->data.max_states = $2; 2329 $$->next = NULL; 2330 $$->tail = $$; 2331 } 2332 | STRING number { 2333 int i; 2334 2335 for (i = 0; pf_timeouts[i].name && 2336 strcmp(pf_timeouts[i].name, $1); ++i) 2337 ; /* nothing */ 2338 if (!pf_timeouts[i].name) { 2339 yyerror("illegal timeout name %s", $1); 2340 YYERROR; 2341 } 2342 if (strchr(pf_timeouts[i].name, '.') == NULL) { 2343 yyerror("illegal state timeout %s", $1); 2344 YYERROR; 2345 } 2346 $$ = calloc(1, sizeof(struct node_state_opt)); 2347 if ($$ == NULL) 2348 err(1, "state_opt_item: calloc"); 2349 $$->type = PF_STATE_OPT_TIMEOUT; 2350 $$->data.timeout.number = pf_timeouts[i].timeout; 2351 $$->data.timeout.seconds = $2; 2352 $$->next = NULL; 2353 $$->tail = $$; 2354 } 2355 ; 2356 2357label : LABEL STRING { 2358 if (($$ = strdup($2)) == NULL) 2359 err(1, "rule label strdup() failed"); 2360 } 2361 ; 2362 2363qname : QUEUE STRING { 2364 if (($$.qname = strdup($2)) == NULL) 2365 err(1, "qname strdup() failed"); 2366 } 2367 | QUEUE '(' STRING ')' { 2368 if (($$.qname = strdup($3)) == NULL) 2369 err(1, "qname strdup() failed"); 2370 } 2371 | QUEUE '(' STRING comma STRING ')' { 2372 if (($$.qname = strdup($3)) == NULL || 2373 ($$.pqname = strdup($5)) == NULL) 2374 err(1, "qname strdup() failed"); 2375 } 2376 ; 2377 2378no : /* empty */ { $$ = 0; } 2379 | NO { $$ = 1; } 2380 ; 2381 2382rport : STRING { 2383 char *p = strchr($1, ':'); 2384 2385 if (p == NULL) { 2386 if (($$.a = getservice($1)) == -1) 2387 YYERROR; 2388 $$.b = $$.t = 0; 2389 } else if (!strcmp(p+1, "*")) { 2390 *p = 0; 2391 if (($$.a = getservice($1)) == -1) 2392 YYERROR; 2393 $$.b = 0; 2394 $$.t = 1; 2395 } else { 2396 *p++ = 0; 2397 if (($$.a = getservice($1)) == -1 || 2398 ($$.b = getservice(p)) == -1) 2399 YYERROR; 2400 if ($$.a == $$.b) 2401 $$.b = 0; 2402 $$.t = 0; 2403 } 2404 } 2405 ; 2406 2407redirspec : host { $$ = $1; } 2408 | '{' redir_host_list '}' { $$ = $2; } 2409 ; 2410 2411redir_host_list : host { $$ = $1; } 2412 | redir_host_list comma host { 2413 $1->tail->next = $3; 2414 $1->tail = $3->tail; 2415 $$ = $1; 2416 } 2417 ; 2418 2419redirpool : /* empty */ { $$ = NULL; } 2420 | ARROW redirspec { 2421 $$ = calloc(1, sizeof(struct redirection)); 2422 if ($$ == NULL) 2423 err(1, "redirection: calloc"); 2424 $$->host = $2; 2425 $$->rport.a = $$->rport.b = $$->rport.t = 0; 2426 } 2427 | ARROW redirspec PORT rport { 2428 $$ = calloc(1, sizeof(struct redirection)); 2429 if ($$ == NULL) 2430 err(1, "redirection: calloc"); 2431 $$->host = $2; 2432 $$->rport = $4; 2433 } 2434 ; 2435 2436hashkey : /* empty */ 2437 { 2438 $$ = calloc(1, sizeof(struct pf_poolhashkey)); 2439 if ($$ == NULL) 2440 err(1, "hashkey: calloc"); 2441 $$->key32[0] = arc4random(); 2442 $$->key32[1] = arc4random(); 2443 $$->key32[2] = arc4random(); 2444 $$->key32[3] = arc4random(); 2445 } 2446 | string 2447 { 2448 if (!strncmp($1, "0x", 2)) { 2449 if (strlen($1) != 34) { 2450 yyerror("hex key must be 128 bits " 2451 "(32 hex digits) long"); 2452 YYERROR; 2453 } 2454 $$ = calloc(1, sizeof(struct pf_poolhashkey)); 2455 if ($$ == NULL) 2456 err(1, "hashkey: calloc"); 2457 2458 if (sscanf($1, "0x%8x%8x%8x%8x", 2459 &$$->key32[0], &$$->key32[1], 2460 &$$->key32[2], &$$->key32[3]) != 4) { 2461 free($$); 2462 yyerror("invalid hex key"); 2463 YYERROR; 2464 } 2465 } else { 2466 MD5_CTX context; 2467 2468 $$ = calloc(1, sizeof(struct pf_poolhashkey)); 2469 if ($$ == NULL) 2470 err(1, "hashkey: calloc"); 2471 MD5Init(&context); 2472 MD5Update(&context, (unsigned char *)$1, 2473 strlen($1)); 2474 MD5Final((unsigned char *)$$, &context); 2475 HTONL($$->key32[0]); 2476 HTONL($$->key32[1]); 2477 HTONL($$->key32[2]); 2478 HTONL($$->key32[3]); 2479 } 2480 } 2481 ; 2482 2483pooltype : /* empty */ 2484 { 2485 $$.type = PF_POOL_NONE; 2486 $$.key = NULL; 2487 } 2488 | BITMASK 2489 { 2490 $$.type = PF_POOL_BITMASK; 2491 $$.key = NULL; 2492 } 2493 | RANDOM 2494 { 2495 $$.type = PF_POOL_RANDOM; 2496 $$.key = NULL; 2497 } 2498 | SOURCEHASH hashkey 2499 { 2500 $$.type = PF_POOL_SRCHASH; 2501 $$.key = $2; 2502 } 2503 | ROUNDROBIN 2504 { 2505 $$.type = PF_POOL_ROUNDROBIN; 2506 $$.key = NULL; 2507 } 2508 ; 2509 2510staticport : /* empty */ { $$ = 0; } 2511 | STATICPORT { $$ = 1; } 2512 ; 2513 2514redirection : /* empty */ { $$ = NULL; } 2515 | ARROW host { 2516 $$ = calloc(1, sizeof(struct redirection)); 2517 if ($$ == NULL) 2518 err(1, "redirection: calloc"); 2519 $$->host = $2; 2520 $$->rport.a = $$->rport.b = $$->rport.t = 0; 2521 } 2522 | ARROW host PORT rport { 2523 $$ = calloc(1, sizeof(struct redirection)); 2524 if ($$ == NULL) 2525 err(1, "redirection: calloc"); 2526 $$->host = $2; 2527 $$->rport = $4; 2528 } 2529 ; 2530 2531natpass : /* empty */ { $$ = 0; } 2532 | PASS { $$ = 1; } 2533 ; 2534 2535nataction : no NAT natpass { 2536 $$.b2 = $$.w = 0; 2537 if ($1) 2538 $$.b1 = PF_NONAT; 2539 else 2540 $$.b1 = PF_NAT; 2541 $$.b2 = $3; 2542 } 2543 | no RDR natpass { 2544 $$.b2 = $$.w = 0; 2545 if ($1) 2546 $$.b1 = PF_NORDR; 2547 else 2548 $$.b1 = PF_RDR; 2549 $$.b2 = $3; 2550 } 2551 ; 2552 2553natrule : nataction interface af proto fromto tag redirpool pooltype 2554 staticport 2555 { 2556 struct pf_rule r; 2557 2558 if (check_rulestate(PFCTL_STATE_NAT)) 2559 YYERROR; 2560 2561 memset(&r, 0, sizeof(r)); 2562 2563 r.action = $1.b1; 2564 r.natpass = $1.b2; 2565 r.af = $3; 2566 2567 if (!r.af) { 2568 if ($5.src.host && $5.src.host->af && 2569 !$5.src.host->ifindex) 2570 r.af = $5.src.host->af; 2571 else if ($5.dst.host && $5.dst.host->af && 2572 !$5.dst.host->ifindex) 2573 r.af = $5.dst.host->af; 2574 } 2575 2576 if ($6 != NULL) 2577 if (strlcpy(r.tagname, $6, PF_TAG_NAME_SIZE) > 2578 PF_TAG_NAME_SIZE) { 2579 yyerror("tag too long, max %u chars", 2580 PF_TAG_NAME_SIZE - 1); 2581 YYERROR; 2582 } 2583 2584 if (r.action == PF_NONAT || r.action == PF_NORDR) { 2585 if ($7 != NULL) { 2586 yyerror("translation rule with 'no' " 2587 "does not need '->'"); 2588 YYERROR; 2589 } 2590 } else { 2591 if ($7 == NULL || $7->host == NULL) { 2592 yyerror("translation rule requires '-> " 2593 "address'"); 2594 YYERROR; 2595 } 2596 if (!r.af && ! $7->host->ifindex) 2597 r.af = $7->host->af; 2598 2599 remove_invalid_hosts(&$7->host, &r.af); 2600 if (invalid_redirect($7->host, r.af)) 2601 YYERROR; 2602 if (check_netmask($7->host, r.af)) 2603 YYERROR; 2604 2605 r.rpool.proxy_port[0] = ntohs($7->rport.a); 2606 2607 switch (r.action) { 2608 case PF_RDR: 2609 if (!$7->rport.b && $7->rport.t && 2610 $5.dst.port != NULL) { 2611 r.rpool.proxy_port[1] = 2612 ntohs($7->rport.a) + 2613 (ntohs($5.dst.port->port[1]) - 2614 ntohs($5.dst.port->port[0])); 2615 } else 2616 r.rpool.proxy_port[1] = 2617 ntohs($7->rport.b); 2618 break; 2619 case PF_NAT: 2620 r.rpool.proxy_port[1] = ntohs($7->rport.b); 2621 if (!r.rpool.proxy_port[0] && 2622 !r.rpool.proxy_port[1]) { 2623 r.rpool.proxy_port[0] = 2624 PF_NAT_PROXY_PORT_LOW; 2625 r.rpool.proxy_port[1] = 2626 PF_NAT_PROXY_PORT_HIGH; 2627 } else if (!r.rpool.proxy_port[1]) 2628 r.rpool.proxy_port[1] = 2629 r.rpool.proxy_port[0]; 2630 break; 2631 default: 2632 break; 2633 } 2634 2635 r.rpool.opts = $8.type; 2636 if (r.rpool.opts == PF_POOL_NONE) 2637 r.rpool.opts = PF_POOL_ROUNDROBIN; 2638 if (r.rpool.opts != PF_POOL_ROUNDROBIN) 2639 if (disallow_table($7->host, "tables " 2640 "are only supported in round-robin " 2641 "redirection pools")) 2642 YYERROR; 2643 if ($7->host->next) { 2644 if (r.rpool.opts != 2645 PF_POOL_ROUNDROBIN) { 2646 yyerror("only round-robin " 2647 "valid for multiple " 2648 "redirection addresses"); 2649 YYERROR; 2650 } 2651 } else { 2652 if ((r.af == AF_INET && 2653 unmask(&$7->host->addr.v.a.mask, 2654 r.af) == 32) || 2655 (r.af == AF_INET6 && 2656 unmask(&$7->host->addr.v.a.mask, 2657 r.af) == 128)) { 2658 r.rpool.opts = PF_POOL_NONE; 2659 } 2660 } 2661 } 2662 2663 if ($8.key != NULL) 2664 memcpy(&r.rpool.key, $8.key, 2665 sizeof(struct pf_poolhashkey)); 2666 2667 if ($9 != NULL) { 2668 if (r.action != PF_NAT) { 2669 yyerror("the 'static-port' option is " 2670 "only valid with nat rules"); 2671 YYERROR; 2672 } 2673 if (r.rpool.proxy_port[0] != 2674 PF_NAT_PROXY_PORT_LOW && 2675 r.rpool.proxy_port[1] != 2676 PF_NAT_PROXY_PORT_HIGH) { 2677 yyerror("the 'static-port' option can't" 2678 " be used when specifying a port" 2679 " range"); 2680 YYERROR; 2681 } 2682 r.rpool.proxy_port[0] = 0; 2683 r.rpool.proxy_port[1] = 0; 2684 } 2685 2686 expand_rule(&r, $2, $7 == NULL ? NULL : $7->host, $4, 2687 $5.src.host, $5.src.port, $5.dst.host, $5.dst.port, 2688 0, 0, 0); 2689 free($7); 2690 } 2691 ; 2692 2693binatrule : no BINAT natpass interface af proto FROM host TO ipspec tag 2694 redirection 2695 { 2696 struct pf_rule binat; 2697 struct pf_pooladdr *pa; 2698 2699 if (check_rulestate(PFCTL_STATE_NAT)) 2700 YYERROR; 2701 2702 memset(&binat, 0, sizeof(binat)); 2703 2704 if ($1) 2705 binat.action = PF_NOBINAT; 2706 else 2707 binat.action = PF_BINAT; 2708 binat.natpass = $3; 2709 binat.af = $5; 2710 if (!binat.af && $8 != NULL && $8->af) 2711 binat.af = $8->af; 2712 if (!binat.af && $10 != NULL && $10->af) 2713 binat.af = $10->af; 2714 if (!binat.af && $12 != NULL && $12->host) 2715 binat.af = $12->host->af; 2716 if (!binat.af) { 2717 yyerror("address family (inet/inet6) " 2718 "undefined"); 2719 YYERROR; 2720 } 2721 2722 if ($4 != NULL) { 2723 memcpy(binat.ifname, $4->ifname, 2724 sizeof(binat.ifname)); 2725 free($4); 2726 } 2727 if ($11 != NULL) 2728 if (strlcpy(binat.tagname, $11, 2729 PF_TAG_NAME_SIZE) > PF_TAG_NAME_SIZE) { 2730 yyerror("tag too long, max %u chars", 2731 PF_TAG_NAME_SIZE - 1); 2732 YYERROR; 2733 } 2734 2735 if ($6 != NULL) { 2736 binat.proto = $6->proto; 2737 free($6); 2738 } 2739 2740 if ($8 != NULL && disallow_table($8, "invalid use of " 2741 "table <%s> as the source address of a binat rule")) 2742 YYERROR; 2743 if ($12 != NULL && $12->host != NULL && disallow_table( 2744 $12->host, "invalid use of table <%s> as the " 2745 "redirect address of a binat rule")) 2746 YYERROR; 2747 2748 if ($8 != NULL) { 2749 if ($8->next) { 2750 yyerror("multiple binat ip addresses"); 2751 YYERROR; 2752 } 2753 if ($8->addr.type == PF_ADDR_DYNIFTL) 2754 $8->af = binat.af; 2755 if ($8->af != binat.af) { 2756 yyerror("binat ip versions must match"); 2757 YYERROR; 2758 } 2759 if (check_netmask($8, binat.af)) 2760 YYERROR; 2761 memcpy(&binat.src.addr, &$8->addr, 2762 sizeof(binat.src.addr)); 2763 free($8); 2764 } 2765 if ($10 != NULL) { 2766 if ($10->next) { 2767 yyerror("multiple binat ip addresses"); 2768 YYERROR; 2769 } 2770 if ($10->af != binat.af && $10->af) { 2771 yyerror("binat ip versions must match"); 2772 YYERROR; 2773 } 2774 if (check_netmask($10, binat.af)) 2775 YYERROR; 2776 memcpy(&binat.dst.addr, &$10->addr, 2777 sizeof(binat.dst.addr)); 2778 binat.dst.not = $10->not; 2779 free($10); 2780 } 2781 2782 if (binat.action == PF_NOBINAT) { 2783 if ($12 != NULL) { 2784 yyerror("'no binat' rule does not need" 2785 " '->'"); 2786 YYERROR; 2787 } 2788 } else { 2789 if ($12 == NULL || $12->host == NULL) { 2790 yyerror("'binat' rule requires" 2791 " '-> address'"); 2792 YYERROR; 2793 } 2794 2795 remove_invalid_hosts(&$12->host, &binat.af); 2796 if (invalid_redirect($12->host, binat.af)) 2797 YYERROR; 2798 if ($12->host->next != NULL) { 2799 yyerror("binat rule must redirect to " 2800 "a single address"); 2801 YYERROR; 2802 } 2803 if (check_netmask($12->host, binat.af)) 2804 YYERROR; 2805 2806 if (!PF_AZERO(&binat.src.addr.v.a.mask, 2807 binat.af) && 2808 !PF_AEQ(&binat.src.addr.v.a.mask, 2809 &$12->host->addr.v.a.mask, binat.af)) { 2810 yyerror("'binat' source mask and " 2811 "redirect mask must be the same"); 2812 YYERROR; 2813 } 2814 2815 TAILQ_INIT(&binat.rpool.list); 2816 pa = calloc(1, sizeof(struct pf_pooladdr)); 2817 if (pa == NULL) 2818 err(1, "binat: calloc"); 2819 pa->addr = $12->host->addr; 2820 pa->ifname[0] = 0; 2821 TAILQ_INSERT_TAIL(&binat.rpool.list, 2822 pa, entries); 2823 2824 free($12); 2825 } 2826 2827 pfctl_add_rule(pf, &binat); 2828 } 2829 ; 2830 2831tag : /* empty */ { $$ = NULL; } 2832 | TAG STRING { $$ = $2; } 2833 2834route_host : STRING { 2835 struct node_host *n; 2836 2837 $$ = calloc(1, sizeof(struct node_host)); 2838 if ($$ == NULL) 2839 err(1, "route_host: calloc"); 2840 if (($$->ifname = strdup($1)) == NULL) 2841 err(1, "routeto: strdup"); 2842 if ((n = ifa_exists($$->ifname)) == NULL) { 2843 yyerror("routeto: unknown interface %s", 2844 $$->ifname); 2845 YYERROR; 2846 } 2847 set_ipmask($$, 128); 2848 $$->next = NULL; 2849 $$->tail = $$; 2850 } 2851 | '(' STRING host ')' { 2852 struct node_host *n; 2853 2854 $$ = $3; 2855 if (($$->ifname = strdup($2)) == NULL) 2856 err(1, "routeto: strdup"); 2857 if ((n = ifa_exists($$->ifname)) == NULL) { 2858 yyerror("routeto: unknown interface %s", 2859 $$->ifname); 2860 YYERROR; 2861 } 2862 } 2863 ; 2864 2865route_host_list : route_host { $$ = $1; } 2866 | route_host_list comma route_host { 2867 if ($1->af == 0) 2868 $1->af = $3->af; 2869 if ($1->af != $3->af) { 2870 yyerror("all pool addresses must be in the " 2871 "same address family"); 2872 YYERROR; 2873 } 2874 $1->tail->next = $3; 2875 $1->tail = $3->tail; 2876 $$ = $1; 2877 } 2878 ; 2879 2880routespec : route_host { $$ = $1; } 2881 | '{' route_host_list '}' { $$ = $2; } 2882 ; 2883 2884route : /* empty */ { 2885 $$.host = NULL; 2886 $$.rt = 0; 2887 $$.pool_opts = 0; 2888 } 2889 | FASTROUTE { 2890 $$.host = NULL; 2891 $$.rt = PF_FASTROUTE; 2892 $$.pool_opts = 0; 2893 } 2894 | ROUTETO routespec pooltype { 2895 $$.host = $2; 2896 $$.rt = PF_ROUTETO; 2897 $$.pool_opts = $3.type; 2898 if ($3.key != NULL) 2899 $$.key = $3.key; 2900 } 2901 | REPLYTO routespec pooltype { 2902 $$.host = $2; 2903 $$.rt = PF_REPLYTO; 2904 $$.pool_opts = $3.type; 2905 if ($3.key != NULL) 2906 $$.key = $3.key; 2907 } 2908 | DUPTO routespec pooltype { 2909 $$.host = $2; 2910 $$.rt = PF_DUPTO; 2911 $$.pool_opts = $3.type; 2912 if ($3.key != NULL) 2913 $$.key = $3.key; 2914 } 2915 ; 2916 2917timeout_spec : STRING number 2918 { 2919 if (check_rulestate(PFCTL_STATE_OPTION)) 2920 YYERROR; 2921 if (pfctl_set_timeout(pf, $1, $2, 0) != 0) { 2922 yyerror("unknown timeout %s", $1); 2923 YYERROR; 2924 } 2925 } 2926 ; 2927 2928timeout_list : timeout_list comma timeout_spec 2929 | timeout_spec 2930 ; 2931 2932limit_spec : STRING number 2933 { 2934 if (check_rulestate(PFCTL_STATE_OPTION)) 2935 YYERROR; 2936 if (pfctl_set_limit(pf, $1, $2) != 0) { 2937 yyerror("unable to set limit %s %u", $1, $2); 2938 YYERROR; 2939 } 2940 } 2941 2942limit_list : limit_list comma limit_spec 2943 | limit_spec 2944 ; 2945 2946comma : ',' 2947 | /* empty */ 2948 ; 2949 2950yesno : NO { $$ = 0; } 2951 | STRING { 2952 if (!strcmp($1, "yes")) 2953 $$ = 1; 2954 else 2955 YYERROR; 2956 } 2957 2958unaryop : '=' { $$ = PF_OP_EQ; } 2959 | '!' '=' { $$ = PF_OP_NE; } 2960 | '<' '=' { $$ = PF_OP_LE; } 2961 | '<' { $$ = PF_OP_LT; } 2962 | '>' '=' { $$ = PF_OP_GE; } 2963 | '>' { $$ = PF_OP_GT; } 2964 ; 2965 2966%% 2967 2968int 2969yyerror(const char *fmt, ...) 2970{ 2971 va_list ap; 2972 extern char *infile; 2973 2974 errors = 1; 2975 va_start(ap, fmt); 2976 fprintf(stderr, "%s:%d: ", infile, yylval.lineno); 2977 vfprintf(stderr, fmt, ap); 2978 fprintf(stderr, "\n"); 2979 va_end(ap); 2980 return (0); 2981} 2982 2983int 2984disallow_table(struct node_host *h, const char *fmt) 2985{ 2986 for (; h != NULL; h = h->next) 2987 if (h->addr.type == PF_ADDR_TABLE) { 2988 yyerror(fmt, h->addr.v.tblname); 2989 return (1); 2990 } 2991 return (0); 2992} 2993 2994int 2995rule_consistent(struct pf_rule *r) 2996{ 2997 int problems = 0; 2998 2999 switch (r->action) { 3000 case PF_PASS: 3001 case PF_DROP: 3002 case PF_SCRUB: 3003 problems = filter_consistent(r); 3004 break; 3005 case PF_NAT: 3006 case PF_NONAT: 3007 problems = nat_consistent(r); 3008 break; 3009 case PF_RDR: 3010 case PF_NORDR: 3011 problems = rdr_consistent(r); 3012 break; 3013 case PF_BINAT: 3014 case PF_NOBINAT: 3015 default: 3016 break; 3017 } 3018 return (problems); 3019} 3020 3021int 3022filter_consistent(struct pf_rule *r) 3023{ 3024 int problems = 0; 3025 3026 if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP && 3027 (r->src.port_op || r->dst.port_op)) { 3028 yyerror("port only applies to tcp/udp"); 3029 problems++; 3030 } 3031 if (r->src.port_op == PF_OP_RRG || r->dst.port_op == PF_OP_RRG) { 3032 yyerror("the ':' port operator only applies to rdr"); 3033 problems++; 3034 } 3035 if (r->proto != IPPROTO_ICMP && r->proto != IPPROTO_ICMPV6 && 3036 (r->type || r->code)) { 3037 yyerror("icmp-type/code only applies to icmp"); 3038 problems++; 3039 } 3040 if (!r->af && (r->type || r->code)) { 3041 yyerror("must indicate address family with icmp-type/code"); 3042 problems++; 3043 } 3044 if ((r->proto == IPPROTO_ICMP && r->af == AF_INET6) || 3045 (r->proto == IPPROTO_ICMPV6 && r->af == AF_INET)) { 3046 yyerror("proto %s doesn't match address family %s", 3047 r->proto == IPPROTO_ICMP ? "icmp" : "icmp6", 3048 r->af == AF_INET ? "inet" : "inet6"); 3049 problems++; 3050 } 3051 if ((r->keep_state == PF_STATE_MODULATE || r->keep_state == 3052 PF_STATE_SYNPROXY) && r->proto && r->proto != IPPROTO_TCP) { 3053 yyerror("modulate/synproxy state can only be applied to " 3054 "TCP rules"); 3055 problems++; 3056 } 3057 if (r->allow_opts && r->action != PF_PASS) { 3058 yyerror("allow-opts can only be specified for pass rules"); 3059 problems++; 3060 } 3061 if (!r->af && (r->src.addr.type == PF_ADDR_DYNIFTL || 3062 r->dst.addr.type == PF_ADDR_DYNIFTL)) { 3063 yyerror("dynamic addresses require address family " 3064 "(inet/inet6)"); 3065 problems++; 3066 } 3067 if (r->rule_flag & PFRULE_FRAGMENT && (r->src.port_op || 3068 r->dst.port_op || r->flagset || r->type || r->code)) { 3069 yyerror("fragments can be filtered only on IP header fields"); 3070 problems++; 3071 } 3072 if (r->rule_flag & PFRULE_RETURNRST && r->proto != IPPROTO_TCP) { 3073 yyerror("return-rst can only be applied to TCP rules"); 3074 problems++; 3075 } 3076 if (r->action == PF_DROP && r->keep_state) { 3077 yyerror("keep state on block rules doesn't make sense"); 3078 problems++; 3079 } 3080 if ((r->tagname[0] || r->match_tagname[0]) && !r->keep_state && 3081 r->action == PF_PASS) { 3082 yyerror("tags cannot be used without keep state"); 3083 problems++; 3084 } 3085 return (-problems); 3086} 3087 3088int 3089nat_consistent(struct pf_rule *r) 3090{ 3091 int problems = 0; 3092 struct pf_pooladdr *pa; 3093 3094 if (r->src.port_op == PF_OP_RRG || r->dst.port_op == PF_OP_RRG) { 3095 yyerror("the ':' port operator only applies to rdr"); 3096 problems++; 3097 } 3098 if (!r->af) { 3099 TAILQ_FOREACH(pa, &r->rpool.list, entries) { 3100 if (pa->addr.type == PF_ADDR_DYNIFTL) { 3101 yyerror("dynamic addresses require " 3102 "address family (inet/inet6)"); 3103 problems++; 3104 break; 3105 } 3106 } 3107 } 3108 return (-problems); 3109} 3110 3111int 3112rdr_consistent(struct pf_rule *r) 3113{ 3114 int problems = 0; 3115 struct pf_pooladdr *pa; 3116 3117 if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP) { 3118 if (r->src.port_op) { 3119 yyerror("src port only applies to tcp/udp"); 3120 problems++; 3121 } 3122 if (r->dst.port_op) { 3123 yyerror("dst port only applies to tcp/udp"); 3124 problems++; 3125 } 3126 if (r->rpool.proxy_port[0]) { 3127 yyerror("rpool port only applies to tcp/udp"); 3128 problems++; 3129 } 3130 } 3131 if (r->dst.port_op && 3132 r->dst.port_op != PF_OP_EQ && r->dst.port_op != PF_OP_RRG) { 3133 yyerror("invalid port operator for rdr destination port"); 3134 problems++; 3135 } 3136 if (r->src.port_op == PF_OP_RRG) { 3137 yyerror("the ':' port operator only applies to rdr " 3138 "destination port"); 3139 problems++; 3140 } 3141 if (!r->af) { 3142 if (r->src.addr.type == PF_ADDR_DYNIFTL || 3143 r->dst.addr.type == PF_ADDR_DYNIFTL) { 3144 yyerror("dynamic addresses require address family " 3145 "(inet/inet6)"); 3146 problems++; 3147 } else { 3148 TAILQ_FOREACH(pa, &r->rpool.list, entries) { 3149 if (pa->addr.type == PF_ADDR_DYNIFTL) { 3150 yyerror("dynamic addresses require " 3151 "address family (inet/inet6)"); 3152 problems++; 3153 break; 3154 } 3155 } 3156 } 3157 } 3158 return (-problems); 3159} 3160 3161int 3162process_tabledef(char *name, struct table_opts *opts) 3163{ 3164 struct pfr_buffer ab; 3165 struct node_tinit *ti; 3166 3167 bzero(&ab, sizeof(ab)); 3168 ab.pfrb_type = PFRB_ADDRS; 3169 SIMPLEQ_FOREACH(ti, &opts->init_nodes, entries) { 3170 if (ti->file) 3171 if (pfr_buf_load(&ab, ti->file, 0, append_addr)) { 3172 if (errno) 3173 yyerror("cannot load \"%s\": %s", 3174 ti->file, strerror(errno)); 3175 else 3176 yyerror("file \"%s\" contains bad data", 3177 ti->file); 3178 goto _error; 3179 } 3180 if (ti->host) 3181 if (append_addr_host(&ab, ti->host, 0, 0)) { 3182 yyerror("cannot create address buffer: %s", 3183 strerror(errno)); 3184 goto _error; 3185 } 3186 } 3187 if (pf->opts & PF_OPT_VERBOSE) 3188 print_tabledef(name, opts->flags, opts->init_addr, 3189 &opts->init_nodes); 3190 if (!(pf->opts & PF_OPT_NOACTION) && 3191 pfctl_define_table(name, opts->flags, opts->init_addr, 3192 pf->anchor, pf->ruleset, &ab, pf->tticket)) { 3193 yyerror("cannot define table %s: %s", name, 3194 pfr_strerror(errno)); 3195 goto _error; 3196 } 3197 pf->tdirty = 1; 3198 pfr_buf_clear(&ab); 3199 return (0); 3200_error: 3201 pfr_buf_clear(&ab); 3202 return (-1); 3203} 3204 3205struct keywords { 3206 const char *k_name; 3207 int k_val; 3208}; 3209 3210/* macro gore, but you should've seen the prior indentation nightmare... */ 3211 3212#define FREE_LIST(T,r) \ 3213 do { \ 3214 T *p, *node = r; \ 3215 while (node != NULL) { \ 3216 p = node; \ 3217 node = node->next; \ 3218 free(p); \ 3219 } \ 3220 } while (0) 3221 3222#define LOOP_THROUGH(T,n,r,C) \ 3223 do { \ 3224 T *n; \ 3225 if (r == NULL) { \ 3226 r = calloc(1, sizeof(T)); \ 3227 if (r == NULL) \ 3228 err(1, "LOOP: calloc"); \ 3229 r->next = NULL; \ 3230 } \ 3231 n = r; \ 3232 while (n != NULL) { \ 3233 do { \ 3234 C; \ 3235 } while (0); \ 3236 n = n->next; \ 3237 } \ 3238 } while (0) 3239 3240void 3241expand_label_str(char *label, const char *srch, const char *repl) 3242{ 3243 char tmp[PF_RULE_LABEL_SIZE] = ""; 3244 char *p, *q; 3245 3246 p = q = label; 3247 while ((q = strstr(p, srch)) != NULL) { 3248 *q = '\0'; 3249 if ((strlcat(tmp, p, sizeof(tmp)) >= sizeof(tmp)) || 3250 (strlcat(tmp, repl, sizeof(tmp)) >= sizeof(tmp))) 3251 err(1, "expand_label: label too long"); 3252 q += strlen(srch); 3253 p = q; 3254 } 3255 if (strlcat(tmp, p, sizeof(tmp)) >= sizeof(tmp)) 3256 err(1, "expand_label: label too long"); 3257 strlcpy(label, tmp, PF_RULE_LABEL_SIZE); /* always fits */ 3258} 3259 3260void 3261expand_label_if(const char *name, char *label, const char *ifname) 3262{ 3263 if (strstr(label, name) != NULL) { 3264 if (!*ifname) 3265 expand_label_str(label, name, "any"); 3266 else 3267 expand_label_str(label, name, ifname); 3268 } 3269} 3270 3271void 3272expand_label_addr(const char *name, char *label, sa_family_t af, 3273 struct node_host *h) 3274{ 3275 char tmp[64], tmp_not[66]; 3276 3277 if (strstr(label, name) != NULL) { 3278 switch (h->addr.type) { 3279 case PF_ADDR_DYNIFTL: 3280 snprintf(tmp, sizeof(tmp), "(%s)", h->addr.v.ifname); 3281 break; 3282 case PF_ADDR_TABLE: 3283 snprintf(tmp, sizeof(tmp), "<%s>", h->addr.v.tblname); 3284 break; 3285 case PF_ADDR_NOROUTE: 3286 snprintf(tmp, sizeof(tmp), "no-route"); 3287 break; 3288 case PF_ADDR_ADDRMASK: 3289 if (!af || (PF_AZERO(&h->addr.v.a.addr, af) && 3290 PF_AZERO(&h->addr.v.a.mask, af))) 3291 snprintf(tmp, sizeof(tmp), "any"); 3292 else { 3293 char a[48]; 3294 int bits; 3295 3296 if (inet_ntop(af, &h->addr.v.a.addr, a, 3297 sizeof(a)) == NULL) 3298 snprintf(tmp, sizeof(tmp), "?"); 3299 else { 3300 bits = unmask(&h->addr.v.a.mask, af); 3301 if ((af == AF_INET && bits < 32) || 3302 (af == AF_INET6 && bits < 128)) 3303 snprintf(tmp, sizeof(tmp), 3304 "%s/%d", a, bits); 3305 else 3306 snprintf(tmp, sizeof(tmp), 3307 "%s", a); 3308 } 3309 } 3310 break; 3311 default: 3312 snprintf(tmp, sizeof(tmp), "?"); 3313 break; 3314 } 3315 3316 if (h->not) { 3317 snprintf(tmp_not, sizeof(tmp_not), "! %s", tmp); 3318 expand_label_str(label, name, tmp_not); 3319 } else 3320 expand_label_str(label, name, tmp); 3321 } 3322} 3323 3324void 3325expand_label_port(const char *name, char *label, struct node_port *port) 3326{ 3327 char a1[6], a2[6], op[13] = ""; 3328 3329 if (strstr(label, name) != NULL) { 3330 snprintf(a1, sizeof(a1), "%u", ntohs(port->port[0])); 3331 snprintf(a2, sizeof(a2), "%u", ntohs(port->port[1])); 3332 if (!port->op) 3333 ; 3334 else if (port->op == PF_OP_IRG) 3335 snprintf(op, sizeof(op), "%s><%s", a1, a2); 3336 else if (port->op == PF_OP_XRG) 3337 snprintf(op, sizeof(op), "%s<>%s", a1, a2); 3338 else if (port->op == PF_OP_EQ) 3339 snprintf(op, sizeof(op), "%s", a1); 3340 else if (port->op == PF_OP_NE) 3341 snprintf(op, sizeof(op), "!=%s", a1); 3342 else if (port->op == PF_OP_LT) 3343 snprintf(op, sizeof(op), "<%s", a1); 3344 else if (port->op == PF_OP_LE) 3345 snprintf(op, sizeof(op), "<=%s", a1); 3346 else if (port->op == PF_OP_GT) 3347 snprintf(op, sizeof(op), ">%s", a1); 3348 else if (port->op == PF_OP_GE) 3349 snprintf(op, sizeof(op), ">=%s", a1); 3350 expand_label_str(label, name, op); 3351 } 3352} 3353 3354void 3355expand_label_proto(const char *name, char *label, u_int8_t proto) 3356{ 3357 struct protoent *pe; 3358 char n[4]; 3359 3360 if (strstr(label, name) != NULL) { 3361 pe = getprotobynumber(proto); 3362 if (pe != NULL) 3363 expand_label_str(label, name, pe->p_name); 3364 else { 3365 snprintf(n, sizeof(n), "%u", proto); 3366 expand_label_str(label, name, n); 3367 } 3368 } 3369} 3370 3371void 3372expand_label_nr(const char *name, char *label) 3373{ 3374 char n[11]; 3375 3376 if (strstr(label, name) != NULL) { 3377 snprintf(n, sizeof(n), "%u", pf->rule_nr); 3378 expand_label_str(label, name, n); 3379 } 3380} 3381 3382void 3383expand_label(char *label, const char *ifname, sa_family_t af, 3384 struct node_host *src_host, struct node_port *src_port, 3385 struct node_host *dst_host, struct node_port *dst_port, 3386 u_int8_t proto) 3387{ 3388 expand_label_if("$if", label, ifname); 3389 expand_label_addr("$srcaddr", label, af, src_host); 3390 expand_label_addr("$dstaddr", label, af, dst_host); 3391 expand_label_port("$srcport", label, src_port); 3392 expand_label_port("$dstport", label, dst_port); 3393 expand_label_proto("$proto", label, proto); 3394 expand_label_nr("$nr", label); 3395} 3396 3397int 3398expand_altq(struct pf_altq *a, struct node_if *interfaces, 3399 struct node_queue *nqueues, struct node_queue_bw bwspec, 3400 struct node_queue_opt *opts) 3401{ 3402 struct pf_altq pa, pb; 3403 char qname[PF_QNAME_SIZE]; 3404 struct node_queue *n; 3405 struct node_queue_bw bw; 3406 int errs = 0; 3407 3408 if ((pf->loadopt & PFCTL_FLAG_ALTQ) == 0) { 3409 FREE_LIST(struct node_if, interfaces); 3410 FREE_LIST(struct node_queue, nqueues); 3411 return (0); 3412 } 3413 3414 LOOP_THROUGH(struct node_if, interface, interfaces, 3415 memcpy(&pa, a, sizeof(struct pf_altq)); 3416 if (strlcpy(pa.ifname, interface->ifname, 3417 sizeof(pa.ifname)) >= sizeof(pa.ifname)) 3418 errx(1, "expand_altq: strlcpy"); 3419 3420 if (interface->not) { 3421 yyerror("altq on ! <interface> is not supported"); 3422 errs++; 3423 } else { 3424 if (eval_pfaltq(pf, &pa, &bwspec, opts)) 3425 errs++; 3426 else 3427 if (pfctl_add_altq(pf, &pa)) 3428 errs++; 3429 3430 if (pf->opts & PF_OPT_VERBOSE) { 3431 print_altq(&pf->paltq->altq, 0, 3432 &bwspec, opts); 3433 if (nqueues && nqueues->tail) { 3434 printf("queue { "); 3435 LOOP_THROUGH(struct node_queue, queue, 3436 nqueues, 3437 printf("%s ", 3438 queue->queue); 3439 ); 3440 printf("}"); 3441 } 3442 printf("\n"); 3443 } 3444 3445 if (pa.scheduler == ALTQT_CBQ || 3446 pa.scheduler == ALTQT_HFSC) { 3447 /* now create a root queue */ 3448 memset(&pb, 0, sizeof(struct pf_altq)); 3449 if (strlcpy(qname, "root_", sizeof(qname)) >= 3450 sizeof(qname)) 3451 errx(1, "expand_altq: strlcpy"); 3452 if (strlcat(qname, interface->ifname, 3453 sizeof(qname)) >= sizeof(qname)) 3454 errx(1, "expand_altq: strlcat"); 3455 if (strlcpy(pb.qname, qname, 3456 sizeof(pb.qname)) >= sizeof(pb.qname)) 3457 errx(1, "expand_altq: strlcpy"); 3458 if (strlcpy(pb.ifname, interface->ifname, 3459 sizeof(pb.ifname)) >= sizeof(pb.ifname)) 3460 errx(1, "expand_altq: strlcpy"); 3461 pb.qlimit = pa.qlimit; 3462 pb.scheduler = pa.scheduler; 3463 bw.bw_absolute = pa.ifbandwidth; 3464 bw.bw_percent = 0; 3465 if (eval_pfqueue(pf, &pb, &bw, opts)) 3466 errs++; 3467 else 3468 if (pfctl_add_altq(pf, &pb)) 3469 errs++; 3470 } 3471 3472 LOOP_THROUGH(struct node_queue, queue, nqueues, 3473 n = calloc(1, sizeof(struct node_queue)); 3474 if (n == NULL) 3475 err(1, "expand_altq: calloc"); 3476 if (pa.scheduler == ALTQT_CBQ || 3477 pa.scheduler == ALTQT_HFSC) 3478 if (strlcpy(n->parent, qname, 3479 sizeof(n->parent)) >= 3480 sizeof(n->parent)) 3481 errx(1, "expand_altq: strlcpy"); 3482 if (strlcpy(n->queue, queue->queue, 3483 sizeof(n->queue)) >= sizeof(n->queue)) 3484 errx(1, "expand_altq: strlcpy"); 3485 if (strlcpy(n->ifname, interface->ifname, 3486 sizeof(n->ifname)) >= sizeof(n->ifname)) 3487 errx(1, "expand_altq: strlcpy"); 3488 n->scheduler = pa.scheduler; 3489 n->next = NULL; 3490 n->tail = n; 3491 if (queues == NULL) 3492 queues = n; 3493 else { 3494 queues->tail->next = n; 3495 queues->tail = n; 3496 } 3497 ); 3498 } 3499 ); 3500 FREE_LIST(struct node_if, interfaces); 3501 FREE_LIST(struct node_queue, nqueues); 3502 3503 return (errs); 3504} 3505 3506int 3507expand_queue(struct pf_altq *a, struct node_if *interfaces, 3508 struct node_queue *nqueues, struct node_queue_bw bwspec, 3509 struct node_queue_opt *opts) 3510{ 3511 struct node_queue *n, *nq; 3512 struct pf_altq pa; 3513 u_int8_t found = 0; 3514 u_int8_t errs = 0; 3515 3516 if ((pf->loadopt & PFCTL_FLAG_ALTQ) == 0) { 3517 FREE_LIST(struct node_queue, nqueues); 3518 return (0); 3519 } 3520 3521 if (queues == NULL) { 3522 yyerror("queue %s has no parent", a->qname); 3523 FREE_LIST(struct node_queue, nqueues); 3524 return (1); 3525 } 3526 3527 LOOP_THROUGH(struct node_if, interface, interfaces, 3528 LOOP_THROUGH(struct node_queue, tqueue, queues, 3529 if (!strncmp(a->qname, tqueue->queue, PF_QNAME_SIZE) && 3530 (interface->ifname[0] == 0 || 3531 (!interface->not && !strncmp(interface->ifname, 3532 tqueue->ifname, IFNAMSIZ)) || 3533 (interface->not && strncmp(interface->ifname, 3534 tqueue->ifname, IFNAMSIZ)))) { 3535 /* found ourselve in queues */ 3536 found++; 3537 3538 memcpy(&pa, a, sizeof(struct pf_altq)); 3539 3540 if (pa.scheduler != ALTQT_NONE && 3541 pa.scheduler != tqueue->scheduler) { 3542 yyerror("exactly one scheduler type " 3543 "per interface allowed"); 3544 return (1); 3545 } 3546 pa.scheduler = tqueue->scheduler; 3547 3548 /* scheduler dependent error checking */ 3549 switch (pa.scheduler) { 3550 case ALTQT_PRIQ: 3551 if (nqueues != NULL) { 3552 yyerror("priq queues cannot " 3553 "have child queues"); 3554 return (1); 3555 } 3556 if (bwspec.bw_absolute > 0 || 3557 bwspec.bw_percent < 100) { 3558 yyerror("priq doesn't take " 3559 "bandwidth"); 3560 return (1); 3561 } 3562 break; 3563 default: 3564 break; 3565 } 3566 3567 if (strlcpy(pa.ifname, tqueue->ifname, 3568 sizeof(pa.ifname)) >= sizeof(pa.ifname)) 3569 errx(1, "expand_queue: strlcpy"); 3570 if (strlcpy(pa.parent, tqueue->parent, 3571 sizeof(pa.parent)) >= sizeof(pa.parent)) 3572 errx(1, "expand_queue: strlcpy"); 3573 3574 if (eval_pfqueue(pf, &pa, &bwspec, opts)) 3575 errs++; 3576 else 3577 if (pfctl_add_altq(pf, &pa)) 3578 errs++; 3579 3580 for (nq = nqueues; nq != NULL; nq = nq->next) { 3581 n = calloc(1, 3582 sizeof(struct node_queue)); 3583 if (n == NULL) 3584 err(1, "expand_queue: calloc"); 3585 if (strlcpy(n->parent, a->qname, 3586 sizeof(n->parent)) >= 3587 sizeof(n->parent)) 3588 errx(1, "expand_queue strlcpy"); 3589 if (strlcpy(n->queue, nq->queue, 3590 sizeof(n->queue)) >= 3591 sizeof(n->queue)) 3592 errx(1, "expand_queue strlcpy"); 3593 if (strlcpy(n->ifname, tqueue->ifname, 3594 sizeof(n->ifname)) >= 3595 sizeof(n->ifname)) 3596 errx(1, "expand_queue strlcpy"); 3597 n->scheduler = tqueue->scheduler; 3598 n->next = NULL; 3599 n->tail = n; 3600 if (queues == NULL) 3601 queues = n; 3602 else { 3603 queues->tail->next = n; 3604 queues->tail = n; 3605 } 3606 } 3607 if ((pf->opts & PF_OPT_VERBOSE) && ( 3608 (found == 1 && interface->ifname[0] == 0) || 3609 (found > 0 && interface->ifname[0] != 0))) { 3610 print_queue(&pf->paltq->altq, 0, 3611 &bwspec, interface->ifname[0] != 0, 3612 opts); 3613 if (nqueues && nqueues->tail) { 3614 printf("{ "); 3615 LOOP_THROUGH(struct node_queue, 3616 queue, nqueues, 3617 printf("%s ", 3618 queue->queue); 3619 ); 3620 printf("}"); 3621 } 3622 printf("\n"); 3623 } 3624 } 3625 ); 3626 ); 3627 3628 FREE_LIST(struct node_queue, nqueues); 3629 FREE_LIST(struct node_if, interfaces); 3630 3631 if (!found) { 3632 yyerror("queue %s has no parent", a->qname); 3633 errs++; 3634 } 3635 3636 if (errs) 3637 return (1); 3638 else 3639 return (0); 3640} 3641 3642void 3643expand_rule(struct pf_rule *r, 3644 struct node_if *interfaces, struct node_host *rpool_hosts, 3645 struct node_proto *protos, struct node_host *src_hosts, 3646 struct node_port *src_ports, struct node_host *dst_hosts, 3647 struct node_port *dst_ports, struct node_uid *uids, 3648 struct node_gid *gids, struct node_icmp *icmp_types) 3649{ 3650 sa_family_t af = r->af; 3651 int added = 0, error = 0; 3652 char ifname[IF_NAMESIZE]; 3653 char label[PF_RULE_LABEL_SIZE]; 3654 struct pf_pooladdr *pa; 3655 struct node_host *h; 3656 u_int8_t flags, flagset; 3657 3658 if (strlcpy(label, r->label, sizeof(label)) >= sizeof(label)) 3659 errx(1, "expand_rule: strlcpy"); 3660 flags = r->flags; 3661 flagset = r->flagset; 3662 3663 LOOP_THROUGH(struct node_if, interface, interfaces, 3664 LOOP_THROUGH(struct node_proto, proto, protos, 3665 LOOP_THROUGH(struct node_icmp, icmp_type, icmp_types, 3666 LOOP_THROUGH(struct node_host, src_host, src_hosts, 3667 LOOP_THROUGH(struct node_port, src_port, src_ports, 3668 LOOP_THROUGH(struct node_host, dst_host, dst_hosts, 3669 LOOP_THROUGH(struct node_port, dst_port, dst_ports, 3670 LOOP_THROUGH(struct node_uid, uid, uids, 3671 LOOP_THROUGH(struct node_gid, gid, gids, 3672 3673 r->af = af; 3674 /* for link-local IPv6 address, interface must match up */ 3675 if ((r->af && src_host->af && r->af != src_host->af) || 3676 (r->af && dst_host->af && r->af != dst_host->af) || 3677 (src_host->af && dst_host->af && 3678 src_host->af != dst_host->af) || 3679 (src_host->ifindex && dst_host->ifindex && 3680 src_host->ifindex != dst_host->ifindex) || 3681 (src_host->ifindex && if_nametoindex(interface->ifname) && 3682 src_host->ifindex != if_nametoindex(interface->ifname)) || 3683 (dst_host->ifindex && if_nametoindex(interface->ifname) && 3684 dst_host->ifindex != if_nametoindex(interface->ifname))) 3685 continue; 3686 if (!r->af && src_host->af) 3687 r->af = src_host->af; 3688 else if (!r->af && dst_host->af) 3689 r->af = dst_host->af; 3690 3691 if (if_indextoname(src_host->ifindex, ifname)) 3692 memcpy(r->ifname, ifname, sizeof(r->ifname)); 3693 else if (if_indextoname(dst_host->ifindex, ifname)) 3694 memcpy(r->ifname, ifname, sizeof(r->ifname)); 3695 else 3696 memcpy(r->ifname, interface->ifname, sizeof(r->ifname)); 3697 3698 if (strlcpy(r->label, label, sizeof(r->label)) >= 3699 sizeof(r->label)) 3700 errx(1, "expand_rule: strlcpy"); 3701 expand_label(r->label, r->ifname, r->af, src_host, src_port, 3702 dst_host, dst_port, proto->proto); 3703 3704 error += check_netmask(src_host, r->af); 3705 error += check_netmask(dst_host, r->af); 3706 3707 r->ifnot = interface->not; 3708 r->proto = proto->proto; 3709 r->src.addr = src_host->addr; 3710 r->src.not = src_host->not; 3711 r->src.port[0] = src_port->port[0]; 3712 r->src.port[1] = src_port->port[1]; 3713 r->src.port_op = src_port->op; 3714 r->dst.addr = dst_host->addr; 3715 r->dst.not = dst_host->not; 3716 r->dst.port[0] = dst_port->port[0]; 3717 r->dst.port[1] = dst_port->port[1]; 3718 r->dst.port_op = dst_port->op; 3719 r->uid.op = uid->op; 3720 r->uid.uid[0] = uid->uid[0]; 3721 r->uid.uid[1] = uid->uid[1]; 3722 r->gid.op = gid->op; 3723 r->gid.gid[0] = gid->gid[0]; 3724 r->gid.gid[1] = gid->gid[1]; 3725 r->type = icmp_type->type; 3726 r->code = icmp_type->code; 3727 3728 if (r->proto && r->proto != IPPROTO_TCP) { 3729 r->flags = 0; 3730 r->flagset = 0; 3731 } else { 3732 r->flags = flags; 3733 r->flagset = flagset; 3734 } 3735 if (icmp_type->proto && r->proto != icmp_type->proto) { 3736 yyerror("icmp-type mismatch"); 3737 error++; 3738 } 3739 3740 TAILQ_INIT(&r->rpool.list); 3741 for (h = rpool_hosts; h != NULL; h = h->next) { 3742 pa = calloc(1, sizeof(struct pf_pooladdr)); 3743 if (pa == NULL) 3744 err(1, "expand_rule: calloc"); 3745 pa->addr = h->addr; 3746 if (h->ifname != NULL) { 3747 if (strlcpy(pa->ifname, h->ifname, 3748 sizeof(pa->ifname)) >= 3749 sizeof(pa->ifname)) 3750 errx(1, "expand_rule: strlcpy"); 3751 } else 3752 pa->ifname[0] = 0; 3753 TAILQ_INSERT_TAIL(&r->rpool.list, pa, entries); 3754 } 3755 3756 if (rule_consistent(r) < 0 || error) 3757 yyerror("skipping rule due to errors"); 3758 else { 3759 r->nr = pf->rule_nr++; 3760 pfctl_add_rule(pf, r); 3761 added++; 3762 } 3763 3764 ))))))))); 3765 3766 FREE_LIST(struct node_if, interfaces); 3767 FREE_LIST(struct node_proto, protos); 3768 FREE_LIST(struct node_host, src_hosts); 3769 FREE_LIST(struct node_port, src_ports); 3770 FREE_LIST(struct node_host, dst_hosts); 3771 FREE_LIST(struct node_port, dst_ports); 3772 FREE_LIST(struct node_uid, uids); 3773 FREE_LIST(struct node_gid, gids); 3774 FREE_LIST(struct node_icmp, icmp_types); 3775 FREE_LIST(struct node_host, rpool_hosts); 3776 3777 if (!added) 3778 yyerror("rule expands to no valid combination"); 3779} 3780 3781#undef FREE_LIST 3782#undef LOOP_THROUGH 3783 3784int 3785check_rulestate(int desired_state) 3786{ 3787 if (require_order && (rulestate > desired_state)) { 3788 yyerror("Rules must be in order: options, normalization, " 3789 "queueing, translation, filtering"); 3790 return (1); 3791 } 3792 rulestate = desired_state; 3793 return (0); 3794} 3795 3796int 3797kw_cmp(const void *k, const void *e) 3798{ 3799 return (strcmp(k, ((const struct keywords *)e)->k_name)); 3800} 3801 3802int 3803lookup(char *s) 3804{ 3805 /* this has to be sorted always */ 3806 static const struct keywords keywords[] = { 3807 { "all", ALL}, 3808 { "allow-opts", ALLOWOPTS}, 3809 { "altq", ALTQ}, 3810 { "anchor", ANCHOR}, 3811 { "antispoof", ANTISPOOF}, 3812 { "any", ANY}, 3813 { "bandwidth", BANDWIDTH}, 3814 { "binat", BINAT}, 3815 { "binat-anchor", BINATANCHOR}, 3816 { "bitmask", BITMASK}, 3817 { "block", BLOCK}, 3818 { "block-policy", BLOCKPOLICY}, 3819 { "cbq", CBQ}, 3820 { "code", CODE}, 3821 { "crop", FRAGCROP}, 3822 { "drop", DROP}, 3823 { "drop-ovl", FRAGDROP}, 3824 { "dup-to", DUPTO}, 3825 { "fastroute", FASTROUTE}, 3826 { "file", FILENAME}, 3827 { "flags", FLAGS}, 3828 { "for", FOR}, 3829 { "fragment", FRAGMENT}, 3830 { "from", FROM}, 3831 { "group", GROUP}, 3832 { "hfsc", HFSC}, 3833 { "icmp-type", ICMPTYPE}, 3834 { "icmp6-type", ICMP6TYPE}, 3835 { "in", IN}, 3836 { "inet", INET}, 3837 { "inet6", INET6}, 3838 { "keep", KEEP}, 3839 { "label", LABEL}, 3840 { "limit", LIMIT}, 3841 { "linkshare", LINKSHARE}, 3842 { "load", LOAD}, 3843 { "log", LOG}, 3844 { "log-all", LOGALL}, 3845 { "loginterface", LOGINTERFACE}, 3846 { "max", MAXIMUM}, 3847 { "max-mss", MAXMSS}, 3848 { "min-ttl", MINTTL}, 3849 { "modulate", MODULATE}, 3850 { "nat", NAT}, 3851 { "nat-anchor", NATANCHOR}, 3852 { "no", NO}, 3853 { "no-df", NODF}, 3854 { "no-route", NOROUTE}, 3855 { "on", ON}, 3856 { "optimization", OPTIMIZATION}, 3857 { "out", OUT}, 3858 { "pass", PASS}, 3859 { "port", PORT}, 3860 { "priority", PRIORITY}, 3861 { "priq", PRIQ}, 3862 { "proto", PROTO}, 3863 { "qlimit", QLIMIT}, 3864 { "queue", QUEUE}, 3865 { "quick", QUICK}, 3866 { "random", RANDOM}, 3867 { "random-id", RANDOMID}, 3868 { "rdr", RDR}, 3869 { "rdr-anchor", RDRANCHOR}, 3870 { "realtime", REALTIME}, 3871 { "reassemble", REASSEMBLE}, 3872 { "reply-to", REPLYTO}, 3873 { "require-order", REQUIREORDER}, 3874 { "return", RETURN}, 3875 { "return-icmp", RETURNICMP}, 3876 { "return-icmp6", RETURNICMP6}, 3877 { "return-rst", RETURNRST}, 3878 { "round-robin", ROUNDROBIN}, 3879 { "route-to", ROUTETO}, 3880 { "scrub", SCRUB}, 3881 { "set", SET}, 3882 { "source-hash", SOURCEHASH}, 3883 { "state", STATE}, 3884 { "static-port", STATICPORT}, 3885 { "synproxy", SYNPROXY}, 3886 { "table", TABLE}, 3887 { "tag", TAG}, 3888 { "tagged", TAGGED}, 3889 { "tbrsize", TBRSIZE}, 3890 { "timeout", TIMEOUT}, 3891 { "to", TO}, 3892 { "tos", TOS}, 3893 { "ttl", TTL}, 3894 { "upperlimit", UPPERLIMIT}, 3895 { "user", USER}, 3896 }; 3897 const struct keywords *p; 3898 3899 p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), 3900 sizeof(keywords[0]), kw_cmp); 3901 3902 if (p) { 3903 if (debug > 1) 3904 fprintf(stderr, "%s: %d\n", s, p->k_val); 3905 return (p->k_val); 3906 } else { 3907 if (debug > 1) 3908 fprintf(stderr, "string: %s\n", s); 3909 return (STRING); 3910 } 3911} 3912 3913#define MAXPUSHBACK 128 3914 3915char *parsebuf; 3916int parseindex; 3917char pushback_buffer[MAXPUSHBACK]; 3918int pushback_index = 0; 3919 3920int 3921lgetc(FILE *f) 3922{ 3923 int c, next; 3924 3925 if (parsebuf) { 3926 /* Read character from the parsebuffer instead of input. */ 3927 if (parseindex >= 0) { 3928 c = parsebuf[parseindex++]; 3929 if (c != '\0') 3930 return (c); 3931 parsebuf = NULL; 3932 } else 3933 parseindex++; 3934 } 3935 3936 if (pushback_index) 3937 return (pushback_buffer[--pushback_index]); 3938 3939 while ((c = getc(f)) == '\\') { 3940 next = getc(f); 3941 if (next != '\n') { 3942 if (isspace(next)) 3943 yyerror("whitespace after \\"); 3944 ungetc(next, f); 3945 break; 3946 } 3947 yylval.lineno = lineno; 3948 lineno++; 3949 } 3950 if (c == '\t' || c == ' ') { 3951 /* Compress blanks to a single space. */ 3952 do { 3953 c = getc(f); 3954 } while (c == '\t' || c == ' '); 3955 ungetc(c, f); 3956 c = ' '; 3957 } 3958 3959 return (c); 3960} 3961 3962int 3963lungetc(int c) 3964{ 3965 if (c == EOF) 3966 return (EOF); 3967 if (parsebuf) { 3968 parseindex--; 3969 if (parseindex >= 0) 3970 return (c); 3971 } 3972 if (pushback_index < MAXPUSHBACK-1) 3973 return (pushback_buffer[pushback_index++] = c); 3974 else 3975 return (EOF); 3976} 3977 3978int 3979findeol(void) 3980{ 3981 int c; 3982 3983 parsebuf = NULL; 3984 pushback_index = 0; 3985 3986 /* skip to either EOF or the first real EOL */ 3987 while (1) { 3988 c = lgetc(fin); 3989 if (c == '\n') { 3990 lineno++; 3991 break; 3992 } 3993 if (c == EOF) 3994 break; 3995 } 3996 return (ERROR); 3997} 3998 3999int 4000yylex(void) 4001{ 4002 char buf[8096]; 4003 char *p, *val; 4004 int endc, c, next; 4005 int token; 4006 4007top: 4008 p = buf; 4009 while ((c = lgetc(fin)) == ' ') 4010 ; /* nothing */ 4011 4012 yylval.lineno = lineno; 4013 if (c == '#') 4014 while ((c = lgetc(fin)) != '\n' && c != EOF) 4015 ; /* nothing */ 4016 if (c == '$' && parsebuf == NULL) { 4017 while (1) { 4018 if ((c = lgetc(fin)) == EOF) 4019 return (0); 4020 4021 if (p + 1 >= buf + sizeof(buf) - 1) { 4022 yyerror("string too long"); 4023 return (findeol()); 4024 } 4025 if (isalnum(c) || c == '_') { 4026 *p++ = (char)c; 4027 continue; 4028 } 4029 *p = '\0'; 4030 lungetc(c); 4031 break; 4032 } 4033 val = symget(buf); 4034 if (val == NULL) { 4035 yyerror("macro '%s' not defined", buf); 4036 return (findeol()); 4037 } 4038 parsebuf = val; 4039 parseindex = 0; 4040 goto top; 4041 } 4042 4043 switch (c) { 4044 case '\'': 4045 case '"': 4046 endc = c; 4047 while (1) { 4048 if ((c = lgetc(fin)) == EOF) 4049 return (0); 4050 if (c == endc) { 4051 *p = '\0'; 4052 break; 4053 } 4054 if (c == '\n') { 4055 lineno++; 4056 continue; 4057 } 4058 if (p + 1 >= buf + sizeof(buf) - 1) { 4059 yyerror("string too long"); 4060 return (findeol()); 4061 } 4062 *p++ = (char)c; 4063 } 4064 yylval.v.string = strdup(buf); 4065 if (yylval.v.string == NULL) 4066 err(1, "yylex: strdup"); 4067 return (STRING); 4068 case '<': 4069 next = lgetc(fin); 4070 if (next == '>') { 4071 yylval.v.i = PF_OP_XRG; 4072 return (PORTBINARY); 4073 } 4074 lungetc(next); 4075 break; 4076 case '>': 4077 next = lgetc(fin); 4078 if (next == '<') { 4079 yylval.v.i = PF_OP_IRG; 4080 return (PORTBINARY); 4081 } 4082 lungetc(next); 4083 break; 4084 case '-': 4085 next = lgetc(fin); 4086 if (next == '>') 4087 return (ARROW); 4088 lungetc(next); 4089 break; 4090 } 4091 4092#define allowed_in_string(x) \ 4093 (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ 4094 x != '{' && x != '}' && x != '<' && x != '>' && \ 4095 x != '!' && x != '=' && x != '/' && x != '#' && \ 4096 x != ',')) 4097 4098 if (isalnum(c) || c == ':' || c == '_') { 4099 do { 4100 *p++ = c; 4101 if ((unsigned)(p-buf) >= sizeof(buf)) { 4102 yyerror("string too long"); 4103 return (findeol()); 4104 } 4105 } while ((c = lgetc(fin)) != EOF && (allowed_in_string(c))); 4106 lungetc(c); 4107 *p = '\0'; 4108 token = lookup(buf); 4109 yylval.v.string = strdup(buf); 4110 if (yylval.v.string == NULL) 4111 err(1, "yylex: strdup"); 4112 return (token); 4113 } 4114 if (c == '\n') { 4115 yylval.lineno = lineno; 4116 lineno++; 4117 } 4118 if (c == EOF) 4119 return (0); 4120 return (c); 4121} 4122 4123int 4124parse_rules(FILE *input, struct pfctl *xpf) 4125{ 4126 struct sym *sym; 4127 4128 fin = input; 4129 pf = xpf; 4130 lineno = 1; 4131 errors = 0; 4132 rulestate = PFCTL_STATE_NONE; 4133 returnicmpdefault = (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT; 4134 returnicmp6default = 4135 (ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT; 4136 blockpolicy = PFRULE_DROP; 4137 require_order = 1; 4138 4139 yyparse(); 4140 4141 /* Free macros and check which have not been used. */ 4142 TAILQ_FOREACH(sym, &symhead, entries) { 4143 if ((pf->opts & PF_OPT_VERBOSE2) && !sym->used) 4144 fprintf(stderr, "warning: macro '%s' not " 4145 "used\n", sym->nam); 4146 free(sym->nam); 4147 free(sym->val); 4148 TAILQ_REMOVE(&symhead, sym, entries); 4149 } 4150 4151 return (errors ? -1 : 0); 4152} 4153 4154/* 4155 * Over-designed efficiency is a French and German concept, so how about 4156 * we wait until they discover this ugliness and make it all fancy. 4157 */ 4158int 4159symset(const char *nam, const char *val, int persist) 4160{ 4161 struct sym *sym; 4162 4163 for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam); 4164 sym = TAILQ_NEXT(sym, entries)) 4165 ; /* nothing */ 4166 4167 if (sym != NULL) { 4168 if (sym->persist == 1) 4169 return (0); 4170 else { 4171 free(sym->nam); 4172 free(sym->val); 4173 TAILQ_REMOVE(&symhead, sym, entries); 4174 free(sym); 4175 } 4176 } 4177 if ((sym = calloc(1, sizeof(*sym))) == NULL) 4178 return (-1); 4179 4180 sym->nam = strdup(nam); 4181 if (sym->nam == NULL) { 4182 free(sym); 4183 return (-1); 4184 } 4185 sym->val = strdup(val); 4186 if (sym->val == NULL) { 4187 free(sym->nam); 4188 free(sym); 4189 return (-1); 4190 } 4191 sym->used = 0; 4192 sym->persist = persist; 4193 TAILQ_INSERT_TAIL(&symhead, sym, entries); 4194 return (0); 4195} 4196 4197int 4198pfctl_cmdline_symset(char *s) 4199{ 4200 char *sym, *val; 4201 int ret; 4202 4203 if ((val = strrchr(s, '=')) == NULL) 4204 return (-1); 4205 4206 if ((sym = malloc(strlen(s) - strlen(val) + 1)) == NULL) 4207 err(1, "pfctl_cmdline_symset: malloc"); 4208 4209 strlcpy(sym, s, strlen(s) - strlen(val) + 1); 4210 4211 ret = symset(sym, val + 1, 1); 4212 free(sym); 4213 4214 return (ret); 4215} 4216 4217char * 4218symget(const char *nam) 4219{ 4220 struct sym *sym; 4221 4222 TAILQ_FOREACH(sym, &symhead, entries) 4223 if (strcmp(nam, sym->nam) == 0) { 4224 sym->used = 1; 4225 return (sym->val); 4226 } 4227 return (NULL); 4228} 4229 4230void 4231decide_address_family(struct node_host *n, sa_family_t *af) 4232{ 4233 sa_family_t target_af = 0; 4234 4235 while (!*af && n != NULL) { 4236 if (n->af) { 4237 if (target_af == 0) 4238 target_af = n->af; 4239 if (target_af != n->af) 4240 return; 4241 } 4242 n = n->next; 4243 } 4244 if (!*af && target_af) 4245 *af = target_af; 4246} 4247 4248void 4249remove_invalid_hosts(struct node_host **nh, sa_family_t *af) 4250{ 4251 struct node_host *n = *nh, *prev = NULL; 4252 4253 while (n != NULL) { 4254 if (*af && n->af && n->af != *af) { 4255 /* unlink and free n */ 4256 struct node_host *next = n->next; 4257 4258 /* adjust tail pointer */ 4259 if (n == (*nh)->tail) 4260 (*nh)->tail = prev; 4261 /* adjust previous node's next pointer */ 4262 if (prev == NULL) 4263 *nh = next; 4264 else 4265 prev->next = next; 4266 /* free node */ 4267 if (n->ifname != NULL) 4268 free(n->ifname); 4269 free(n); 4270 n = next; 4271 } else { 4272 if (n->af && !*af) 4273 *af = n->af; 4274 prev = n; 4275 n = n->next; 4276 } 4277 } 4278} 4279 4280int 4281invalid_redirect(struct node_host *nh, sa_family_t af) 4282{ 4283 if (!af) { 4284 yyerror("address family not given and translation " 4285 "address expands to multiple address families"); 4286 return (1); 4287 } 4288 if (nh == NULL) { 4289 yyerror("no translation address with matching address family " 4290 "found."); 4291 return (1); 4292 } 4293 return (0); 4294} 4295 4296int 4297atoul(char *s, u_long *ulvalp) 4298{ 4299 u_long ulval; 4300 char *ep; 4301 4302 errno = 0; 4303 ulval = strtoul(s, &ep, 0); 4304 if (s[0] == '\0' || *ep != '\0') 4305 return (-1); 4306 if (errno == ERANGE && ulval == ULONG_MAX) 4307 return (-1); 4308 *ulvalp = ulval; 4309 return (0); 4310} 4311 4312int 4313getservice(char *n) 4314{ 4315 struct servent *s; 4316 u_long ulval; 4317 4318 if (atoul(n, &ulval) == 0) { 4319 if (ulval > 65535) { 4320 yyerror("illegal port value %d", ulval); 4321 return (-1); 4322 } 4323 return (htons(ulval)); 4324 } else { 4325 s = getservbyname(n, "tcp"); 4326 if (s == NULL) 4327 s = getservbyname(n, "udp"); 4328 if (s == NULL) { 4329 yyerror("unknown port %s", n); 4330 return (-1); 4331 } 4332 return (s->s_port); 4333 } 4334} 4335 4336int 4337rule_label(struct pf_rule *r, char *s) 4338{ 4339 if (s) { 4340 if (strlcpy(r->label, s, sizeof(r->label)) >= 4341 sizeof(r->label)) { 4342 yyerror("rule label too long (max %d chars)", 4343 sizeof(r->label)-1); 4344 return (-1); 4345 } 4346 } 4347 return (0); 4348} 4349 4350u_int16_t 4351parseicmpspec(char *w, sa_family_t af) 4352{ 4353 const struct icmpcodeent *p; 4354 u_long ulval; 4355 u_int8_t icmptype; 4356 4357 if (af == AF_INET) 4358 icmptype = returnicmpdefault >> 8; 4359 else 4360 icmptype = returnicmp6default >> 8; 4361 4362 if (atoul(w, &ulval) == -1) { 4363 if ((p = geticmpcodebyname(icmptype, w, af)) == NULL) { 4364 yyerror("unknown icmp code %s", w); 4365 return (0); 4366 } 4367 ulval = p->code; 4368 } 4369 if (ulval > 255) { 4370 yyerror("invalid icmp code %ld", ulval); 4371 return (0); 4372 } 4373 return (icmptype << 8 | ulval); 4374} 4375 4376int 4377pfctl_load_anchors(int dev, int opts) 4378{ 4379 struct loadanchors *la; 4380 4381 TAILQ_FOREACH(la, &loadanchorshead, entries) { 4382 if (opts & PF_OPT_VERBOSE) 4383 fprintf(stderr, "\nLoading anchor %s:%s from %s\n", 4384 la->anchorname, la->rulesetname, la->filename); 4385 if (pfctl_rules(dev, la->filename, opts, la->anchorname, 4386 la->rulesetname) == -1) 4387 return (-1); 4388 } 4389 4390 return (0); 4391} 4392 4393