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