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