parse.y revision 1.158
1/* $OpenBSD: parse.y,v 1.158 2002/10/07 12:39:29 dhartmei 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 52#include "pfctl_parser.h" 53 54static struct pfctl *pf = NULL; 55static FILE *fin = NULL; 56static int debug = 0; 57static int lineno = 1; 58static int errors = 0; 59static int rulestate = 0; 60 61enum { 62 PFCTL_STATE_NONE = 0, 63 PFCTL_STATE_OPTION = 1, 64 PFCTL_STATE_SCRUB = 2, 65 PFCTL_STATE_NAT = 3, 66 PFCTL_STATE_FILTER = 4 67}; 68 69enum pfctl_iflookup_mode { 70 PFCTL_IFLOOKUP_HOST = 0, 71 PFCTL_IFLOOKUP_NET = 1, 72 PFCTL_IFLOOKUP_BCAST = 2 73}; 74 75struct node_if { 76 char ifname[IFNAMSIZ]; 77 u_int8_t not; 78 u_int ifa_flags; 79 struct node_if *next; 80 struct node_if *tail; 81}; 82 83struct node_proto { 84 u_int8_t proto; 85 struct node_proto *next; 86 struct node_proto *tail; 87}; 88 89struct node_host { 90 struct pf_addr_wrap addr; 91 struct pf_addr mask; 92 struct pf_addr bcast; 93 u_int8_t af; 94 u_int8_t not; 95 u_int8_t noroute; 96 u_int32_t ifindex; /* link-local IPv6 addrs */ 97 char *ifname; 98 u_int ifa_flags; 99 struct node_host *next; 100 struct node_host *tail; 101}; 102 103struct node_port { 104 u_int16_t port[2]; 105 u_int8_t op; 106 struct node_port *next; 107 struct node_port *tail; 108}; 109 110struct node_uid { 111 uid_t uid[2]; 112 u_int8_t op; 113 struct node_uid *next; 114 struct node_uid *tail; 115}; 116 117struct node_gid { 118 gid_t gid[2]; 119 u_int8_t op; 120 struct node_gid *next; 121 struct node_gid *tail; 122}; 123 124struct node_icmp { 125 u_int8_t code; 126 u_int8_t type; 127 u_int8_t proto; 128 struct node_icmp *next; 129 struct node_icmp *tail; 130}; 131 132enum { PF_STATE_OPT_MAX=0, PF_STATE_OPT_TIMEOUT=1 }; 133struct node_state_opt { 134 int type; 135 union { 136 u_int32_t max_states; 137 struct { 138 int number; 139 u_int32_t seconds; 140 } timeout; 141 } data; 142 struct node_state_opt *next; 143 struct node_state_opt *tail; 144}; 145 146struct peer { 147 struct node_host *host; 148 struct node_port *port; 149}; 150 151int yyerror(char *, ...); 152int rule_consistent(struct pf_rule *); 153int nat_consistent(struct pf_nat *); 154int rdr_consistent(struct pf_rdr *); 155int yyparse(void); 156void ipmask(struct pf_addr *, u_int8_t); 157void expand_rdr(struct pf_rdr *, struct node_if *, struct node_proto *, 158 struct node_host *, struct node_host *); 159void expand_nat(struct pf_nat *, struct node_if *, struct node_proto *, 160 struct node_host *, struct node_port *, 161 struct node_host *, struct node_port *); 162void expand_label_addr(const char *, char *, u_int8_t, struct node_host *); 163void expand_label_port(const char *, char *, struct node_port *); 164void expand_label_proto(const char *, char *, u_int8_t); 165void expand_label_nr(const char *, char *); 166void expand_label(char *, u_int8_t, struct node_host *, struct node_port *, 167 struct node_host *, struct node_port *, u_int8_t); 168void expand_rule(struct pf_rule *, struct node_if *, struct node_proto *, 169 struct node_host *, struct node_port *, struct node_host *, 170 struct node_port *, struct node_uid *, struct node_gid *, 171 struct node_icmp *); 172int check_rulestate(int); 173int kw_cmp(const void *, const void *); 174int lookup(char *); 175int lgetc(FILE *); 176int lungetc(int, FILE *); 177int findeol(void); 178int yylex(void); 179struct node_host *host(char *); 180int atoul(char *, u_long *); 181int getservice(char *); 182 183 184struct sym { 185 struct sym *next; 186 char *nam; 187 char *val; 188}; 189struct sym *symhead = NULL; 190 191int symset(const char *, const char *); 192char * symget(const char *); 193 194void ifa_load(void); 195struct node_host *ifa_exists(char *); 196struct node_host *ifa_lookup(char *, enum pfctl_iflookup_mode); 197struct node_host *ifa_pick_ip(struct node_host *, u_int8_t); 198 199typedef struct { 200 union { 201 u_int32_t number; 202 int i; 203 char *string; 204 struct { 205 u_int8_t b1; 206 u_int8_t b2; 207 u_int16_t w; 208 } b; 209 struct range { 210 int a; 211 int b; 212 int t; 213 } range; 214 struct node_if *interface; 215 struct node_proto *proto; 216 struct node_icmp *icmp; 217 struct node_host *host; 218 struct node_port *port; 219 struct node_uid *uid; 220 struct node_gid *gid; 221 struct node_state_opt *state_opt; 222 struct peer peer; 223 struct { 224 struct peer src, dst; 225 } fromto; 226 struct { 227 char *string; 228 struct pf_addr *addr; 229 u_int8_t rt; 230 u_int8_t af; 231 } route; 232 struct redirection { 233 struct node_host *address; 234 struct range rport; 235 } *redirection; 236 struct { 237 int action; 238 struct node_state_opt *options; 239 } keep_state; 240 struct { 241 u_int8_t log; 242 u_int8_t quick; 243 } logquick; 244 } v; 245 int lineno; 246} YYSTYPE; 247 248%} 249 250%token PASS BLOCK SCRUB RETURN IN OUT LOG LOGALL QUICK ON FROM TO FLAGS 251%token RETURNRST RETURNICMP RETURNICMP6 PROTO INET INET6 ALL ANY ICMPTYPE 252%token ICMP6TYPE CODE KEEP MODULATE STATE PORT RDR NAT BINAT ARROW NODF 253%token MINTTL ERROR ALLOWOPTS FASTROUTE ROUTETO DUPTO REPLYTO NO LABEL 254%token NOROUTE FRAGMENT USER GROUP MAXMSS MAXIMUM TTL TOS 255%token FRAGNORM FRAGDROP FRAGCROP 256%token SET OPTIMIZATION TIMEOUT LIMIT LOGINTERFACE 257%token ANTISPOOF FOR 258%token <v.string> STRING 259%token <v.i> PORTUNARY PORTBINARY 260%type <v.interface> interface if_list if_item_not if_item 261%type <v.number> number port icmptype icmp6type minttl uid gid maxmss 262%type <v.number> tos 263%type <v.i> no dir log af nodf allowopts fragment fragcache 264%type <v.b> action flag flags blockspec 265%type <v.range> dport rport 266%type <v.proto> proto proto_list proto_item 267%type <v.icmp> icmpspec icmp_list icmp6_list icmp_item icmp6_item 268%type <v.fromto> fromto 269%type <v.peer> ipportspec 270%type <v.host> ipspec xhost host address host_list 271%type <v.port> portspec port_list port_item 272%type <v.uid> uids uid_list uid_item 273%type <v.gid> gids gid_list gid_item 274%type <v.route> route 275%type <v.redirection> redirection 276%type <v.string> label string 277%type <v.keep_state> keep 278%type <v.state_opt> state_opt_spec state_opt_list state_opt_item 279%type <v.logquick> logquick 280%type <v.interface> antispoof_ifspc antispoof_iflst 281%% 282 283ruleset : /* empty */ 284 | ruleset '\n' 285 | ruleset option '\n' 286 | ruleset scrubrule '\n' 287 | ruleset natrule '\n' 288 | ruleset binatrule '\n' 289 | ruleset rdrrule '\n' 290 | ruleset pfrule '\n' 291 | ruleset varset '\n' 292 | ruleset antispoof '\n' 293 | ruleset error '\n' { errors++; } 294 ; 295 296option : SET OPTIMIZATION STRING { 297 if (pf->opts & PF_OPT_VERBOSE) 298 printf("set optimization %s\n", $3); 299 if (check_rulestate(PFCTL_STATE_OPTION)) 300 YYERROR; 301 if (pfctl_set_optimization(pf, $3) != 0) { 302 yyerror("unknown optimization %s", $3); 303 YYERROR; 304 } 305 } 306 | SET TIMEOUT timeout_spec 307 | SET TIMEOUT '{' timeout_list '}' 308 | SET LIMIT limit_spec 309 | SET LIMIT '{' limit_list '}' 310 | SET LOGINTERFACE STRING { 311 if (pf->opts & PF_OPT_VERBOSE) 312 printf("set loginterface %s\n", $3); 313 if (check_rulestate(PFCTL_STATE_OPTION)) 314 YYERROR; 315 if (pfctl_set_logif(pf, $3) != 0) { 316 yyerror("error setting loginterface %s", $3); 317 YYERROR; 318 } 319 } 320 ; 321 322string : string STRING { 323 if (asprintf(&$$, "%s %s", $1, $2) == -1) { 324 yyerror("malloc failed"); 325 YYERROR; 326 } 327 free($1); 328 free($2); 329 } 330 | STRING 331 ; 332 333varset : STRING PORTUNARY string { 334 if (pf->opts & PF_OPT_VERBOSE) 335 printf("%s = %s\n", $1, $3); 336 if (symset($1, $3) == -1) { 337 yyerror("cannot store variable %s", $1); 338 YYERROR; 339 } 340 } 341 ; 342 343scrubrule : SCRUB dir interface fromto nodf minttl maxmss fragcache 344 { 345 struct pf_rule r; 346 347 if (check_rulestate(PFCTL_STATE_SCRUB)) 348 YYERROR; 349 350 memset(&r, 0, sizeof(r)); 351 352 r.action = PF_SCRUB; 353 r.direction = $2; 354 355 if ($3) { 356 if ($3->not) { 357 yyerror("scrub rules don't support " 358 "'! <if>'"); 359 YYERROR; 360 } else if ($3->next) { 361 yyerror("scrub rules don't support " 362 "{} expansion"); 363 YYERROR; 364 } 365 memcpy(r.ifname, $3->ifname, 366 sizeof(r.ifname)); 367 free($3); 368 } 369 if ($5) 370 r.rule_flag |= PFRULE_NODF; 371 if ($6) 372 r.min_ttl = $6; 373 if ($7) 374 r.max_mss = $7; 375 if ($8) 376 r.rule_flag |= $8; 377 378 r.nr = pf->rule_nr++; 379 if (rule_consistent(&r) < 0) 380 yyerror("skipping scrub rule due to errors"); 381 else 382 pfctl_add_rule(pf, &r); 383 384 } 385 ; 386 387antispoof : ANTISPOOF logquick antispoof_ifspc af { 388 struct pf_rule r; 389 struct node_host *h = NULL; 390 struct node_if *i, *j; 391 392 if (check_rulestate(PFCTL_STATE_FILTER)) 393 YYERROR; 394 395 for (i = $3; i; i = i->next) { 396 memset(&r, 0, sizeof(r)); 397 398 r.action = PF_DROP; 399 r.direction = PF_IN; 400 r.log = $2.log; 401 r.quick = $2.quick; 402 r.af = $4; 403 404 j = calloc(1, sizeof(struct node_if)); 405 if (j == NULL) 406 errx(1, "antispoof: calloc"); 407 strlcpy(j->ifname, i->ifname, IFNAMSIZ); 408 j->not = 1; 409 h = ifa_lookup(j->ifname, PFCTL_IFLOOKUP_NET); 410 411 expand_rule(&r, j, NULL, h, NULL, NULL, NULL, 412 NULL, NULL, NULL); 413 414 if ((i->ifa_flags & IFF_LOOPBACK) == 0) { 415 memset(&r, 0, sizeof(r)); 416 417 r.action = PF_DROP; 418 r.direction = PF_IN; 419 r.log = $2.log; 420 r.quick = $2.quick; 421 r.af = $4; 422 423 h = ifa_lookup(i->ifname, 424 PFCTL_IFLOOKUP_HOST); 425 426 expand_rule(&r, NULL, NULL, h, NULL, 427 NULL, NULL, NULL, NULL, NULL); 428 } 429 } 430 } 431 ; 432 433antispoof_ifspc : FOR if_item { $$ = $2; } 434 | FOR '{' antispoof_iflst '}' { $$ = $3; } 435 ; 436 437antispoof_iflst : if_item { $$ = $1; } 438 | antispoof_iflst comma if_item { 439 $1->tail->next = $3; 440 $1->tail = $3; 441 $$ = $1; 442 } 443 ; 444 445pfrule : action dir logquick interface route af proto fromto 446 uids gids flags icmpspec tos keep fragment allowopts label 447 { 448 struct pf_rule r; 449 struct node_state_opt *o; 450 struct node_proto *proto; 451 452 if (check_rulestate(PFCTL_STATE_FILTER)) 453 YYERROR; 454 455 memset(&r, 0, sizeof(r)); 456 457 r.action = $1.b1; 458 if ($1.b2) { 459 r.rule_flag |= PFRULE_RETURNRST; 460 r.return_ttl = $1.w; 461 } else 462 r.return_icmp = $1.w; 463 r.direction = $2; 464 r.log = $3.log; 465 r.quick = $3.quick; 466 467 r.af = $6; 468 r.flags = $11.b1; 469 r.flagset = $11.b2; 470 471 if ($11.b1 || $11.b2) { 472 for (proto = $7; proto != NULL && 473 proto->proto != IPPROTO_TCP; 474 proto = proto->next) 475 ; /* nothing */ 476 if (proto == NULL && $7 != NULL) { 477 yyerror("flags only apply to tcp"); 478 YYERROR; 479 } 480 } 481 482 r.tos = $13; 483 r.keep_state = $14.action; 484 o = $14.options; 485 while (o) { 486 struct node_state_opt *p = o; 487 488 switch (o->type) { 489 case PF_STATE_OPT_MAX: 490 if (r.max_states) { 491 yyerror("state option 'max' " 492 "multiple definitions"); 493 YYERROR; 494 } 495 r.max_states = o->data.max_states; 496 break; 497 case PF_STATE_OPT_TIMEOUT: 498 if (r.timeout[o->data.timeout.number]) { 499 yyerror("state timeout %s " 500 "multiple definitions", 501 pf_timeouts[o->data. 502 timeout.number].name); 503 YYERROR; 504 } 505 r.timeout[o->data.timeout.number] = 506 o->data.timeout.seconds; 507 } 508 o = o->next; 509 free(p); 510 } 511 512 if ($15) 513 r.rule_flag |= PFRULE_FRAGMENT; 514 r.allow_opts = $16; 515 516 if ($5.rt) { 517 r.rt = $5.rt; 518 if ($5.string) { 519 strlcpy(r.rt_ifname, $5.string, 520 IFNAMSIZ); 521 if (ifa_exists(r.rt_ifname) == NULL) { 522 yyerror("unknown interface %s", 523 r.rt_ifname); 524 YYERROR; 525 } 526 free($5.string); 527 } 528 if ($5.addr) { 529 if (!r.af) 530 r.af = $5.af; 531 else if (r.af != $5.af) { 532 yyerror("address family" 533 " mismatch"); 534 YYERROR; 535 } 536 memcpy(&r.rt_addr, $5.addr, 537 sizeof(r.rt_addr)); 538 free($5.addr); 539 } 540 } 541 542 if ($17) { 543 if (strlen($17) >= PF_RULE_LABEL_SIZE) { 544 yyerror("rule label too long (max " 545 "%d chars)", PF_RULE_LABEL_SIZE-1); 546 YYERROR; 547 } 548 strlcpy(r.label, $17, sizeof(r.label)); 549 free($17); 550 } 551 552 expand_rule(&r, $4, $7, $8.src.host, $8.src.port, 553 $8.dst.host, $8.dst.port, $9, $10, $12); 554 } 555 ; 556 557action : PASS { $$.b1 = PF_PASS; $$.b2 = $$.w = 0; } 558 | BLOCK blockspec { $$ = $2; $$.b1 = PF_DROP; } 559 ; 560 561blockspec : /* empty */ { $$.b2 = 0; $$.w = 0; } 562 | RETURNRST { $$.b2 = 1; $$.w = 0; } 563 | RETURNRST '(' TTL number ')' { 564 $$.w = $4; 565 $$.b2 = 1; 566 } 567 | RETURNICMP { 568 $$.b2 = 0; 569 $$.w = (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT; 570 } 571 | RETURNICMP6 { 572 $$.b2 = 0; 573 $$.w = (ICMP6_DST_UNREACH << 8) | 574 ICMP6_DST_UNREACH_NOPORT; 575 } 576 | RETURNICMP '(' STRING ')' { 577 const struct icmpcodeent *p; 578 u_long ulval; 579 580 if (atoul($3, &ulval) == -1) { 581 if ((p = geticmpcodebyname(ICMP_UNREACH, $3, 582 AF_INET)) == NULL) { 583 yyerror("unknown icmp code %s", $3); 584 YYERROR; 585 } 586 ulval = p->code; 587 } 588 $$.w = (ICMP_UNREACH << 8) | ulval; 589 $$.b2 = 0; 590 } 591 | RETURNICMP6 '(' STRING ')' { 592 const struct icmpcodeent *p; 593 u_long ulval; 594 595 if (atoul($3, &ulval) == -1) { 596 if ((p = geticmpcodebyname(ICMP6_DST_UNREACH, $3, 597 AF_INET6)) == NULL) { 598 yyerror("unknown icmp code %s", $3); 599 YYERROR; 600 } 601 ulval = p->code; 602 } 603 $$.w = (ICMP6_DST_UNREACH << 8) | ulval; 604 $$.b2 = 0; 605 } 606 ; 607 608fragcache : /* empty */ { $$ = 0; } 609 | fragment FRAGNORM { $$ = 0; /* default */ } 610 | fragment FRAGCROP { $$ = PFRULE_FRAGCROP; } 611 | fragment FRAGDROP { $$ = PFRULE_FRAGDROP; } 612 ; 613 614 615dir : IN { $$ = PF_IN; } 616 | OUT { $$ = PF_OUT; } 617 ; 618 619logquick : /* empty */ { $$.log = 0; $$.quick = 0; } 620 | log { $$.log = $1; $$.quick = 0; } 621 | QUICK { $$.log = 0; $$.quick = 1; } 622 | log QUICK { $$.log = $1; $$.quick = 1; } 623 | QUICK log { $$.log = $2; $$.quick = 1; } 624 ; 625 626log : LOG { $$ = 1; } 627 | LOGALL { $$ = 2; } 628 ; 629 630interface : /* empty */ { $$ = NULL; } 631 | ON if_item_not { $$ = $2; } 632 | ON '{' if_list '}' { $$ = $3; } 633 ; 634 635if_list : if_item_not { $$ = $1; } 636 | if_list comma if_item_not { 637 $1->tail->next = $3; 638 $1->tail = $3; 639 $$ = $1; 640 } 641 ; 642 643if_item_not : '!' if_item { $$ = $2; $$->not = 1; } 644 | if_item { $$ = $1; } 645 646if_item : STRING { 647 struct node_host *n; 648 649 if ((n = ifa_exists($1)) == NULL) { 650 yyerror("unknown interface %s", $1); 651 YYERROR; 652 } 653 $$ = malloc(sizeof(struct node_if)); 654 if ($$ == NULL) 655 err(1, "if_item: malloc"); 656 strlcpy($$->ifname, $1, IFNAMSIZ); 657 $$->ifa_flags = n->ifa_flags; 658 $$->not = 0; 659 $$->next = NULL; 660 $$->tail = $$; 661 } 662 ; 663 664af : /* empty */ { $$ = 0; } 665 | INET { $$ = AF_INET; } 666 | INET6 { $$ = AF_INET6; } 667 668proto : /* empty */ { $$ = NULL; } 669 | PROTO proto_item { $$ = $2; } 670 | PROTO '{' proto_list '}' { $$ = $3; } 671 ; 672 673proto_list : proto_item { $$ = $1; } 674 | proto_list comma proto_item { 675 $1->tail->next = $3; 676 $1->tail = $3; 677 $$ = $1; 678 } 679 ; 680 681proto_item : STRING { 682 struct protoent *p; 683 u_long ulval; 684 685 if (atoul($1, &ulval) == 0) 686 p = getprotobynumber(ulval); 687 else 688 p = getprotobyname($1); 689 690 if (p == NULL) { 691 yyerror("unknown protocol %s", $1); 692 YYERROR; 693 } 694 $$ = malloc(sizeof(struct node_proto)); 695 if ($$ == NULL) 696 err(1, "proto_item: malloc"); 697 $$->proto = p->p_proto; 698 $$->next = NULL; 699 $$->tail = $$; 700 } 701 ; 702 703fromto : ALL { 704 $$.src.host = NULL; 705 $$.src.port = NULL; 706 $$.dst.host = NULL; 707 $$.dst.port = NULL; 708 } 709 | FROM ipportspec TO ipportspec { 710 $$.src = $2; 711 $$.dst = $4; 712 } 713 ; 714 715ipportspec : ipspec { $$.host = $1; $$.port = NULL; } 716 | ipspec PORT portspec { 717 $$.host = $1; 718 $$.port = $3; 719 } 720 ; 721 722ipspec : ANY { $$ = NULL; } 723 | xhost { $$ = $1; } 724 | '{' host_list '}' { $$ = $2; } 725 ; 726 727host_list : xhost { $$ = $1; } 728 | host_list comma xhost { 729 /* $3 may be a list, so use its tail pointer */ 730 $1->tail->next = $3->tail; 731 $1->tail = $3->tail; 732 $$ = $1; 733 } 734 ; 735 736xhost : '!' host { 737 struct node_host *h; 738 for (h = $2; h; h = h->next) 739 h->not = 1; 740 $$ = $2; 741 } 742 | host { $$ = $1; } 743 | NOROUTE { 744 $$ = calloc(1, sizeof(struct node_host)); 745 if ($$ == NULL) 746 err(1, "xhost: calloc"); 747 $$->noroute = 1; 748 $$->next = NULL; 749 $$->tail = $$; 750 } 751 ; 752 753host : address 754 | address '/' number { 755 struct node_host *n; 756 for (n = $1; n; n = n->next) { 757 if ($1->af == AF_INET) { 758 if ($3 < 0 || $3 > 32) { 759 yyerror( 760 "illegal netmask value /%d", 761 $3); 762 YYERROR; 763 } 764 } else { 765 if ($3 < 0 || $3 > 128) { 766 yyerror( 767 "illegal netmask value /%d", 768 $3); 769 YYERROR; 770 } 771 } 772 ipmask(&n->mask, $3); 773 } 774 $$ = $1; 775 } 776 ; 777 778number: STRING 779 { 780 u_long ulval; 781 782 if (atoul($1, &ulval) == -1) { 783 yyerror("%s is not a number", $1); 784 YYERROR; 785 } else 786 $$ = ulval; 787 } 788 ; 789 790address : '(' STRING ')' { 791 $$ = calloc(1, sizeof(struct node_host)); 792 if ($$ == NULL) 793 err(1, "address: calloc"); 794 $$->af = 0; 795 ipmask(&$$->mask, 128); 796 $$->addr.addr_dyn = (struct pf_addr_dyn *)1; 797 strncpy($$->addr.addr.pfa.ifname, $2, 798 sizeof($$->addr.addr.pfa.ifname)); 799 } 800 | STRING { $$ = host($1); } 801 ; 802 803portspec : port_item { $$ = $1; } 804 | '{' port_list '}' { $$ = $2; } 805 ; 806 807port_list : port_item { $$ = $1; } 808 | port_list comma port_item { 809 $1->tail->next = $3; 810 $1->tail = $3; 811 $$ = $1; 812 } 813 ; 814 815port_item : port { 816 $$ = malloc(sizeof(struct node_port)); 817 if ($$ == NULL) 818 err(1, "port_item: malloc"); 819 $$->port[0] = $1; 820 $$->port[1] = $1; 821 $$->op = PF_OP_EQ; 822 $$->next = NULL; 823 $$->tail = $$; 824 } 825 | PORTUNARY port { 826 $$ = malloc(sizeof(struct node_port)); 827 if ($$ == NULL) 828 err(1, "port_item: malloc"); 829 $$->port[0] = $2; 830 $$->port[1] = $2; 831 $$->op = $1; 832 $$->next = NULL; 833 $$->tail = $$; 834 } 835 | port PORTBINARY port { 836 $$ = malloc(sizeof(struct node_port)); 837 if ($$ == NULL) 838 err(1, "port_item: malloc"); 839 $$->port[0] = $1; 840 $$->port[1] = $3; 841 $$->op = $2; 842 $$->next = NULL; 843 $$->tail = $$; 844 } 845 ; 846 847port : STRING { 848 struct servent *s = NULL; 849 u_long ulval; 850 851 if (atoul($1, &ulval) == 0) { 852 if (ulval < 0 || ulval > 65535) { 853 yyerror("illegal port value %d", ulval); 854 YYERROR; 855 } 856 $$ = htons(ulval); 857 } else { 858 s = getservbyname($1, "tcp"); 859 if (s == NULL) 860 s = getservbyname($1, "udp"); 861 if (s == NULL) { 862 yyerror("unknown port %s", $1); 863 YYERROR; 864 } 865 $$ = s->s_port; 866 } 867 } 868 ; 869 870uids : /* empty */ { $$ = NULL; } 871 | USER uid_item { $$ = $2; } 872 | USER '{' uid_list '}' { $$ = $3; } 873 ; 874 875uid_list : uid_item { $$ = $1; } 876 | uid_list comma uid_item { 877 $1->tail->next = $3; 878 $1->tail = $3; 879 $$ = $1; 880 } 881 ; 882 883uid_item : uid { 884 $$ = malloc(sizeof(struct node_uid)); 885 if ($$ == NULL) 886 err(1, "uid_item: malloc"); 887 $$->uid[0] = $1; 888 $$->uid[1] = $1; 889 $$->op = PF_OP_EQ; 890 $$->next = NULL; 891 $$->tail = $$; 892 } 893 | PORTUNARY uid { 894 if ($2 == UID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) { 895 yyerror("user unknown requires operator = or !="); 896 YYERROR; 897 } 898 $$ = malloc(sizeof(struct node_uid)); 899 if ($$ == NULL) 900 err(1, "uid_item: malloc"); 901 $$->uid[0] = $2; 902 $$->uid[1] = $2; 903 $$->op = $1; 904 $$->next = NULL; 905 $$->tail = $$; 906 } 907 | uid PORTBINARY uid { 908 if ($1 == UID_MAX || $3 == UID_MAX) { 909 yyerror("user unknown requires operator = or !="); 910 YYERROR; 911 } 912 $$ = malloc(sizeof(struct node_uid)); 913 if ($$ == NULL) 914 err(1, "uid_item: malloc"); 915 $$->uid[0] = $1; 916 $$->uid[1] = $3; 917 $$->op = $2; 918 $$->next = NULL; 919 $$->tail = $$; 920 } 921 ; 922 923uid : STRING { 924 u_long ulval; 925 926 if (atoul($1, &ulval) == -1) { 927 if (!strcmp($1, "unknown")) 928 $$ = UID_MAX; 929 else { 930 struct passwd *pw; 931 932 if ((pw = getpwnam($1)) == NULL) { 933 yyerror("unknown user %s", $1); 934 YYERROR; 935 } 936 $$ = pw->pw_uid; 937 } 938 } else { 939 if (ulval < 0 || ulval >= UID_MAX) { 940 yyerror("illegal uid value %ul", ulval); 941 YYERROR; 942 } 943 $$ = ulval; 944 } 945 } 946 ; 947 948gids : /* empty */ { $$ = NULL; } 949 | GROUP gid_item { $$ = $2; } 950 | GROUP '{' gid_list '}' { $$ = $3; } 951 ; 952 953gid_list : gid_item { $$ = $1; } 954 | gid_list comma gid_item { 955 $1->tail->next = $3; 956 $1->tail = $3; 957 $$ = $1; 958 } 959 ; 960 961gid_item : gid { 962 $$ = malloc(sizeof(struct node_gid)); 963 if ($$ == NULL) 964 err(1, "gid_item: malloc"); 965 $$->gid[0] = $1; 966 $$->gid[1] = $1; 967 $$->op = PF_OP_EQ; 968 $$->next = NULL; 969 $$->tail = $$; 970 } 971 | PORTUNARY gid { 972 if ($2 == GID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) { 973 yyerror("group unknown requires operator = or !="); 974 YYERROR; 975 } 976 $$ = malloc(sizeof(struct node_gid)); 977 if ($$ == NULL) 978 err(1, "gid_item: malloc"); 979 $$->gid[0] = $2; 980 $$->gid[1] = $2; 981 $$->op = $1; 982 $$->next = NULL; 983 $$->tail = $$; 984 } 985 | gid PORTBINARY gid { 986 if ($1 == GID_MAX || $3 == GID_MAX) { 987 yyerror("group unknown requires operator = or !="); 988 YYERROR; 989 } 990 $$ = malloc(sizeof(struct node_gid)); 991 if ($$ == NULL) 992 err(1, "gid_item: malloc"); 993 $$->gid[0] = $1; 994 $$->gid[1] = $3; 995 $$->op = $2; 996 $$->next = NULL; 997 $$->tail = $$; 998 } 999 ; 1000 1001gid : STRING { 1002 u_long ulval; 1003 1004 if (atoul($1, &ulval) == -1) { 1005 if (!strcmp($1, "unknown")) 1006 $$ = GID_MAX; 1007 else { 1008 struct group *grp; 1009 1010 if ((grp = getgrnam($1)) == NULL) { 1011 yyerror("unknown group %s", $1); 1012 YYERROR; 1013 } 1014 $$ = grp->gr_gid; 1015 } 1016 } else { 1017 if (ulval < 0 || ulval >= GID_MAX) { 1018 yyerror("illegal gid value %ul", ulval); 1019 YYERROR; 1020 } 1021 $$ = ulval; 1022 } 1023 } 1024 ; 1025 1026flag : STRING { 1027 int f; 1028 1029 if ((f = parse_flags($1)) < 0) { 1030 yyerror("bad flags %s", $1); 1031 YYERROR; 1032 } 1033 $$.b1 = f; 1034 } 1035 ; 1036 1037flags : /* empty */ { $$.b1 = 0; $$.b2 = 0; } 1038 | FLAGS flag { $$.b1 = $2.b1; $$.b2 = PF_TH_ALL; } 1039 | FLAGS flag "/" flag { $$.b1 = $2.b1; $$.b2 = $4.b1; } 1040 | FLAGS "/" flag { $$.b1 = 0; $$.b2 = $3.b1; } 1041 ; 1042 1043icmpspec : /* empty */ { $$ = NULL; } 1044 | ICMPTYPE icmp_item { $$ = $2; } 1045 | ICMPTYPE '{' icmp_list '}' { $$ = $3; } 1046 | ICMP6TYPE icmp6_item { $$ = $2; } 1047 | ICMP6TYPE '{' icmp6_list '}' { $$ = $3; } 1048 ; 1049 1050icmp_list : icmp_item { $$ = $1; } 1051 | icmp_list comma icmp_item { 1052 $1->tail->next = $3; 1053 $1->tail = $3; 1054 $$ = $1; 1055 } 1056 ; 1057 1058icmp6_list : icmp6_item { $$ = $1; } 1059 | icmp6_list comma icmp6_item { 1060 $1->tail->next = $3; 1061 $1->tail = $3; 1062 $$ = $1; 1063 } 1064 ; 1065 1066icmp_item : icmptype { 1067 $$ = malloc(sizeof(struct node_icmp)); 1068 if ($$ == NULL) 1069 err(1, "icmp_item: malloc"); 1070 $$->type = $1; 1071 $$->code = 0; 1072 $$->proto = IPPROTO_ICMP; 1073 $$->next = NULL; 1074 $$->tail = $$; 1075 } 1076 | icmptype CODE STRING { 1077 const struct icmpcodeent *p; 1078 u_long ulval; 1079 1080 if (atoul($3, &ulval) == 0) { 1081 if (ulval < 0 || ulval > 255) { 1082 yyerror("illegal icmp-code %d", ulval); 1083 YYERROR; 1084 } 1085 } else { 1086 if ((p = geticmpcodebyname($1, $3, 1087 AF_INET)) == NULL) { 1088 yyerror("unknown icmp-code %s", $3); 1089 YYERROR; 1090 } 1091 ulval = p->code; 1092 } 1093 $$ = malloc(sizeof(struct node_icmp)); 1094 if ($$ == NULL) 1095 err(1, "icmp_item: malloc"); 1096 $$->type = $1; 1097 $$->code = ulval + 1; 1098 $$->proto = IPPROTO_ICMP; 1099 $$->next = NULL; 1100 $$->tail = $$; 1101 } 1102 ; 1103 1104icmp6_item : icmp6type { 1105 $$ = malloc(sizeof(struct node_icmp)); 1106 if ($$ == NULL) 1107 err(1, "icmp_item: malloc"); 1108 $$->type = $1; 1109 $$->code = 0; 1110 $$->proto = IPPROTO_ICMPV6; 1111 $$->next = NULL; 1112 $$->tail = $$; 1113 } 1114 | icmp6type CODE STRING { 1115 const struct icmpcodeent *p; 1116 u_long ulval; 1117 1118 if (atoul($3, &ulval) == 0) { 1119 if (ulval < 0 || ulval > 255) { 1120 yyerror("illegal icmp6-code %ld", ulval); 1121 YYERROR; 1122 } 1123 } else { 1124 if ((p = geticmpcodebyname($1, $3, 1125 AF_INET6)) == NULL) { 1126 yyerror("unknown icmp6-code %s", $3); 1127 YYERROR; 1128 } 1129 ulval = p->code; 1130 } 1131 $$ = malloc(sizeof(struct node_icmp)); 1132 if ($$ == NULL) 1133 err(1, "icmp_item: malloc"); 1134 $$->type = $1; 1135 $$->code = ulval + 1; 1136 $$->proto = IPPROTO_ICMPV6; 1137 $$->next = NULL; 1138 $$->tail = $$; 1139 } 1140 ; 1141 1142icmptype : STRING { 1143 const struct icmptypeent *p; 1144 u_long ulval; 1145 1146 if (atoul($1, &ulval) == 0) { 1147 if (ulval < 0 || ulval > 255) { 1148 yyerror("illegal icmp-type %d", ulval); 1149 YYERROR; 1150 } 1151 $$ = ulval + 1; 1152 } else { 1153 if ((p = geticmptypebyname($1, AF_INET)) == NULL) { 1154 yyerror("unknown icmp-type %s", $1); 1155 YYERROR; 1156 } 1157 $$ = p->type + 1; 1158 } 1159 } 1160 ; 1161 1162icmp6type : STRING { 1163 const struct icmptypeent *p; 1164 u_long ulval; 1165 1166 if (atoul($1, &ulval) == 0) { 1167 if (ulval < 0 || ulval > 255) { 1168 yyerror("illegal icmp6-type %d", ulval); 1169 YYERROR; 1170 } 1171 $$ = ulval + 1; 1172 } else { 1173 if ((p = geticmptypebyname($1, AF_INET6)) == NULL) { 1174 yyerror("unknown ipv6-icmp-type %s", $1); 1175 YYERROR; 1176 } 1177 $$ = p->type + 1; 1178 } 1179 } 1180 ; 1181 1182tos : /* empty */ { $$ = 0; } 1183 | TOS STRING { 1184 if (!strcmp($2, "lowdelay")) 1185 $$ = IPTOS_LOWDELAY; 1186 else if (!strcmp($2, "throughput")) 1187 $$ = IPTOS_THROUGHPUT; 1188 else if (!strcmp($2, "reliability")) 1189 $$ = IPTOS_RELIABILITY; 1190 else if ($2[0] == '0' && $2[1] == 'x') 1191 $$ = strtoul($2, NULL, 16); 1192 else 1193 $$ = strtoul($2, NULL, 10); 1194 if (!$$ || $$ > 255) { 1195 yyerror("illegal tos value %s", $2); 1196 YYERROR; 1197 } 1198 } 1199 ; 1200 1201keep : /* empty */ { 1202 $$.action = 0; 1203 $$.options = NULL; 1204 } 1205 | KEEP STATE state_opt_spec { 1206 $$.action = PF_STATE_NORMAL; 1207 $$.options = $3; 1208 } 1209 | MODULATE STATE state_opt_spec { 1210 $$.action = PF_STATE_MODULATE; 1211 $$.options = $3; 1212 } 1213 ; 1214 1215state_opt_spec : /* empty */ { $$ = NULL; } 1216 | '(' state_opt_list ')' { $$ = $2; } 1217 ; 1218 1219state_opt_list : state_opt_item { $$ = $1; } 1220 | state_opt_list comma state_opt_item { 1221 $1->tail->next = $3; 1222 $1->tail = $3; 1223 $$ = $1; 1224 } 1225 ; 1226 1227state_opt_item : MAXIMUM number { 1228 if ($2 <= 0) { 1229 yyerror("illegal states max value %d", $2); 1230 YYERROR; 1231 } 1232 $$ = calloc(1, sizeof(struct node_state_opt)); 1233 if ($$ == NULL) 1234 err(1, "state_opt_item: calloc"); 1235 $$->type = PF_STATE_OPT_MAX; 1236 $$->data.max_states = $2; 1237 $$->next = NULL; 1238 $$->tail = $$; 1239 } 1240 | STRING number { 1241 int i; 1242 1243 for (i = 0; pf_timeouts[i].name && 1244 strcmp(pf_timeouts[i].name, $1); ++i); 1245 if (!pf_timeouts[i].name) { 1246 yyerror("illegal timeout name %s", $1); 1247 YYERROR; 1248 } 1249 if (strchr(pf_timeouts[i].name, '.') == NULL) { 1250 yyerror("illegal state timeout %s", $1); 1251 YYERROR; 1252 } 1253 if ($2 < 0) { 1254 yyerror("illegal timeout value %d", $2); 1255 YYERROR; 1256 } 1257 $$ = calloc(1, sizeof(struct node_state_opt)); 1258 if ($$ == NULL) 1259 err(1, "state_opt_item: calloc"); 1260 $$->type = PF_STATE_OPT_TIMEOUT; 1261 $$->data.timeout.number = pf_timeouts[i].timeout; 1262 $$->data.timeout.seconds = $2; 1263 $$->next = NULL; 1264 $$->tail = $$; 1265 } 1266 ; 1267 1268fragment : /* empty */ { $$ = 0; } 1269 | FRAGMENT { $$ = 1; } 1270 1271minttl : /* empty */ { $$ = 0; } 1272 | MINTTL number { 1273 if ($2 < 0 || $2 > 255) { 1274 yyerror("illegal min-ttl value %d", $2); 1275 YYERROR; 1276 } 1277 $$ = $2; 1278 } 1279 ; 1280 1281nodf : /* empty */ { $$ = 0; } 1282 | NODF { $$ = 1; } 1283 ; 1284 1285maxmss : /* empty */ { $$ = 0; } 1286 | MAXMSS number { 1287 if ($2 < 0) { 1288 yyerror("illegal max-mss value %d", $2); 1289 YYERROR; 1290 } 1291 $$ = $2; 1292 } 1293 ; 1294 1295allowopts : /* empty */ { $$ = 0; } 1296 | ALLOWOPTS { $$ = 1; } 1297 1298label : /* empty */ { $$ = NULL; } 1299 | LABEL STRING { 1300 if (($$ = strdup($2)) == NULL) { 1301 yyerror("rule label strdup() failed"); 1302 YYERROR; 1303 } 1304 } 1305 ; 1306 1307no : /* empty */ { $$ = 0; } 1308 | NO { $$ = 1; } 1309 ; 1310 1311rport : STRING { 1312 char *p = strchr($1, ':'); 1313 1314 if (p == NULL) { 1315 if (($$.a = getservice($1)) == -1) 1316 YYERROR; 1317 $$.b = $$.t = 0; 1318 } else if (!strcmp(p+1, "*")) { 1319 *p = 0; 1320 if (($$.a = getservice($1)) == -1) 1321 YYERROR; 1322 $$.b = 0; 1323 $$.t = PF_RPORT_RANGE; 1324 } else { 1325 *p++ = 0; 1326 if (($$.a = getservice($1)) == -1 || 1327 ($$.b = getservice(p)) == -1) 1328 YYERROR; 1329 $$.t = PF_RPORT_RANGE; 1330 } 1331 } 1332 ; 1333 1334redirection : /* empty */ { $$ = NULL; } 1335 | ARROW address { 1336 $$ = malloc(sizeof(struct redirection)); 1337 if ($$ == NULL) 1338 err(1, "redirection: malloc"); 1339 $$->address = $2; 1340 $$->rport.a = $$->rport.b = $$->rport.t = 0; 1341 } 1342 | ARROW address PORT rport { 1343 $$ = malloc(sizeof(struct redirection)); 1344 if ($$ == NULL) 1345 err(1, "redirection: malloc"); 1346 $$->address = $2; 1347 $$->rport = $4; 1348 } 1349 ; 1350 1351natrule : no NAT interface af proto fromto redirection 1352 { 1353 struct pf_nat nat; 1354 1355 if (check_rulestate(PFCTL_STATE_NAT)) 1356 YYERROR; 1357 1358 memset(&nat, 0, sizeof(nat)); 1359 1360 nat.no = $1; 1361 nat.af = $4; 1362 1363 if (!nat.af) { 1364 if ($6.src.host && $6.src.host->af 1365 && !$6.src.host->ifindex) 1366 nat.af = $6.src.host->af; 1367 else if ($6.dst.host && $6.dst.host->af 1368 && !$6.dst.host->ifindex) 1369 nat.af = $6.dst.host->af; 1370 } 1371 1372 if (nat.no) { 1373 if ($7 != NULL) { 1374 yyerror("'no nat' rule does not need " 1375 "'->'"); 1376 YYERROR; 1377 } 1378 } else { 1379 struct node_host *n; 1380 1381 if ($7 == NULL || $7->address == NULL) { 1382 yyerror("'nat' rule requires '-> " 1383 "address'"); 1384 YYERROR; 1385 } 1386 if (!nat.af && !$7->address->ifindex) 1387 nat.af = $7->address->af; 1388 n = ifa_pick_ip($7->address, nat.af); 1389 if (n == NULL) 1390 YYERROR; 1391 if (!nat.af) 1392 nat.af = n->af; 1393 memcpy(&nat.raddr, &n->addr, 1394 sizeof(nat.raddr)); 1395 nat.proxy_port[0] = ntohs($7->rport.a); 1396 nat.proxy_port[1] = ntohs($7->rport.b); 1397 if (!nat.proxy_port[0] && !nat.proxy_port[1]) { 1398 nat.proxy_port[0] = 1399 PF_NAT_PROXY_PORT_LOW; 1400 nat.proxy_port[1] = 1401 PF_NAT_PROXY_PORT_HIGH; 1402 } else if (!nat.proxy_port[1]) 1403 nat.proxy_port[1] = nat.proxy_port[0]; 1404 free($7->address); 1405 free($7); 1406 } 1407 1408 expand_nat(&nat, $3, $5, $6.src.host, $6.src.port, 1409 $6.dst.host, $6.dst.port); 1410 } 1411 ; 1412 1413binatrule : no BINAT interface af proto FROM address TO ipspec redirection 1414 { 1415 struct pf_binat binat; 1416 1417 if (check_rulestate(PFCTL_STATE_NAT)) 1418 YYERROR; 1419 1420 memset(&binat, 0, sizeof(binat)); 1421 1422 binat.no = $1; 1423 if ($3 != NULL) { 1424 memcpy(binat.ifname, $3->ifname, 1425 sizeof(binat.ifname)); 1426 free($3); 1427 } 1428 binat.af = $4; 1429 if ($5 != NULL) { 1430 binat.proto = $5->proto; 1431 free($5); 1432 } 1433 if ($7 != NULL && $9 != NULL && $7->af != $9->af) { 1434 yyerror("binat ip versions must match"); 1435 YYERROR; 1436 } 1437 if ($7 != NULL) { 1438 if ($7->next) { 1439 yyerror("multiple binat ip addresses"); 1440 YYERROR; 1441 } 1442 if ($7->addr.addr_dyn != NULL) { 1443 if (!binat.af) { 1444 yyerror("address family (inet/" 1445 "inet6) undefined"); 1446 YYERROR; 1447 } 1448 $7->af = binat.af; 1449 } 1450 if (binat.af && $7->af != binat.af) { 1451 yyerror("binat ip versions must match"); 1452 YYERROR; 1453 } 1454 binat.af = $7->af; 1455 memcpy(&binat.saddr, &$7->addr, 1456 sizeof(binat.saddr)); 1457 free($7); 1458 } 1459 if ($9 != NULL) { 1460 if ($9->next) { 1461 yyerror("multiple binat ip addresses"); 1462 YYERROR; 1463 } 1464 if ($9->addr.addr_dyn != NULL) { 1465 if (!binat.af) { 1466 yyerror("address family (inet/" 1467 "inet6) undefined"); 1468 YYERROR; 1469 } 1470 $9->af = binat.af; 1471 } 1472 if (binat.af && $9->af != binat.af) { 1473 yyerror("binat ip versions must match"); 1474 YYERROR; 1475 } 1476 binat.af = $9->af; 1477 memcpy(&binat.daddr, &$9->addr, 1478 sizeof(binat.daddr)); 1479 memcpy(&binat.dmask, &$9->mask, 1480 sizeof(binat.dmask)); 1481 binat.dnot = $9->not; 1482 free($9); 1483 } 1484 1485 if (binat.no) { 1486 if ($10 != NULL) { 1487 yyerror("'no binat' rule does not need" 1488 " '->'"); 1489 YYERROR; 1490 } 1491 } else { 1492 struct node_host *n; 1493 1494 if ($10 == NULL || $10->address == NULL) { 1495 yyerror("'binat' rule requires" 1496 " '-> address'"); 1497 YYERROR; 1498 } 1499 n = ifa_pick_ip($10->address, binat.af); 1500 if (n == NULL) 1501 YYERROR; 1502 if (n->addr.addr_dyn != NULL) { 1503 if (!binat.af) { 1504 yyerror("address family (inet/" 1505 "inet6) undefined"); 1506 YYERROR; 1507 } 1508 n->af = binat.af; 1509 } 1510 if (binat.af && n->af != binat.af) { 1511 yyerror("binat ip versions must match"); 1512 YYERROR; 1513 } 1514 binat.af = n->af; 1515 memcpy(&binat.raddr, &n->addr, 1516 sizeof(binat.raddr)); 1517 free($10->address); 1518 free($10); 1519 } 1520 1521 pfctl_add_binat(pf, &binat); 1522 } 1523 1524rdrrule : no RDR interface af proto FROM ipspec TO ipspec dport redirection 1525 { 1526 struct pf_rdr rdr; 1527 1528 if (check_rulestate(PFCTL_STATE_NAT)) 1529 YYERROR; 1530 1531 memset(&rdr, 0, sizeof(rdr)); 1532 1533 rdr.no = $1; 1534 rdr.af = $4; 1535 if ($7 != NULL) { 1536 memcpy(&rdr.saddr, &$7->addr, 1537 sizeof(rdr.saddr)); 1538 memcpy(&rdr.smask, &$7->mask, 1539 sizeof(rdr.smask)); 1540 rdr.snot = $7->not; 1541 if (!rdr.af && !$7->ifindex) 1542 rdr.af = $7->af; 1543 } 1544 if ($9 != NULL) { 1545 memcpy(&rdr.daddr, &$9->addr, 1546 sizeof(rdr.daddr)); 1547 memcpy(&rdr.dmask, &$9->mask, 1548 sizeof(rdr.dmask)); 1549 rdr.dnot = $9->not; 1550 if (!rdr.af && !$9->ifindex) 1551 rdr.af = $9->af; 1552 } 1553 1554 rdr.dport = $10.a; 1555 rdr.dport2 = $10.b; 1556 rdr.opts |= $10.t; 1557 1558 if (rdr.no) { 1559 if ($11 != NULL) { 1560 yyerror("'no rdr' rule does not need '->'"); 1561 YYERROR; 1562 } 1563 } else { 1564 struct node_host *n; 1565 1566 if ($11 == NULL || $11->address == NULL) { 1567 yyerror("'rdr' rule requires '-> " 1568 "address'"); 1569 YYERROR; 1570 } 1571 if (!rdr.af && !$11->address->ifindex) 1572 rdr.af = $11->address->af; 1573 n = ifa_pick_ip($11->address, rdr.af); 1574 if (n == NULL) 1575 YYERROR; 1576 if (!rdr.af) 1577 rdr.af = n->af; 1578 memcpy(&rdr.raddr, &n->addr, 1579 sizeof(rdr.raddr)); 1580 free($11->address); 1581 rdr.rport = $11->rport.a; 1582 rdr.opts |= $11->rport.t; 1583 free($11); 1584 } 1585 1586 expand_rdr(&rdr, $3, $5, $7, $9); 1587 } 1588 ; 1589 1590dport : /* empty */ { 1591 $$.a = $$.b = $$.t = 0; 1592 } 1593 | PORT STRING { 1594 char *p = strchr($2, ':'); 1595 1596 if (p == NULL) { 1597 if (($$.a = getservice($2)) == -1) 1598 YYERROR; 1599 $$.b = $$.t = 0; 1600 } else { 1601 *p++ = 0; 1602 if (($$.a = getservice($2)) == -1 || 1603 ($$.b = getservice(p)) == -1) 1604 YYERROR; 1605 $$.t = PF_DPORT_RANGE; 1606 } 1607 } 1608 ; 1609 1610route : /* empty */ { 1611 $$.string = NULL; 1612 $$.rt = 0; 1613 $$.addr = NULL; 1614 $$.af = 0; 1615 } 1616 | FASTROUTE { 1617 $$.string = NULL; 1618 $$.rt = PF_FASTROUTE; 1619 $$.addr = NULL; 1620 } 1621 | ROUTETO '(' STRING address ')' { 1622 if (($$.string = strdup($3)) == NULL) { 1623 yyerror("routeto: strdup"); 1624 YYERROR; 1625 } 1626 $$.rt = PF_ROUTETO; 1627 if ($4->addr.addr_dyn != NULL) { 1628 yyerror("route-to does not support" 1629 " dynamic addresses"); 1630 YYERROR; 1631 } 1632 if ($4->next) { 1633 yyerror("multiple route-to ip addresses"); 1634 YYERROR; 1635 } 1636 $$.addr = &$4->addr.addr; 1637 $$.af = $4->af; 1638 } 1639 | ROUTETO STRING { 1640 if (($$.string = strdup($2)) == NULL) { 1641 yyerror("routeto: strdup"); 1642 YYERROR; 1643 } 1644 $$.rt = PF_ROUTETO; 1645 $$.addr = NULL; 1646 } 1647 | REPLYTO '(' STRING address ')' { 1648 if (($$.string = strdup($3)) == NULL) { 1649 yyerror("reply-to: strdup"); 1650 YYERROR; 1651 } 1652 $$.rt = PF_REPLYTO; 1653 if ($4->addr.addr_dyn != NULL) { 1654 yyerror("reply-to does not support" 1655 " dynamic addresses"); 1656 YYERROR; 1657 } 1658 if ($4->next) { 1659 yyerror("multiple reply-to ip addresses"); 1660 YYERROR; 1661 } 1662 $$.addr = &$4->addr.addr; 1663 $$.af = $4->af; 1664 } 1665 | REPLYTO STRING { 1666 if (($$.string = strdup($2)) == NULL) { 1667 yyerror("reply-to: strdup"); 1668 YYERROR; 1669 } 1670 $$.rt = PF_REPLYTO; 1671 $$.addr = NULL; 1672 } 1673 | DUPTO '(' STRING address ')' { 1674 if (($$.string = strdup($3)) == NULL) { 1675 yyerror("dupto: strdup"); 1676 YYERROR; 1677 } 1678 $$.rt = PF_DUPTO; 1679 if ($4->addr.addr_dyn != NULL) { 1680 yyerror("dup-to does not support" 1681 " dynamic addresses"); 1682 YYERROR; 1683 } 1684 if ($4->next) { 1685 yyerror("multiple dup-to ip addresses"); 1686 YYERROR; 1687 } 1688 $$.addr = &$4->addr.addr; 1689 $$.af = $4->af; 1690 } 1691 | DUPTO STRING { 1692 if (($$.string = strdup($2)) == NULL) { 1693 yyerror("dupto: strdup"); 1694 YYERROR; 1695 } 1696 $$.rt = PF_DUPTO; 1697 $$.addr = NULL; 1698 } 1699 ; 1700 1701timeout_spec : STRING number 1702 { 1703 if (pf->opts & PF_OPT_VERBOSE) 1704 printf("set timeout %s %us\n", $1, $2); 1705 if (check_rulestate(PFCTL_STATE_OPTION)) 1706 YYERROR; 1707 if (pfctl_set_timeout(pf, $1, $2) != 0) { 1708 yyerror("unknown timeout %s", $1); 1709 YYERROR; 1710 } 1711 } 1712 ; 1713 1714timeout_list : timeout_list comma timeout_spec 1715 | timeout_spec 1716 ; 1717 1718limit_spec : STRING number 1719 { 1720 if (pf->opts & PF_OPT_VERBOSE) 1721 printf("set limit %s %u\n", $1, $2); 1722 if (check_rulestate(PFCTL_STATE_OPTION)) 1723 YYERROR; 1724 if (pfctl_set_limit(pf, $1, $2) != 0) { 1725 yyerror("unable to set limit %s %u", $1, $2); 1726 YYERROR; 1727 } 1728 } 1729 1730limit_list : limit_list comma limit_spec 1731 | limit_spec 1732 ; 1733 1734comma : ',' 1735 | /* empty */ 1736 ; 1737 1738%% 1739 1740int 1741yyerror(char *fmt, ...) 1742{ 1743 va_list ap; 1744 extern char *infile; 1745 errors = 1; 1746 1747 va_start(ap, fmt); 1748 fprintf(stderr, "%s:%d: ", infile, yylval.lineno); 1749 vfprintf(stderr, fmt, ap); 1750 fprintf(stderr, "\n"); 1751 va_end(ap); 1752 return (0); 1753} 1754 1755int 1756rule_consistent(struct pf_rule *r) 1757{ 1758 int problems = 0; 1759 1760 if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP && 1761 (r->src.port_op || r->dst.port_op)) { 1762 yyerror("port only applies to tcp/udp"); 1763 problems++; 1764 } 1765 if (r->proto != IPPROTO_ICMP && r->proto != IPPROTO_ICMPV6 && 1766 (r->type || r->code)) { 1767 yyerror("icmp-type/code only applies to icmp"); 1768 problems++; 1769 } 1770 if (!r->af && (r->type || r->code)) { 1771 yyerror("must indicate address family with icmp-type/code"); 1772 problems++; 1773 } 1774 if ((r->proto == IPPROTO_ICMP && r->af == AF_INET6) || 1775 (r->proto == IPPROTO_ICMPV6 && r->af == AF_INET)) { 1776 yyerror("icmp version does not match address family"); 1777 problems++; 1778 } 1779 if (!(r->rule_flag & PFRULE_RETURNRST) && r->return_icmp && 1780 ((r->af != AF_INET6 && (r->return_icmp>>8) != ICMP_UNREACH) || 1781 (r->af == AF_INET6 && (r->return_icmp>>8) != ICMP6_DST_UNREACH))) { 1782 yyerror("return-icmp version does not match address family"); 1783 problems++; 1784 } 1785 if (r->keep_state == PF_STATE_MODULATE && r->proto && 1786 r->proto != IPPROTO_TCP) { 1787 yyerror("modulate state can only be applied to TCP rules"); 1788 problems++; 1789 } 1790 if (r->allow_opts && r->action != PF_PASS) { 1791 yyerror("allow-opts can only be specified for pass rules"); 1792 problems++; 1793 } 1794 if (!r->af && (r->src.addr.addr_dyn != NULL || 1795 r->dst.addr.addr_dyn != NULL)) { 1796 yyerror("dynamic addresses require address family (inet/inet6)"); 1797 problems++; 1798 } 1799 if (r->rule_flag & PFRULE_FRAGMENT && (r->src.port_op || 1800 r->dst.port_op || r->flagset || r->type || r->code)) { 1801 yyerror("fragments can be filtered only on IP header fields"); 1802 problems++; 1803 } 1804 if (r->rule_flag & PFRULE_RETURNRST && r->proto != IPPROTO_TCP) { 1805 yyerror("return-rst can only be applied to TCP rules"); 1806 problems++; 1807 } 1808 if (r->action == PF_DROP && r->keep_state) { 1809 yyerror("keep state on block rules doesn't make sense"); 1810 problems++; 1811 } 1812 return (-problems); 1813} 1814 1815int 1816nat_consistent(struct pf_nat *r) 1817{ 1818 int problems = 0; 1819 1820 if (!r->af && (r->raddr.addr_dyn != NULL)) { 1821 yyerror("dynamic addresses require address family (inet/inet6)"); 1822 problems++; 1823 } 1824 return (-problems); 1825} 1826 1827int 1828rdr_consistent(struct pf_rdr *r) 1829{ 1830 int problems = 0; 1831 1832 if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP && 1833 (r->dport || r->dport2 || r->rport)) { 1834 yyerror("port only applies to tcp/udp"); 1835 problems++; 1836 } 1837 if (!r->af && (r->saddr.addr_dyn != NULL || 1838 r->daddr.addr_dyn != NULL || r->raddr.addr_dyn != NULL)) { 1839 yyerror("dynamic addresses require address family (inet/inet6)"); 1840 problems++; 1841 } 1842 return (-problems); 1843} 1844 1845struct keywords { 1846 const char *k_name; 1847 int k_val; 1848}; 1849 1850/* macro gore, but you should've seen the prior indentation nightmare... */ 1851 1852#define FREE_LIST(T,r) \ 1853 do { \ 1854 T *p, *n = r; \ 1855 while (n != NULL) { \ 1856 p = n; \ 1857 n = n->next; \ 1858 free(p); \ 1859 } \ 1860 } while (0) 1861 1862#define LOOP_THROUGH(T,n,r,C) \ 1863 do { \ 1864 T *n; \ 1865 if (r == NULL) { \ 1866 r = calloc(1, sizeof(T)); \ 1867 if (r == NULL) \ 1868 err(1, "LOOP: calloc"); \ 1869 r->next = NULL; \ 1870 } \ 1871 n = r; \ 1872 while (n != NULL) { \ 1873 do { \ 1874 C; \ 1875 } while (0); \ 1876 n = n->next; \ 1877 } \ 1878 } while (0) 1879 1880void 1881expand_label_addr(const char *name, char *label, u_int8_t af, 1882 struct node_host *host) 1883{ 1884 char tmp[PF_RULE_LABEL_SIZE]; 1885 char *p; 1886 1887 while ((p = strstr(label, name)) != NULL) { 1888 tmp[0] = 0; 1889 1890 strlcat(tmp, label, p-label+1); 1891 1892 if (host->not) 1893 strlcat(tmp, "! ", PF_RULE_LABEL_SIZE); 1894 if (host->addr.addr_dyn != NULL) { 1895 strlcat(tmp, "(", PF_RULE_LABEL_SIZE); 1896 strlcat(tmp, host->addr.addr.pfa.ifname, 1897 PF_RULE_LABEL_SIZE); 1898 strlcat(tmp, ")", PF_RULE_LABEL_SIZE); 1899 } else if (!af || (PF_AZERO(&host->addr.addr, af) && 1900 PF_AZERO(&host->mask, af))) 1901 strlcat(tmp, "any", PF_RULE_LABEL_SIZE); 1902 else { 1903 char a[48]; 1904 int bits; 1905 1906 if (inet_ntop(af, &host->addr.addr, a, 1907 sizeof(a)) == NULL) 1908 strlcat(a, "?", sizeof(a)); 1909 strlcat(tmp, a, PF_RULE_LABEL_SIZE); 1910 bits = unmask(&host->mask, af); 1911 a[0] = 0; 1912 if ((af == AF_INET && bits < 32) || 1913 (af == AF_INET6 && bits < 128)) 1914 snprintf(a, sizeof(a), "/%u", bits); 1915 strlcat(tmp, a, PF_RULE_LABEL_SIZE); 1916 } 1917 strlcat(tmp, p+strlen(name), PF_RULE_LABEL_SIZE); 1918 strncpy(label, tmp, PF_RULE_LABEL_SIZE); 1919 } 1920} 1921 1922void 1923expand_label_port(const char *name, char *label, struct node_port *port) 1924{ 1925 char tmp[PF_RULE_LABEL_SIZE]; 1926 char *p; 1927 char a1[6], a2[6], op[13]; 1928 1929 while ((p = strstr(label, name)) != NULL) { 1930 tmp[0] = 0; 1931 1932 strlcat(tmp, label, p-label+1); 1933 1934 snprintf(a1, sizeof(a1), "%u", ntohs(port->port[0])); 1935 snprintf(a2, sizeof(a2), "%u", ntohs(port->port[1])); 1936 if (!port->op) 1937 op[0] = 0; 1938 else if (port->op == PF_OP_IRG) 1939 snprintf(op, sizeof(op), "%s><%s", a1, a2); 1940 else if (port->op == PF_OP_XRG) 1941 snprintf(op, sizeof(op), "%s<>%s", a1, a2); 1942 else if (port->op == PF_OP_EQ) 1943 snprintf(op, sizeof(op), "%s", a1); 1944 else if (port->op == PF_OP_NE) 1945 snprintf(op, sizeof(op), "!=%s", a1); 1946 else if (port->op == PF_OP_LT) 1947 snprintf(op, sizeof(op), "<%s", a1); 1948 else if (port->op == PF_OP_LE) 1949 snprintf(op, sizeof(op), "<=%s", a1); 1950 else if (port->op == PF_OP_GT) 1951 snprintf(op, sizeof(op), ">%s", a1); 1952 else if (port->op == PF_OP_GE) 1953 snprintf(op, sizeof(op), ">=%s", a1); 1954 strlcat(tmp, op, PF_RULE_LABEL_SIZE); 1955 strlcat(tmp, p+strlen(name), PF_RULE_LABEL_SIZE); 1956 strncpy(label, tmp, PF_RULE_LABEL_SIZE); 1957 } 1958} 1959 1960void 1961expand_label_proto(const char *name, char *label, u_int8_t proto) 1962{ 1963 char tmp[PF_RULE_LABEL_SIZE]; 1964 char *p; 1965 struct protoent *pe; 1966 1967 while ((p = strstr(label, name)) != NULL) { 1968 tmp[0] = 0; 1969 strlcat(tmp, label, p-label+1); 1970 pe = getprotobynumber(proto); 1971 if (pe != NULL) 1972 strlcat(tmp, pe->p_name, PF_RULE_LABEL_SIZE); 1973 else 1974 snprintf(tmp+strlen(tmp), PF_RULE_LABEL_SIZE-strlen(tmp), 1975 "%u", proto); 1976 strlcat(tmp, p+strlen(name), PF_RULE_LABEL_SIZE); 1977 strncpy(label, tmp, PF_RULE_LABEL_SIZE); 1978 } 1979} 1980 1981void 1982expand_label_nr(const char *name, char *label) 1983{ 1984 char tmp[PF_RULE_LABEL_SIZE]; 1985 char *p; 1986 1987 while ((p = strstr(label, name)) != NULL) { 1988 tmp[0] = 0; 1989 strlcat(tmp, label, p-label+1); 1990 snprintf(tmp+strlen(tmp), PF_RULE_LABEL_SIZE-strlen(tmp), 1991 "%u", pf->rule_nr); 1992 strlcat(tmp, p+strlen(name), PF_RULE_LABEL_SIZE); 1993 strncpy(label, tmp, PF_RULE_LABEL_SIZE); 1994 } 1995} 1996 1997void 1998expand_label(char *label, u_int8_t af, 1999 struct node_host *src_host, struct node_port *src_port, 2000 struct node_host *dst_host, struct node_port *dst_port, 2001 u_int8_t proto) 2002{ 2003 expand_label_addr("$srcaddr", label, af, src_host); 2004 expand_label_addr("$dstaddr", label, af, dst_host); 2005 expand_label_port("$srcport", label, src_port); 2006 expand_label_port("$dstport", label, dst_port); 2007 expand_label_proto("$proto", label, proto); 2008 expand_label_nr("$nr", label); 2009} 2010 2011void 2012expand_rule(struct pf_rule *r, 2013 struct node_if *interfaces, struct node_proto *protos, 2014 struct node_host *src_hosts, struct node_port *src_ports, 2015 struct node_host *dst_hosts, struct node_port *dst_ports, 2016 struct node_uid *uids, struct node_gid *gids, 2017 struct node_icmp *icmp_types) 2018{ 2019 int af = r->af, nomatch = 0, added = 0; 2020 char ifname[IF_NAMESIZE]; 2021 char label[PF_RULE_LABEL_SIZE]; 2022 u_int8_t flags, flagset; 2023 2024 strlcpy(label, r->label, sizeof(label)); 2025 flags = r->flags; 2026 flagset = r->flagset; 2027 2028 LOOP_THROUGH(struct node_if, interface, interfaces, 2029 LOOP_THROUGH(struct node_proto, proto, protos, 2030 LOOP_THROUGH(struct node_icmp, icmp_type, icmp_types, 2031 LOOP_THROUGH(struct node_host, src_host, src_hosts, 2032 LOOP_THROUGH(struct node_port, src_port, src_ports, 2033 LOOP_THROUGH(struct node_host, dst_host, dst_hosts, 2034 LOOP_THROUGH(struct node_port, dst_port, dst_ports, 2035 LOOP_THROUGH(struct node_uid, uid, uids, 2036 LOOP_THROUGH(struct node_gid, gid, gids, 2037 2038 r->af = af; 2039 /* for link-local IPv6 address, interface must match up */ 2040 if ((r->af && src_host->af && r->af != src_host->af) || 2041 (r->af && dst_host->af && r->af != dst_host->af) || 2042 (src_host->af && dst_host->af && 2043 src_host->af != dst_host->af) || 2044 (src_host->ifindex && dst_host->ifindex && 2045 src_host->ifindex != dst_host->ifindex) || 2046 (src_host->ifindex && if_nametoindex(interface->ifname) && 2047 src_host->ifindex != if_nametoindex(interface->ifname)) || 2048 (dst_host->ifindex && if_nametoindex(interface->ifname) && 2049 dst_host->ifindex != if_nametoindex(interface->ifname))) 2050 continue; 2051 if (!r->af && src_host->af) 2052 r->af = src_host->af; 2053 else if (!r->af && dst_host->af) 2054 r->af = dst_host->af; 2055 2056 if (if_indextoname(src_host->ifindex, ifname)) 2057 memcpy(r->ifname, ifname, sizeof(r->ifname)); 2058 else if (if_indextoname(dst_host->ifindex, ifname)) 2059 memcpy(r->ifname, ifname, sizeof(r->ifname)); 2060 else 2061 memcpy(r->ifname, interface->ifname, sizeof(r->ifname)); 2062 2063 strlcpy(r->label, label, PF_RULE_LABEL_SIZE); 2064 expand_label(r->label, r->af, src_host, src_port, 2065 dst_host, dst_port, proto->proto); 2066 r->ifnot = interface->not; 2067 r->proto = proto->proto; 2068 r->src.addr = src_host->addr; 2069 r->src.mask = src_host->mask; 2070 r->src.noroute = src_host->noroute; 2071 r->src.not = src_host->not; 2072 r->src.port[0] = src_port->port[0]; 2073 r->src.port[1] = src_port->port[1]; 2074 r->src.port_op = src_port->op; 2075 r->dst.addr = dst_host->addr; 2076 r->dst.mask = dst_host->mask; 2077 r->dst.noroute = dst_host->noroute; 2078 r->dst.not = dst_host->not; 2079 r->dst.port[0] = dst_port->port[0]; 2080 r->dst.port[1] = dst_port->port[1]; 2081 r->dst.port_op = dst_port->op; 2082 r->uid.op = uid->op; 2083 r->uid.uid[0] = uid->uid[0]; 2084 r->uid.uid[1] = uid->uid[1]; 2085 r->gid.op = gid->op; 2086 r->gid.gid[0] = gid->gid[0]; 2087 r->gid.gid[1] = gid->gid[1]; 2088 r->type = icmp_type->type; 2089 r->code = icmp_type->code; 2090 2091 if (r->proto && r->proto != IPPROTO_TCP) { 2092 r->flags = 0; 2093 r->flagset = 0; 2094 } else { 2095 r->flags = flags; 2096 r->flagset = flagset; 2097 } 2098 if (icmp_type->proto && r->proto != icmp_type->proto) { 2099 yyerror("icmp-type mismatch"); 2100 nomatch++; 2101 } 2102 2103 if (rule_consistent(r) < 0 || nomatch) 2104 yyerror("skipping filter rule due to errors"); 2105 else { 2106 r->nr = pf->rule_nr++; 2107 pfctl_add_rule(pf, r); 2108 added++; 2109 } 2110 2111 ))))))))); 2112 2113 FREE_LIST(struct node_if, interfaces); 2114 FREE_LIST(struct node_proto, protos); 2115 FREE_LIST(struct node_host, src_hosts); 2116 FREE_LIST(struct node_port, src_ports); 2117 FREE_LIST(struct node_host, dst_hosts); 2118 FREE_LIST(struct node_port, dst_ports); 2119 FREE_LIST(struct node_uid, uids); 2120 FREE_LIST(struct node_gid, gids); 2121 FREE_LIST(struct node_icmp, icmp_types); 2122 2123 if (!added) 2124 yyerror("rule expands to no valid combination"); 2125} 2126 2127void 2128expand_nat(struct pf_nat *n, 2129 struct node_if *interfaces, struct node_proto *protos, 2130 struct node_host *src_hosts, struct node_port *src_ports, 2131 struct node_host *dst_hosts, struct node_port *dst_ports) 2132{ 2133 char ifname[IF_NAMESIZE]; 2134 int af = n->af, added = 0; 2135 2136 LOOP_THROUGH(struct node_if, interface, interfaces, 2137 LOOP_THROUGH(struct node_proto, proto, protos, 2138 LOOP_THROUGH(struct node_host, src_host, src_hosts, 2139 LOOP_THROUGH(struct node_port, src_port, src_ports, 2140 LOOP_THROUGH(struct node_host, dst_host, dst_hosts, 2141 LOOP_THROUGH(struct node_port, dst_port, dst_ports, 2142 2143 n->af = af; 2144 /* for link-local IPv6 address, interface must match up */ 2145 if ((n->af && src_host->af && n->af != src_host->af) || 2146 (n->af && dst_host->af && n->af != dst_host->af) || 2147 (src_host->af && dst_host->af && 2148 src_host->af != dst_host->af) || 2149 (src_host->ifindex && dst_host->ifindex && 2150 src_host->ifindex != dst_host->ifindex) || 2151 (src_host->ifindex && if_nametoindex(interface->ifname) && 2152 src_host->ifindex != if_nametoindex(interface->ifname)) || 2153 (dst_host->ifindex && if_nametoindex(interface->ifname) && 2154 dst_host->ifindex != if_nametoindex(interface->ifname))) 2155 continue; 2156 if (!n->af && src_host->af) 2157 n->af = src_host->af; 2158 else if (!n->af && dst_host->af) 2159 n->af = dst_host->af; 2160 2161 if (if_indextoname(src_host->ifindex, ifname)) 2162 memcpy(n->ifname, ifname, sizeof(n->ifname)); 2163 else if (if_indextoname(dst_host->ifindex, ifname)) 2164 memcpy(n->ifname, ifname, sizeof(n->ifname)); 2165 else 2166 memcpy(n->ifname, interface->ifname, sizeof(n->ifname)); 2167 2168 if (!n->af && n->raddr.addr_dyn != NULL) { 2169 yyerror("address family (inet/inet6) undefined"); 2170 continue; 2171 } 2172 2173 n->ifnot = interface->not; 2174 n->proto = proto->proto; 2175 n->src.addr = src_host->addr; 2176 n->src.mask = src_host->mask; 2177 n->src.noroute = src_host->noroute; 2178 n->src.not = src_host->not; 2179 n->src.port[0] = src_port->port[0]; 2180 n->src.port[1] = src_port->port[1]; 2181 n->src.port_op = src_port->op; 2182 n->dst.addr = dst_host->addr; 2183 n->dst.mask = dst_host->mask; 2184 n->dst.noroute = dst_host->noroute; 2185 n->dst.not = dst_host->not; 2186 n->dst.port[0] = dst_port->port[0]; 2187 n->dst.port[1] = dst_port->port[1]; 2188 n->dst.port_op = dst_port->op; 2189 2190 if (nat_consistent(n) < 0) 2191 yyerror("skipping nat rule due to errors"); 2192 else { 2193 pfctl_add_nat(pf, n); 2194 added++; 2195 } 2196 2197 )))))); 2198 2199 FREE_LIST(struct node_if, interfaces); 2200 FREE_LIST(struct node_proto, protos); 2201 FREE_LIST(struct node_host, src_hosts); 2202 FREE_LIST(struct node_port, src_ports); 2203 FREE_LIST(struct node_host, dst_hosts); 2204 FREE_LIST(struct node_port, dst_ports); 2205 2206 if (!added) 2207 yyerror("nat rule expands to no valid combinations"); 2208} 2209 2210void 2211expand_rdr(struct pf_rdr *r, struct node_if *interfaces, 2212 struct node_proto *protos, struct node_host *src_hosts, 2213 struct node_host *dst_hosts) 2214{ 2215 int af = r->af, added = 0; 2216 char ifname[IF_NAMESIZE]; 2217 2218 LOOP_THROUGH(struct node_if, interface, interfaces, 2219 LOOP_THROUGH(struct node_proto, proto, protos, 2220 LOOP_THROUGH(struct node_host, src_host, src_hosts, 2221 LOOP_THROUGH(struct node_host, dst_host, dst_hosts, 2222 2223 r->af = af; 2224 if ((r->af && src_host->af && r->af != src_host->af) || 2225 (r->af && dst_host->af && r->af != dst_host->af) || 2226 (src_host->af && dst_host->af && 2227 src_host->af != dst_host->af) || 2228 (src_host->ifindex && dst_host->ifindex && 2229 src_host->ifindex != dst_host->ifindex) || 2230 (src_host->ifindex && if_nametoindex(interface->ifname) && 2231 src_host->ifindex != if_nametoindex(interface->ifname)) || 2232 (dst_host->ifindex && if_nametoindex(interface->ifname) && 2233 dst_host->ifindex != if_nametoindex(interface->ifname))) 2234 continue; 2235 2236 if (!r->af && src_host->af) 2237 r->af = src_host->af; 2238 else if (!r->af && dst_host->af) 2239 r->af = dst_host->af; 2240 if (!r->af && (r->saddr.addr_dyn != NULL || 2241 r->daddr.addr_dyn != NULL || r->raddr.addr_dyn)) { 2242 yyerror("address family (inet/inet6) undefined"); 2243 continue; 2244 } 2245 2246 if (if_indextoname(src_host->ifindex, ifname)) 2247 memcpy(r->ifname, ifname, sizeof(r->ifname)); 2248 else if (if_indextoname(dst_host->ifindex, ifname)) 2249 memcpy(r->ifname, ifname, sizeof(r->ifname)); 2250 else 2251 memcpy(r->ifname, interface->ifname, sizeof(r->ifname)); 2252 2253 r->proto = proto->proto; 2254 r->ifnot = interface->not; 2255 r->saddr = src_host->addr; 2256 r->smask = src_host->mask; 2257 r->daddr = dst_host->addr; 2258 r->dmask = dst_host->mask; 2259 2260 if (rdr_consistent(r) < 0) 2261 yyerror("skipping rdr rule due to errors"); 2262 else { 2263 pfctl_add_rdr(pf, r); 2264 added++; 2265 } 2266 2267 )))); 2268 2269 FREE_LIST(struct node_if, interfaces); 2270 FREE_LIST(struct node_proto, protos); 2271 FREE_LIST(struct node_host, src_hosts); 2272 FREE_LIST(struct node_host, dst_hosts); 2273 2274 if (!added) 2275 yyerror("rdr rule expands to no valid combination"); 2276} 2277 2278#undef FREE_LIST 2279#undef LOOP_THROUGH 2280 2281int 2282check_rulestate(int desired_state) 2283{ 2284 if (rulestate > desired_state) { 2285 yyerror("Rules must be in order: options, normalization, " 2286 "translation, filter"); 2287 return (1); 2288 } 2289 rulestate = desired_state; 2290 return (0); 2291} 2292 2293int 2294kw_cmp(const void *k, const void *e) 2295{ 2296 return (strcmp(k, ((struct keywords *)e)->k_name)); 2297} 2298 2299int 2300lookup(char *s) 2301{ 2302 /* this has to be sorted always */ 2303 static const struct keywords keywords[] = { 2304 { "all", ALL}, 2305 { "allow-opts", ALLOWOPTS}, 2306 { "antispoof", ANTISPOOF}, 2307 { "any", ANY}, 2308 { "binat", BINAT}, 2309 { "block", BLOCK}, 2310 { "code", CODE}, 2311 { "crop", FRAGCROP}, 2312 { "drop-ovl", FRAGDROP}, 2313 { "dup-to", DUPTO}, 2314 { "fastroute", FASTROUTE}, 2315 { "flags", FLAGS}, 2316 { "for", FOR}, 2317 { "fragment", FRAGMENT}, 2318 { "from", FROM}, 2319 { "group", GROUP}, 2320 { "icmp-type", ICMPTYPE}, 2321 { "in", IN}, 2322 { "inet", INET}, 2323 { "inet6", INET6}, 2324 { "ipv6-icmp-type", ICMP6TYPE}, 2325 { "keep", KEEP}, 2326 { "label", LABEL}, 2327 { "limit", LIMIT}, 2328 { "log", LOG}, 2329 { "log-all", LOGALL}, 2330 { "loginterface", LOGINTERFACE}, 2331 { "max", MAXIMUM}, 2332 { "max-mss", MAXMSS}, 2333 { "min-ttl", MINTTL}, 2334 { "modulate", MODULATE}, 2335 { "nat", NAT}, 2336 { "no", NO}, 2337 { "no-df", NODF}, 2338 { "no-route", NOROUTE}, 2339 { "on", ON}, 2340 { "optimization", OPTIMIZATION}, 2341 { "out", OUT}, 2342 { "pass", PASS}, 2343 { "port", PORT}, 2344 { "proto", PROTO}, 2345 { "quick", QUICK}, 2346 { "rdr", RDR}, 2347 { "reassemble", FRAGNORM}, 2348 { "reply-to", REPLYTO}, 2349 { "return", RETURN}, 2350 { "return-icmp",RETURNICMP}, 2351 { "return-icmp6",RETURNICMP6}, 2352 { "return-rst", RETURNRST}, 2353 { "route-to", ROUTETO}, 2354 { "scrub", SCRUB}, 2355 { "set", SET}, 2356 { "state", STATE}, 2357 { "timeout", TIMEOUT}, 2358 { "to", TO}, 2359 { "tos", TOS}, 2360 { "ttl", TTL}, 2361 { "user", USER}, 2362 }; 2363 const struct keywords *p; 2364 2365 p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), 2366 sizeof(keywords[0]), kw_cmp); 2367 2368 if (p) { 2369 if (debug > 1) 2370 fprintf(stderr, "%s: %d\n", s, p->k_val); 2371 return (p->k_val); 2372 } else { 2373 if (debug > 1) 2374 fprintf(stderr, "string: %s\n", s); 2375 return (STRING); 2376 } 2377} 2378 2379#define MAXPUSHBACK 128 2380 2381char *parsebuf; 2382int parseindex; 2383char pushback_buffer[MAXPUSHBACK]; 2384int pushback_index = 0; 2385 2386int 2387lgetc(FILE *fin) 2388{ 2389 int c, next; 2390 2391 if (parsebuf) { 2392 /* Reading characters from the parse buffer, instead of input */ 2393 if (parseindex >= 0) { 2394 c = parsebuf[parseindex++]; 2395 if (c != '\0') 2396 return (c); 2397 parsebuf = NULL; 2398 } else 2399 parseindex++; 2400 } 2401 2402 if (pushback_index) 2403 return (pushback_buffer[--pushback_index]); 2404 2405 while ((c = getc(fin)) == '\\') { 2406 next = getc(fin); 2407 if (next != '\n') { 2408 ungetc(next, fin); 2409 break; 2410 } 2411 yylval.lineno = lineno; 2412 lineno++; 2413 } 2414 return (c); 2415} 2416 2417int 2418lungetc(int c, FILE *fin) 2419{ 2420 if (c == EOF) 2421 return (EOF); 2422 if (parsebuf) { 2423 parseindex--; 2424 if (parseindex >= 0) 2425 return (c); 2426 } 2427 if (pushback_index < MAXPUSHBACK-1) 2428 return (pushback_buffer[pushback_index++] = c); 2429 else 2430 return (EOF); 2431} 2432 2433int 2434findeol(void) 2435{ 2436 int c; 2437 2438 parsebuf = NULL; 2439 pushback_index = 0; 2440 2441 /* skip to either EOF or the first real EOL */ 2442 while (1) { 2443 c = lgetc(fin); 2444 if (c == '\n') { 2445 lineno++; 2446 break; 2447 } 2448 if (c == EOF) 2449 break; 2450 } 2451 return (ERROR); 2452} 2453 2454int 2455yylex(void) 2456{ 2457 char buf[8096], *p, *val; 2458 int endc, c, next; 2459 int token; 2460 2461top: 2462 p = buf; 2463 while ((c = lgetc(fin)) == ' ' || c == '\t') 2464 ; 2465 2466 yylval.lineno = lineno; 2467 if (c == '#') 2468 while ((c = lgetc(fin)) != '\n' && c != EOF) 2469 ; 2470 if (c == '$' && parsebuf == NULL) { 2471 while (1) { 2472 if ((c = lgetc(fin)) == EOF) 2473 return (0); 2474 if (p + 1 >= buf + sizeof(buf) - 1) { 2475 yyerror("string too long"); 2476 return (findeol()); 2477 } 2478 if (isalnum(c) || c == '_') { 2479 *p++ = (char)c; 2480 continue; 2481 } 2482 *p = '\0'; 2483 lungetc(c, fin); 2484 break; 2485 } 2486 val = symget(buf); 2487 if (val == NULL) 2488 return (ERROR); 2489 parsebuf = val; 2490 parseindex = 0; 2491 goto top; 2492 } 2493 2494 switch (c) { 2495 case '\'': 2496 case '"': 2497 endc = c; 2498 while (1) { 2499 if ((c = lgetc(fin)) == EOF) 2500 return (0); 2501 if (c == endc) { 2502 *p = '\0'; 2503 break; 2504 } 2505 if (c == '\n') { 2506 lineno++; 2507 continue; 2508 } 2509 if (p + 1 >= buf + sizeof(buf) - 1) { 2510 yyerror("string too long"); 2511 return (findeol()); 2512 } 2513 *p++ = (char)c; 2514 } 2515 yylval.v.string = strdup(buf); 2516 if (yylval.v.string == NULL) 2517 err(1, "yylex: strdup"); 2518 return (STRING); 2519 case '=': 2520 yylval.v.i = PF_OP_EQ; 2521 return (PORTUNARY); 2522 case '!': 2523 next = lgetc(fin); 2524 if (next == '=') { 2525 yylval.v.i = PF_OP_NE; 2526 return (PORTUNARY); 2527 } 2528 lungetc(next, fin); 2529 break; 2530 case '<': 2531 next = lgetc(fin); 2532 if (next == '>') { 2533 yylval.v.i = PF_OP_XRG; 2534 return (PORTBINARY); 2535 } else if (next == '=') { 2536 yylval.v.i = PF_OP_LE; 2537 } else { 2538 yylval.v.i = PF_OP_LT; 2539 lungetc(next, fin); 2540 } 2541 return (PORTUNARY); 2542 break; 2543 case '>': 2544 next = lgetc(fin); 2545 if (next == '<') { 2546 yylval.v.i = PF_OP_IRG; 2547 return (PORTBINARY); 2548 } else if (next == '=') { 2549 yylval.v.i = PF_OP_GE; 2550 } else { 2551 yylval.v.i = PF_OP_GT; 2552 lungetc(next, fin); 2553 } 2554 return (PORTUNARY); 2555 break; 2556 case '-': 2557 next = lgetc(fin); 2558 if (next == '>') 2559 return (ARROW); 2560 lungetc(next, fin); 2561 break; 2562 } 2563 2564#define allowed_in_string(x) \ 2565 (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ 2566 x != '{' && x != '}' && x != '<' && x != '>' && \ 2567 x != '!' && x != '=' && x != '/' && x != '#' && \ 2568 x != ',')) 2569 2570 if (isalnum(c) || c == ':') { 2571 do { 2572 *p++ = c; 2573 if (p-buf >= sizeof(buf)) { 2574 yyerror("string too long"); 2575 return (findeol()); 2576 } 2577 } while ((c = lgetc(fin)) != EOF && (allowed_in_string(c))); 2578 lungetc(c, fin); 2579 *p = '\0'; 2580 token = lookup(buf); 2581 yylval.v.string = strdup(buf); 2582 if (yylval.v.string == NULL) 2583 err(1, "yylex: strdup"); 2584 return (token); 2585 } 2586 if (c == '\n') { 2587 yylval.lineno = lineno; 2588 lineno++; 2589 } 2590 if (c == EOF) 2591 return (0); 2592 return (c); 2593} 2594 2595int 2596parse_rules(FILE *input, struct pfctl *xpf) 2597{ 2598 fin = input; 2599 pf = xpf; 2600 lineno = 1; 2601 errors = 0; 2602 rulestate = PFCTL_STATE_NONE; 2603 yyparse(); 2604 return (errors ? -1 : 0); 2605} 2606 2607void 2608ipmask(struct pf_addr *m, u_int8_t b) 2609{ 2610 int i, j = 0; 2611 2612 for (i = 0; i < 4; i++) 2613 m->addr32[i] = 0; 2614 2615 while (b >= 32) { 2616 m->addr32[j++] = 0xffffffff; 2617 b -= 32; 2618 } 2619 for (i = 31; i > 31-b; --i) 2620 m->addr32[j] |= (1 << i); 2621 if (b) 2622 m->addr32[j] = htonl(m->addr32[j]); 2623} 2624 2625/* 2626 * Over-designed efficiency is a French and German concept, so how about 2627 * we wait until they discover this ugliness and make it all fancy. 2628 */ 2629int 2630symset(const char *nam, const char *val) 2631{ 2632 struct sym *sym; 2633 2634 sym = calloc(1, sizeof(*sym)); 2635 if (sym == NULL) 2636 return (-1); 2637 sym->nam = strdup(nam); 2638 if (sym->nam == NULL) { 2639 free(sym); 2640 return (-1); 2641 } 2642 sym->val = strdup(val); 2643 if (sym->val == NULL) { 2644 free(sym->nam); 2645 free(sym); 2646 return (-1); 2647 } 2648 sym->next = symhead; 2649 symhead = sym; 2650 return (0); 2651} 2652 2653char * 2654symget(const char *nam) 2655{ 2656 struct sym *sym; 2657 2658 for (sym = symhead; sym; sym = sym->next) 2659 if (strcmp(nam, sym->nam) == 0) 2660 return (sym->val); 2661 return (NULL); 2662} 2663 2664/* interface lookup routines */ 2665 2666struct node_host *iftab; 2667 2668void 2669ifa_load(void) 2670{ 2671 struct ifaddrs *ifap, *ifa; 2672 struct node_host *n = NULL, *h = NULL; 2673 2674 if (getifaddrs(&ifap) < 0) 2675 err(1, "getifaddrs"); 2676 2677 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 2678 if (!(ifa->ifa_addr->sa_family == AF_INET || 2679 ifa->ifa_addr->sa_family == AF_INET6 || 2680 ifa->ifa_addr->sa_family == AF_LINK)) 2681 continue; 2682 n = calloc(1, sizeof(struct node_host)); 2683 if (n == NULL) 2684 err(1, "address: calloc"); 2685 n->af = ifa->ifa_addr->sa_family; 2686 n->addr.addr_dyn = NULL; 2687 n->ifa_flags = ifa->ifa_flags; 2688#ifdef __KAME__ 2689 if (n->af == AF_INET6 && 2690 IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr) && 2691 ((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_scope_id == 0) { 2692 struct sockaddr_in6 *sin6; 2693 2694 sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; 2695 sin6->sin6_scope_id = sin6->sin6_addr.s6_addr[2] << 8 | 2696 sin6->sin6_addr.s6_addr[3]; 2697 sin6->sin6_addr.s6_addr[2] = 0; 2698 sin6->sin6_addr.s6_addr[3] = 0; 2699 } 2700#endif 2701 n->ifindex = 0; 2702 if (n->af == AF_INET) { 2703 memcpy(&n->addr.addr, &((struct sockaddr_in *) 2704 ifa->ifa_addr)->sin_addr.s_addr, 2705 sizeof(struct in_addr)); 2706 memcpy(&n->mask, &((struct sockaddr_in *) 2707 ifa->ifa_netmask)->sin_addr.s_addr, 2708 sizeof(struct in_addr)); 2709 if (ifa->ifa_broadaddr != NULL) 2710 memcpy(&n->bcast, &((struct sockaddr_in *) 2711 ifa->ifa_broadaddr)->sin_addr.s_addr, 2712 sizeof(struct in_addr)); 2713 } else if (n->af == AF_INET6) { 2714 memcpy(&n->addr.addr, &((struct sockaddr_in6 *) 2715 ifa->ifa_addr)->sin6_addr.s6_addr, 2716 sizeof(struct in6_addr)); 2717 memcpy(&n->mask, &((struct sockaddr_in6 *) 2718 ifa->ifa_netmask)->sin6_addr.s6_addr, 2719 sizeof(struct in6_addr)); 2720 if (ifa->ifa_broadaddr != NULL) 2721 memcpy(&n->bcast, &((struct sockaddr_in6 *) 2722 ifa->ifa_broadaddr)->sin6_addr.s6_addr, 2723 sizeof(struct in6_addr)); 2724 n->ifindex = ((struct sockaddr_in6 *) 2725 ifa->ifa_addr)->sin6_scope_id; 2726 } 2727 if ((n->ifname = strdup(ifa->ifa_name)) == NULL) { 2728 yyerror("malloc failed"); 2729 exit(1); 2730 } 2731 n->next = NULL; 2732 n->tail = n; 2733 if (h == NULL) 2734 h = n; 2735 else { 2736 h->tail->next = n; 2737 h->tail = n; 2738 } 2739 } 2740 iftab = h; 2741 freeifaddrs(ifap); 2742} 2743 2744struct node_host * 2745ifa_exists(char *ifa_name) 2746{ 2747 struct node_host *n; 2748 2749 if (iftab == NULL) 2750 ifa_load(); 2751 2752 for (n = iftab; n; n = n->next) { 2753 if (n->af == AF_LINK && !strncmp(n->ifname, ifa_name, IFNAMSIZ)) 2754 return (n); 2755 } 2756 return (NULL); 2757} 2758 2759struct node_host * 2760ifa_lookup(char *ifa_name, enum pfctl_iflookup_mode mode) 2761{ 2762 struct node_host *p = NULL, *h = NULL, *n = NULL; 2763 int return_all = 0; 2764 2765 if (!strncmp(ifa_name, "self", IFNAMSIZ)) 2766 return_all = 1; 2767 2768 if (iftab == NULL) 2769 ifa_load(); 2770 2771 for (p = iftab; p; p = p->next) { 2772 if (!((p->af == AF_INET || p->af == AF_INET6) 2773 && (!strncmp(p->ifname, ifa_name, IFNAMSIZ) || return_all))) 2774 continue; 2775 if (mode == PFCTL_IFLOOKUP_BCAST && p->af != AF_INET) 2776 continue; 2777 if (mode == PFCTL_IFLOOKUP_NET && p->ifindex > 0) 2778 continue; 2779 n = calloc(1, sizeof(struct node_host)); 2780 if (n == NULL) 2781 err(1, "address: calloc"); 2782 n->af = p->af; 2783 n->addr.addr_dyn = NULL; 2784 if (mode == PFCTL_IFLOOKUP_BCAST) { 2785 memcpy(&n->addr.addr, &p->bcast, 2786 sizeof(struct pf_addr)); 2787 } else 2788 memcpy(&n->addr.addr, &p->addr.addr, 2789 sizeof(struct pf_addr)); 2790 if (mode == PFCTL_IFLOOKUP_NET) 2791 memcpy(&n->mask, &p->mask, sizeof(struct pf_addr)); 2792 else { 2793 if (n->af == AF_INET) 2794 ipmask(&n->mask, 32); 2795 else 2796 ipmask(&n->mask, 128); 2797 } 2798 n->ifindex = p->ifindex; 2799 2800 n->next = NULL; 2801 n->tail = n; 2802 if (h == NULL) 2803 h = n; 2804 else { 2805 h->tail->next = n; 2806 h->tail = n; 2807 } 2808 } 2809 if (h == NULL && mode == PFCTL_IFLOOKUP_HOST) { 2810 yyerror("no IP address found for %s", ifa_name); 2811 } 2812 return (h); 2813} 2814 2815struct node_host * 2816ifa_pick_ip(struct node_host *nh, u_int8_t af) 2817{ 2818 struct node_host *h, *n = NULL; 2819 2820 if (af == 0 && nh && nh->next) { 2821 yyerror("address family not given and translation address " 2822 "expands to multiple IPs"); 2823 return (NULL); 2824 } 2825 for (h = nh; h; h = h->next) { 2826 if (h->af == af || h->af == 0 || af == 0) { 2827 if (n != NULL) { 2828 yyerror("translation address expands to " 2829 "multiple IPs of this address family"); 2830 return (NULL); 2831 } 2832 n = h; 2833 } 2834 } 2835 if (n == NULL) 2836 yyerror("no translation address with matching address family " 2837 "found."); 2838 else { 2839 n->next = NULL; 2840 n->tail = n; 2841 } 2842 2843 return (n); 2844} 2845 2846struct node_host * 2847host(char *s) 2848{ 2849 struct node_host *h = NULL, *n; 2850 struct in_addr ina; 2851 struct addrinfo hints, *res0, *res; 2852 int error; 2853 2854 if (ifa_exists(s) || !strncmp(s, "self", IFNAMSIZ)) { 2855 /* interface with this name exists */ 2856 if ((h = ifa_lookup(s, PFCTL_IFLOOKUP_HOST)) == NULL) 2857 return (NULL); 2858 else { 2859 h->next = NULL; 2860 h->tail = h; 2861 return (h); 2862 } 2863 } 2864 2865 if (inet_aton(s, &ina) == 1) { 2866 h = calloc(1, sizeof(struct node_host)); 2867 if (h == NULL) 2868 err(1, "address: calloc"); 2869 h->af = AF_INET; 2870 h->addr.addr_dyn = NULL; 2871 h->addr.addr.addr32[0] = ina.s_addr; 2872 ipmask(&h->mask, 32); 2873 h->next = NULL; 2874 h->tail = h; 2875 return (h); 2876 } 2877 2878 memset(&hints, 0, sizeof(hints)); 2879 hints.ai_family = AF_INET6; 2880 hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 2881 hints.ai_flags = AI_NUMERICHOST; 2882 if (getaddrinfo(s, "0", &hints, &res) == 0) { 2883 n = calloc(1, sizeof(struct node_host)); 2884 if (n == NULL) 2885 err(1, "address: calloc"); 2886 n->af = AF_INET6; 2887 n->addr.addr_dyn = NULL; 2888 memcpy(&n->addr.addr, 2889 &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr, 2890 sizeof(n->addr.addr)); 2891 n->ifindex = ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id; 2892 ipmask(&n->mask, 128); 2893 freeaddrinfo(res); 2894 n->next = NULL; 2895 n->tail = n; 2896 return (n); 2897 } 2898 2899 memset(&hints, 0, sizeof(hints)); 2900 hints.ai_family = PF_UNSPEC; 2901 hints.ai_socktype = SOCK_STREAM; /* DUMMY */ 2902 error = getaddrinfo(s, NULL, &hints, &res0); 2903 if (error) { 2904 yyerror("cannot resolve %s: %s", 2905 s, gai_strerror(error)); 2906 return (NULL); 2907 } 2908 for (res = res0; res; res = res->ai_next) { 2909 if (res->ai_family != AF_INET && 2910 res->ai_family != AF_INET6) 2911 continue; 2912 n = calloc(1, sizeof(struct node_host)); 2913 if (n == NULL) 2914 err(1, "address: calloc"); 2915 n->af = res->ai_family; 2916 n->addr.addr_dyn = NULL; 2917 if (res->ai_family == AF_INET) { 2918 memcpy(&n->addr.addr, 2919 &((struct sockaddr_in *)res->ai_addr)->sin_addr.s_addr, 2920 sizeof(struct in_addr)); 2921 ipmask(&n->mask, 32); 2922 } else { 2923 memcpy(&n->addr.addr, 2924 &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr.s6_addr, 2925 sizeof(struct in6_addr)); 2926 n->ifindex = 2927 ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id; 2928 ipmask(&n->mask, 128); 2929 } 2930 n->next = NULL; 2931 n->tail = n; 2932 if (h == NULL) 2933 h = n; 2934 else { 2935 h->tail->next = n; 2936 h->tail = n; 2937 } 2938 } 2939 freeaddrinfo(res0); 2940 if (h == NULL) { 2941 yyerror("no IP address found for %s", s); 2942 return (NULL); 2943 } 2944 return (h); 2945} 2946 2947int 2948atoul(char *s, u_long *ulvalp) 2949{ 2950 u_long ulval; 2951 char *ep; 2952 2953 errno = 0; 2954 ulval = strtoul(s, &ep, 0); 2955 if (s[0] == '\0' || *ep != '\0') 2956 return (-1); 2957 if (errno == ERANGE && ulval == ULONG_MAX) 2958 return (-1); 2959 *ulvalp = ulval; 2960 return (0); 2961} 2962 2963int 2964getservice(char *n) 2965{ 2966 struct servent *s; 2967 u_long ulval; 2968 2969 if (atoul(n, &ulval) == 0) { 2970 if (ulval < 0 || ulval > 65535) { 2971 yyerror("illegal port value %d", ulval); 2972 return (-1); 2973 } 2974 return (htons(ulval)); 2975 } else { 2976 s = getservbyname(n, "tcp"); 2977 if (s == NULL) 2978 s = getservbyname(n, "udp"); 2979 if (s == NULL) { 2980 yyerror("unknown port %s", n); 2981 return (-1); 2982 } 2983 return (s->s_port); 2984 } 2985} 2986