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