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