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