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