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