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