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