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