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