parse.y revision 1.42
1/* $OpenBSD: parse.y,v 1.42 2001/10/24 09:18:35 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 50#include "pfctl_parser.h" 51 52static struct pfctl *pf = NULL; 53static FILE *fin = NULL; 54static int debug = 0; 55static int lineno = 1; 56static int errors = 0; 57static int natmode = 0; 58 59struct node_if { 60 char ifname[IFNAMSIZ]; 61 u_int8_t not; 62 struct node_if *next; 63}; 64 65struct node_proto { 66 u_int8_t proto; 67 struct node_proto *next; 68}; 69 70struct node_host { 71 struct pf_addr addr; 72 struct pf_addr mask; 73 u_int8_t af; 74 u_int8_t not; 75 struct node_host *next; 76}; 77 78struct node_port { 79 u_int16_t port[2]; 80 u_int8_t op; 81 struct node_port *next; 82}; 83 84struct node_icmp { 85 u_int8_t code; 86 u_int8_t type; 87 u_int8_t proto; 88 struct node_icmp *next; 89}; 90 91struct peer { 92 struct node_host *host; 93 struct node_port *port; 94}; 95 96int rule_consistent(struct pf_rule *); 97int yyparse(void); 98struct pf_rule_addr *new_addr(void); 99void ipmask(struct pf_addr *, u_int8_t, int); 100void expand_rule_hosts(struct pf_rule *, 101 struct node_if *, struct node_proto *, 102 struct node_host *, struct node_port *, 103 struct node_host *, struct node_port *, 104 struct node_icmp *); 105void expand_rule_protos(struct pf_rule *, 106 struct node_if *, struct node_proto *, 107 struct node_host *, struct node_port *, 108 struct node_host *, struct node_port *, 109 struct node_icmp *); 110void expand_rule(struct pf_rule *, 111 struct node_if *, struct node_proto *, 112 struct node_host *, struct node_port *, 113 struct node_host *, struct node_port *, 114 struct node_icmp *); 115 116struct sym { 117 struct sym *next; 118 char *nam; 119 char *val; 120}; 121struct sym *symhead = NULL; 122 123int symset(char *name, char *val); 124char * symget(char *name); 125 126struct ifaddrs *ifa0_lookup(char *ifa_name); 127struct ifaddrs *ifa4_lookup(char *ifa_name); 128struct ifaddrs *ifa6_lookup(char *ifa_name); 129 130typedef struct { 131 union { 132 u_int32_t number; 133 int i; 134 char *string; 135 struct { 136 u_int8_t b1; 137 u_int8_t b2; 138 u_int16_t w; 139 } b; 140 struct { 141 int a; 142 int b; 143 int t; 144 } range; 145 struct node_if *interface; 146 struct node_proto *proto; 147 struct node_icmp *icmp; 148 struct node_host *host; 149 struct node_port *port; 150 struct peer peer; 151 struct { 152 struct peer src, dst; 153 } fromto; 154 } v; 155 int lineno; 156} YYSTYPE; 157 158%} 159 160%token PASS BLOCK SCRUB RETURN IN OUT LOG LOGALL QUICK ON FROM TO FLAGS 161%token RETURNRST RETURNICMP RETURNICMP6 PROTO INET INET6 ALL ANY ICMPTYPE 162%token ICMP6TYPE CODE KEEP MODULATE STATE PORT RDR NAT BINAT ARROW NODF 163%token MINTTL IPV6ADDR ERROR ALLOWOPTS 164%token <v.string> STRING 165%token <v.number> NUMBER 166%token <v.i> PORTUNARY PORTBINARY 167%type <v.interface> interface if_list if_item_not if_item 168%type <v.number> port icmptype icmp6type minttl 169%type <v.i> dir log quick af keep nodf allowopts 170%type <v.b> action flag flags blockspec 171%type <v.range> dport rport 172%type <v.proto> proto proto_list proto_item 173%type <v.icmp> icmpspec icmp_list icmp6_list icmp_item icmp6_item 174%type <v.fromto> fromto 175%type <v.peer> ipportspec 176%type <v.host> ipspec xhost host address host_list IPV6ADDR 177%type <v.port> portspec port_list port_item 178%% 179 180ruleset : /* empty */ 181 | ruleset '\n' 182 | ruleset pfrule '\n' 183 | ruleset natrule '\n' 184 | ruleset binatrule '\n' 185 | ruleset rdrrule '\n' 186 | ruleset varset '\n' 187 | ruleset error '\n' { errors++; } 188 ; 189 190varset : STRING PORTUNARY STRING 191 { 192 if (pf->opts & PF_OPT_VERBOSE) 193 printf("%s = %s\n", $1, $3); 194 if (symset($1, $3) == -1) { 195 yyerror("cannot store variable %s", $1); 196 YYERROR; 197 } 198 } 199 ; 200 201pfrule : action dir log quick interface af proto fromto flags icmpspec keep nodf minttl allowopts 202 { 203 struct pf_rule r; 204 205 if (natmode) { 206 yyerror("filter rule not permitted in nat mode"); 207 YYERROR; 208 } 209 memset(&r, 0, sizeof(r)); 210 211 r.action = $1.b1; 212 if ($1.b2) 213 r.rule_flag |= PFRULE_RETURNRST; 214 else 215 r.return_icmp = $1.w; 216 r.direction = $2; 217 r.log = $3; 218 r.quick = $4; 219 220 r.af = $6; 221 r.flags = $9.b1; 222 r.flagset = $9.b2; 223 224 r.keep_state = $11; 225 226 if ($12) 227 r.rule_flag |= PFRULE_NODF; 228 if ($13) 229 r.min_ttl = $13; 230 r.allow_opts = $14; 231 232 expand_rule(&r, $5, $7, $8.src.host, $8.src.port, 233 $8.dst.host, $8.dst.port, $10); 234 } 235 ; 236 237action : PASS { $$.b1 = PF_PASS; $$.b2 = $$.w = 0; } 238 | BLOCK blockspec { $$ = $2; $$.b1 = PF_DROP; } 239 | SCRUB { $$.b1 = PF_SCRUB; $$.b2 = $$.w = 0; } 240 ; 241 242blockspec : /* empty */ { $$.b2 = 0; $$.w = 0; } 243 | RETURNRST { $$.b2 = 1; $$.w = 0;} 244 | RETURNICMP { 245 $$.b2 = 0; 246 $$.w = (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT; 247 } 248 | RETURNICMP6 { 249 $$.b2 = 0; 250 $$.w = (ICMP6_DST_UNREACH << 8) | 251 ICMP6_DST_UNREACH_NOPORT; 252 } 253 | RETURNICMP '(' NUMBER ')' { 254 $$.w = (ICMP_UNREACH << 8) | $3; 255 $$.b2 = 0; 256 } 257 | RETURNICMP '(' STRING ')' { 258 struct icmpcodeent *p; 259 260 if ((p = geticmpcodebyname(ICMP_UNREACH, $3, 261 AF_INET)) == NULL) { 262 yyerror("unknown icmp code %s", $3); 263 YYERROR; 264 } 265 $$.w = (p->type << 8) | p->code; 266 $$.b2 = 0; 267 } 268 | RETURNICMP6 '(' NUMBER ')' { 269 $$.w = (ICMP6_DST_UNREACH << 8) | $3; 270 $$.b2 = 0; 271 } 272 | RETURNICMP6 '(' STRING ')' { 273 struct icmpcodeent *p; 274 275 if ((p = geticmpcodebyname(ICMP6_DST_UNREACH, $3, 276 AF_INET6)) == NULL) { 277 yyerror("unknown icmp code %s", $3); 278 YYERROR; 279 } 280 $$.w = (p->type << 8) | p->code; 281 $$.b2 = 0; 282 } 283 ; 284 285dir : IN { $$ = PF_IN; } 286 | OUT { $$ = PF_OUT; } 287 ; 288 289log : /* empty */ { $$ = 0; } 290 | LOG { $$ = 1; } 291 | LOGALL { $$ = 2; } 292 ; 293 294quick : /* empty */ { $$ = 0; } 295 | QUICK { $$ = 1; } 296 ; 297 298interface : /* empty */ { $$ = NULL; } 299 | ON if_item_not { $$ = $2; } 300 | ON '{' if_list '}' { $$ = $3; } 301 ; 302 303if_list : if_item_not { $$ = $1; } 304 | if_list ',' if_item_not { $3->next = $1; $$ = $3; } 305 ; 306 307if_item_not : '!' if_item { $$ = $2; $$->not = 1; } 308 | if_item { $$ = $1; } 309 310if_item : STRING { 311 if (ifa0_lookup($1) == NULL) { 312 yyerror("unknown interface %s", $1); 313 YYERROR; 314 } 315 $$ = malloc(sizeof(struct node_if)); 316 if ($$ == NULL) 317 err(1, "if_item: malloc"); 318 strlcpy($$->ifname, $1, IFNAMSIZ); 319 $$->not = 0; 320 $$->next = NULL; 321 } 322 ; 323 324af : /* empty */ { $$ = 0; } 325 | INET { $$ = AF_INET; } 326 | INET6 { $$ = AF_INET6; } 327 328proto : /* empty */ { $$ = NULL; } 329 | PROTO proto_item { $$ = $2; } 330 | PROTO '{' proto_list '}' { $$ = $3; } 331 ; 332 333proto_list : proto_item { $$ = $1; } 334 | proto_list ',' proto_item { $3->next = $1; $$ = $3; } 335 ; 336 337proto_item : NUMBER { 338 struct protoent *p; 339 340 if ((p = getprotobynumber($1)) == NULL) { 341 yyerror("unknown protocol %d", $1); 342 YYERROR; 343 } 344 $$ = malloc(sizeof(struct node_proto)); 345 if ($$ == NULL) 346 err(1, "proto_item: malloc"); 347 $$->proto = p->p_proto; 348 $$->next = NULL; 349 } 350 | STRING { 351 struct protoent *p; 352 353 if ((p = getprotobyname($1)) == NULL) { 354 yyerror("unknown protocol %s", $1); 355 YYERROR; 356 } 357 $$ = malloc(sizeof(struct node_proto)); 358 if ($$ == NULL) 359 err(1, "proto_item: malloc"); 360 $$->proto = p->p_proto; 361 $$->next = NULL; 362 } 363 ; 364 365fromto : ALL { 366 $$.src.host = NULL; 367 $$.src.port = NULL; 368 $$.dst.host = NULL; 369 $$.dst.port = NULL; 370 } 371 | FROM ipportspec TO ipportspec { 372 $$.src = $2; 373 $$.dst = $4; 374 } 375 ; 376 377ipportspec : ipspec { $$.host = $1; $$.port = NULL; } 378 | ipspec PORT portspec { 379 $$.host = $1; 380 $$.port = $3; 381 } 382 ; 383 384ipspec : ANY { $$ = NULL; } 385 | xhost { $$ = $1; } 386 | '{' host_list '}' { $$ = $2; } 387 ; 388 389host_list : xhost { $$ = $1; } 390 | host_list ',' xhost { $3->next = $1; $$ = $3; } 391 ; 392 393xhost : '!' host { $$ = $2; $$->not = 1; } 394 | host { $$ = $1; } 395 ; 396 397host : address { 398 $$ = $1; 399 if ($$->af == AF_INET) 400 ipmask(&$$->mask, 32, AF_INET); 401 else 402 ipmask(&$$->mask, 128, AF_INET6); 403 } 404 | address '/' NUMBER { 405 if ($$->af == AF_INET) { 406 if ($3 < 0 || $3 > 32) { 407 yyerror("illegal netmask value %d", $3); 408 YYERROR; 409 } 410 } else { 411 if ($3 < 0 || $3 > 128) { 412 yyerror("illegal netmask value %d", $3); 413 YYERROR; 414 } 415 } 416 $$ = $1; 417 ipmask(&$$->mask, $3, $$->af); 418 } 419 ; 420 421address : STRING { 422 struct hostent *hp; 423 struct ifaddrs *ifa; 424 425 if (ifa0_lookup($1)) { 426 /* an interface with this name exists */ 427 if ((ifa = ifa4_lookup($1))) { 428 struct sockaddr_in *sin = 429 (struct sockaddr_in *) 430 ifa->ifa_addr; 431 432 $$ = calloc(1, 433 sizeof(struct node_host)); 434 if ($$ == NULL) 435 err(1, "address: calloc"); 436 $$->af = AF_INET; 437 memcpy(&$$->addr, &sin->sin_addr, 438 sizeof(u_int32_t)); 439 } else if ((ifa = ifa6_lookup($1))) { 440 struct sockaddr_in6 *sin6 = 441 (struct sockaddr_in6 *) 442 ifa->ifa_addr; 443 444 $$ = calloc(1, 445 sizeof(struct node_host)); 446 if ($$ == NULL) 447 err(1, "address: calloc"); 448 $$->af = AF_INET6; 449 memcpy(&$$->addr, &sin6->sin6_addr, 450 sizeof(struct pf_addr)); 451 } else { 452 yyerror("interface %s has no IP " 453 "addresses", $1); 454 YYERROR; 455 } 456 } 457 else if ((hp = gethostbyname2($1, AF_INET)) == NULL) { 458 if ((hp = gethostbyname2($1, AF_INET6)) 459 == NULL) { 460 yyerror("cannot resolve %s", $1); 461 YYERROR; 462 } else { 463 $$ = calloc(1, sizeof(struct node_host)); 464 if ($$ == NULL) 465 err(1, "address: calloc"); 466 $$->af = AF_INET6; 467 memcpy(&$$->addr, hp->h_addr, 468 sizeof(struct pf_addr)); 469 } 470 } else { 471 $$ = calloc(1, sizeof(struct node_host)); 472 if ($$ == NULL) 473 err(1, "address: calloc"); 474 $$->af = AF_INET; 475 memcpy(&$$->addr, hp->h_addr, sizeof(u_int32_t)); 476 } 477 } 478 | NUMBER '.' NUMBER '.' NUMBER '.' NUMBER { 479 if ($1 < 0 || $3 < 0 || $5 < 0 || $7 < 0 || 480 $1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) { 481 yyerror("illegal ip address %d.%d.%d.%d", 482 $1, $3, $5, $7); 483 YYERROR; 484 } 485 $$ = calloc(1, sizeof(struct node_host)); 486 if ($$ == NULL) 487 err(1, "address: calloc"); 488 $$->af = AF_INET; 489 $$->addr.addr32[0] = htonl(($1 << 24) | 490 ($3 << 16) | ($5 << 8) | $7); 491 } 492 | IPV6ADDR { $$ = $1; } 493 ; 494 495portspec : port_item { $$ = $1; } 496 | '{' port_list '}' { $$ = $2; } 497 ; 498 499port_list : port_item { $$ = $1; } 500 | port_list ',' port_item { $3->next = $1; $$ = $3; } 501 ; 502 503port_item : port { 504 $$ = malloc(sizeof(struct node_port)); 505 if ($$ == NULL) 506 err(1, "port_item: malloc"); 507 $$->port[0] = $1; 508 $$->port[1] = $1; 509 $$->op = PF_OP_EQ; 510 $$->next = NULL; 511 } 512 | PORTUNARY port { 513 $$ = malloc(sizeof(struct node_port)); 514 if ($$ == NULL) 515 err(1, "port_item: malloc"); 516 $$->port[0] = $2; 517 $$->port[1] = $2; 518 $$->op = $1; 519 $$->next = NULL; 520 } 521 | port PORTBINARY port { 522 $$ = malloc(sizeof(struct node_port)); 523 if ($$ == NULL) 524 err(1, "port_item: malloc"); 525 $$->port[0] = $1; 526 $$->port[1] = $3; 527 $$->op = $2; 528 $$->next = NULL; 529 } 530 ; 531 532port : NUMBER { 533 if (0 > $1 || $1 > 65535) { 534 yyerror("illegal port value %d", $1); 535 YYERROR; 536 } 537 $$ = htons($1); 538 } 539 | STRING { 540 struct servent *s = NULL; 541 542 s = getservbyname($1, "tcp"); 543 if (s == NULL) 544 s = getservbyname($1, "udp"); 545 if (s == NULL) { 546 yyerror("unknown protocol %s", $1); 547 YYERROR; 548 } 549 $$ = s->s_port; 550 } 551 ; 552 553flag : STRING { 554 int f; 555 556 if ((f = parse_flags($1)) < 0) { 557 yyerror("bad flags %s", $1); 558 YYERROR; 559 } 560 $$.b1 = f; 561 } 562 ; 563 564flags : /* empty */ { $$.b1 = 0; $$.b2 = 0; } 565 | FLAGS flag { $$.b1 = $2.b1; $$.b2 = 63; } 566 | FLAGS flag "/" flag { $$.b1 = $2.b1; $$.b2 = $4.b1; } 567 | FLAGS "/" flag { $$.b1 = 0; $$.b2 = $3.b1; } 568 ; 569 570icmpspec : /* empty */ { $$ = NULL; } 571 | ICMPTYPE icmp_item { $$ = $2; } 572 | ICMPTYPE '{' icmp_list '}' { $$ = $3; } 573 | ICMP6TYPE icmp6_item { $$ = $2; } 574 | ICMP6TYPE '{' icmp6_list '}' { $$ = $3; } 575 ; 576 577icmp_list : icmp_item { $$ = $1; } 578 | icmp_list ',' icmp_item { $3->next = $1; $$ = $3; } 579 ; 580 581icmp6_list : icmp6_item { $$ = $1; } 582 | icmp6_list ',' icmp6_item { $3->next = $1; $$ = $3; } 583 ; 584 585icmp_item : icmptype { 586 $$ = malloc(sizeof(struct node_icmp)); 587 if ($$ == NULL) 588 err(1, "icmp_item: malloc"); 589 $$->type = $1; 590 $$->code = 0; 591 $$->proto = IPPROTO_ICMP; 592 $$->next = NULL; 593 } 594 | icmptype CODE NUMBER { 595 $$ = malloc(sizeof(struct node_icmp)); 596 if ($$ == NULL) 597 err(1, "icmp_item: malloc"); 598 if ($3 < 0 || $3 > 255) { 599 yyerror("illegal icmp code %d", $3); 600 YYERROR; 601 } 602 $$->type = $1; 603 $$->code = $3 + 1; 604 $$->proto = IPPROTO_ICMP; 605 $$->next = NULL; 606 } 607 | icmptype CODE STRING { 608 struct icmpcodeent *p; 609 610 $$ = malloc(sizeof(struct node_icmp)); 611 if ($$ == NULL) 612 err(1, "icmp_item: malloc"); 613 $$->type = $1; 614 if ((p = geticmpcodebyname($1, $3, 615 AF_INET)) == NULL) { 616 yyerror("unknown icmp-code %s", $3); 617 YYERROR; 618 } 619 $$->code = p->code + 1; 620 $$->proto = IPPROTO_ICMP; 621 $$->next = NULL; 622 } 623 ; 624 625icmp6_item : icmp6type { 626 $$ = malloc(sizeof(struct node_icmp)); 627 if ($$ == NULL) 628 err(1, "icmp_item: malloc"); 629 $$->type = $1; 630 $$->code = 0; 631 $$->proto = IPPROTO_ICMPV6; 632 $$->next = NULL; 633 } 634 | icmp6type CODE NUMBER { 635 $$ = malloc(sizeof(struct node_icmp)); 636 if ($$ == NULL) 637 err(1, "icmp_item: malloc"); 638 if ($3 < 0 || $3 > 255) { 639 yyerror("illegal icmp6 code %d", $3); 640 YYERROR; 641 } 642 $$->type = $1; 643 $$->code = $3 + 1; 644 $$->proto = IPPROTO_ICMPV6; 645 $$->next = NULL; 646 } 647 | icmp6type CODE STRING { 648 struct icmpcodeent *p; 649 650 $$ = malloc(sizeof(struct node_icmp)); 651 if ($$ == NULL) 652 err(1, "icmp_item: malloc"); 653 $$->type = $1; 654 if ((p = geticmpcodebyname($1, $3, 655 AF_INET6)) == NULL) { 656 yyerror("unknown icmp6-code %s", $3); 657 YYERROR; 658 } 659 $$->code = p->code + 1; 660 $$->proto = IPPROTO_ICMPV6; 661 $$->next = NULL; 662 } 663 ; 664 665icmptype : STRING { 666 struct icmptypeent *p; 667 668 if ((p = geticmptypebyname($1, AF_INET)) == NULL) { 669 yyerror("unknown icmp-type %s", $1); 670 YYERROR; 671 } 672 $$ = p->type + 1; 673 } 674 | NUMBER { 675 if ($1 < 0 || $1 > 255) { 676 yyerror("illegal icmp type %d", $1); 677 YYERROR; 678 } 679 $$ = $1 + 1; 680 } 681 ; 682 683icmp6type : STRING { 684 struct icmptypeent *p; 685 686 if ((p = geticmptypebyname($1, AF_INET6)) == NULL) { 687 yyerror("unknown ipv6-icmp-type %s", $1); 688 YYERROR; 689 } 690 $$ = p->type + 1; 691 } 692 | NUMBER { 693 if ($1 < 0 || $1 > 255) { 694 yyerror("illegal icmp6 type %d", $1); 695 YYERROR; 696 } 697 $$ = $1 + 1; 698 } 699 ; 700 701keep : /* empty */ { $$ = 0; } 702 | KEEP STATE { $$ = PF_STATE_NORMAL; } 703 | MODULATE STATE { $$ = PF_STATE_MODULATE; } 704 ; 705 706minttl : /* empty */ { $$ = 0; } 707 | MINTTL NUMBER { 708 if ($2 < 0 || $2 > 255) { 709 yyerror("illegal min-ttl value %d", $2); 710 YYERROR; 711 } 712 $$ = $2; 713 } 714 ; 715 716nodf : /* empty */ { $$ = 0; } 717 | NODF { $$ = 1; } 718 ; 719 720allowopts : /* empty */ { $$ = 0; } 721 | ALLOWOPTS { $$ = 1; } 722 723natrule : NAT interface proto FROM ipspec TO ipspec ARROW address 724 { 725 struct pf_nat nat; 726 727 if (!natmode) { 728 yyerror("nat rule not permitted in filter mode"); 729 YYERROR; 730 } 731 memset(&nat, 0, sizeof(nat)); 732 733 if ($2 != NULL) { 734 memcpy(nat.ifname, $2->ifname, 735 sizeof(nat.ifname)); 736 nat.ifnot = $2->not; 737 } 738 if ($3 != NULL) { 739 nat.proto = $3->proto; 740 free($3); 741 } 742 if ($5 != NULL && $7 != NULL) { 743 if ($5->af && $7->af && $5->af != $7->af) { 744 yyerror("nat ip versions must match"); 745 YYERROR; 746 } else { 747 if ($5->af) 748 nat.af = $5->af; 749 else if ($7->af) 750 nat.af = $7->af; 751 } 752 } 753 if ($5 != NULL) { 754 memcpy(&nat.saddr, &$5->addr, 755 sizeof(nat.saddr)); 756 memcpy(&nat.smask, &$5->mask, 757 sizeof(nat.smask)); 758 nat.snot = $5->not; 759 free($5); 760 } 761 if ($7 != NULL) { 762 memcpy(&nat.daddr, &$7->addr, 763 sizeof(nat.daddr)); 764 memcpy(&nat.dmask, &$7->mask, 765 sizeof(nat.dmask)); 766 nat.dnot = $7->not; 767 free($7); 768 } 769 770 if ($9 == NULL) { 771 yyerror("nat rule requires redirection address"); 772 YYERROR; 773 } 774 /* we don't support IPv4 <-> IPv6 nat... yet */ 775 if (nat.af && $9->af != nat.af) { 776 yyerror("nat ip versions must match"); 777 YYERROR; 778 } else 779 nat.af = $9->af; 780 memcpy(&nat.raddr, &$9->addr, sizeof(nat.raddr)); 781 free($9); 782 pfctl_add_nat(pf, &nat); 783 } 784 ; 785 786binatrule : BINAT interface proto FROM address TO ipspec ARROW address 787 { 788 struct pf_binat binat; 789 790 if (!natmode) { 791 yyerror("binat rule not permitted in filter mode"); 792 YYERROR; 793 } 794 memset(&binat, 0, sizeof(binat)); 795 796 if ($2 != NULL) { 797 memcpy(binat.ifname, $2->ifname, 798 sizeof(binat.ifname)); 799 } 800 if ($3 != NULL) { 801 binat.proto = $3->proto; 802 free($3); 803 } 804 if ($5 != NULL && $7 != NULL) { 805 if ($5->af && $7->af && $5->af != $7->af) { 806 yyerror("binat ip versions must match"); 807 YYERROR; 808 } else { 809 if ($5->af) 810 binat.af = $5->af; 811 else if ($7->af) 812 binat.af = $7->af; 813 } 814 } 815 if ($5 != NULL) { 816 memcpy(&binat.saddr, &$5->addr, 817 sizeof(binat.saddr)); 818 free($5); 819 } 820 if ($7 != NULL) { 821 memcpy(&binat.daddr, &$7->addr, 822 sizeof(binat.daddr)); 823 memcpy(&binat.dmask, &$7->mask, 824 sizeof(binat.dmask)); 825 binat.dnot = $7->not; 826 free($7); 827 } 828 829 if ($9 == NULL) { 830 yyerror("binat rule requires redirection address"); 831 YYERROR; 832 } 833 /* we don't support IPv4 <-> IPv6 binat... yet */ 834 if (binat.af && $9->af != binat.af) { 835 yyerror("binat ip versions must match"); 836 YYERROR; 837 } else 838 binat.af = $9->af; 839 memcpy(&binat.raddr, &$9->addr, sizeof(binat.raddr)); 840 free($9); 841 pfctl_add_binat(pf, &binat); 842 } 843 844rdrrule : RDR interface proto FROM ipspec TO ipspec dport ARROW address rport 845 { 846 struct pf_rdr rdr; 847 848 if (!natmode) { 849 yyerror("rdr rule not permitted in filter mode"); 850 YYERROR; 851 } 852 memset(&rdr, 0, sizeof(rdr)); 853 854 if ($2 != NULL) { 855 memcpy(rdr.ifname, $2->ifname, 856 sizeof(rdr.ifname)); 857 rdr.ifnot = $2->not; 858 } 859 if ($3 != NULL) { 860 rdr.proto = $3->proto; 861 free($3); 862 } 863 if ($5 != NULL && $7 != NULL) { 864 if ($5->af && $7->af && $5->af != $7->af) { 865 yyerror("rdr ip versions must match"); 866 YYERROR; 867 } else { 868 if ($5->af) 869 rdr.af = $5->af; 870 else if ($7->af) 871 rdr.af = $7->af; 872 } 873 } 874 if ($5 != NULL) { 875 memcpy(&rdr.saddr, &$5->addr, 876 sizeof(rdr.saddr)); 877 memcpy(&rdr.smask, &$5->mask, 878 sizeof(rdr.smask)); 879 rdr.snot = $5->not; 880 free($5); 881 } 882 if ($7 != NULL) { 883 memcpy(&rdr.daddr, &$7->addr, 884 sizeof(rdr.daddr)); 885 memcpy(&rdr.dmask, &$7->mask, 886 sizeof(rdr.dmask)); 887 rdr.dnot = $7->not; 888 free($7); 889 } 890 891 rdr.dport = $8.a; 892 rdr.dport2 = $8.b; 893 rdr.opts |= $8.t; 894 895 if ($10 == NULL) { 896 yyerror("rdr rule requires redirection address"); 897 YYERROR; 898 } 899 if (rdr.af && $10->af != rdr.af) { 900 yyerror("rdr ip versions must match"); 901 YYERROR; 902 } else 903 rdr.af = $10->af; 904 memcpy(&rdr.raddr, &$10->addr, sizeof(rdr.raddr)); 905 free($10); 906 907 rdr.rport = $11.a; 908 rdr.opts |= $11.t; 909 910 pfctl_add_rdr(pf, &rdr); 911 } 912 ; 913 914dport : PORT port { 915 $$.a = $2; 916 $$.b = $$.t = 0; 917 } 918 | PORT port ':' port { 919 $$.a = $2; 920 $$.b = $4; 921 $$.t = PF_DPORT_RANGE; 922 } 923 ; 924 925rport : PORT port { 926 $$.a = $2; 927 $$.b = $$.t = 0; 928 } 929 | PORT port ':' '*' { 930 $$.a = $2; 931 $$.b = 0; 932 $$.t = PF_RPORT_RANGE; 933 } 934 ; 935%% 936 937int 938yyerror(char *fmt, ...) 939{ 940 va_list ap; 941 extern char *infile; 942 errors = 1; 943 944 va_start(ap, fmt); 945 fprintf(stderr, "%s:%d: ", infile, yyval.lineno); 946 vfprintf(stderr, fmt, ap); 947 fprintf(stderr, "\n"); 948 va_end(ap); 949 return (0); 950} 951 952int 953rule_consistent(struct pf_rule *r) 954{ 955 int problems = 0; 956 957 if (r->action == PF_SCRUB) { 958 if (r->quick) { 959 yyerror("quick does not apply to scrub"); 960 problems++; 961 } 962 if (r->keep_state == PF_STATE_MODULATE) { 963 yyerror("modulate state does not apply to scrub"); 964 problems++; 965 } 966 if (r->keep_state == PF_STATE_NORMAL) { 967 yyerror("keep state does not apply to scrub"); 968 problems++; 969 } 970 if (r->src.port_op) { 971 yyerror("src port does not apply to scrub"); 972 problems++; 973 } 974 if (r->dst.port_op) { 975 yyerror("dst port does not apply to scrub"); 976 problems++; 977 } 978 if (r->type || r->code) { 979 yyerror("icmp-type/code does not apply to scrub"); 980 problems++; 981 } 982 } else { 983 if (r->rule_flag & PFRULE_NODF) { 984 yyerror("nodf only applies to scrub"); 985 problems++; 986 } 987 if (r->min_ttl) { 988 yyerror("min-ttl only applies to scrub"); 989 problems++; 990 } 991 } 992 if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP && 993 (r->src.port_op || r->dst.port_op)) { 994 yyerror("port only applies to tcp/udp"); 995 problems++; 996 } 997 if (r->proto != IPPROTO_ICMP && r->proto != IPPROTO_ICMPV6 && 998 (r->type || r->code)) { 999 yyerror("icmp-type/code only applies to icmp"); 1000 problems++; 1001 } 1002 if (!r->af && (r->type || r->code)) { 1003 yyerror("must indicate address family with icmp-type/code"); 1004 problems++; 1005 } 1006 if ((r->proto == IPPROTO_ICMP && r->af == AF_INET6) || 1007 (r->proto == IPPROTO_ICMPV6 && r->af == AF_INET)) { 1008 yyerror("icmp version does not match address family"); 1009 problems++; 1010 } 1011 if (!(r->rule_flag & PFRULE_RETURNRST) && r->return_icmp && 1012 ((r->af != AF_INET6 && (r->return_icmp>>8) != ICMP_UNREACH) || 1013 (r->af == AF_INET6 && (r->return_icmp>>8) != ICMP6_DST_UNREACH))) { 1014 yyerror("return-icmp version does not match address family"); 1015 problems++; 1016 } 1017 if (r->keep_state == PF_STATE_MODULATE && r->proto && 1018 r->proto != IPPROTO_TCP) { 1019 yyerror("modulate state can only be applied to TCP rules"); 1020 problems++; 1021 } 1022 if (r->allow_opts && r->action != PF_PASS) { 1023 yyerror("allow-opts can only be specified for pass rules"); 1024 problems++; 1025 } 1026 return (-problems); 1027} 1028 1029#define CHECK_ROOT(T,r) \ 1030 do { \ 1031 if (r == NULL) { \ 1032 r = malloc(sizeof(T)); \ 1033 if (r == NULL) \ 1034 err(1, "malloc"); \ 1035 memset(r, 0, sizeof(T)); \ 1036 } \ 1037 } while (0) 1038 1039#define FREE_LIST(T,r) \ 1040 do { \ 1041 T *p, *n = r; \ 1042 while (n != NULL) { \ 1043 p = n; \ 1044 n = n->next; \ 1045 free(p); \ 1046 } \ 1047 } while (0) 1048 1049void expand_rule_hosts(struct pf_rule *r, 1050 struct node_if *interface, struct node_proto *proto, 1051 struct node_host *src_hosts, struct node_port *src_ports, 1052 struct node_host *dst_hosts, struct node_port *dst_ports, 1053 struct node_icmp *icmp_type) 1054{ 1055 struct node_host *src_host, *dst_host; 1056 struct node_port *src_port, *dst_port; 1057 int nomatch = 0; 1058 1059 src_host = src_hosts; 1060 while (src_host != NULL) { 1061 src_port = src_ports; 1062 while (src_port != NULL) { 1063 dst_host = dst_hosts; 1064 while (dst_host != NULL) { 1065 dst_port = dst_ports; 1066 while (dst_port != NULL) { 1067 memcpy(r->ifname, interface->ifname, 1068 sizeof(r->ifname)); 1069 r->proto = proto->proto; 1070 r->src.addr = src_host->addr; 1071 r->src.mask = src_host->mask; 1072 r->src.not = src_host->not; 1073 r->src.port[0] = src_port->port[0]; 1074 r->src.port[1] = src_port->port[1]; 1075 r->src.port_op = src_port->op; 1076 r->dst.addr = dst_host->addr; 1077 r->dst.mask = dst_host->mask; 1078 r->dst.not = dst_host->not; 1079 r->dst.port[0] = dst_port->port[0]; 1080 r->dst.port[1] = dst_port->port[1]; 1081 r->dst.port_op = dst_port->op; 1082 r->type = icmp_type->type; 1083 r->code = icmp_type->code; 1084 1085 if (src_host->af && 1086 dst_host->af && 1087 (src_host->af != 1088 dst_host->af)) { 1089 yyerror("address family" 1090 " mismatch"); 1091 nomatch++; 1092 } else if (src_host->af) 1093 r->af = src_host->af; 1094 else if (dst_host->af) 1095 r->af = dst_host->af; 1096 1097 if (icmp_type->proto && 1098 r->proto != icmp_type->proto) { 1099 yyerror("icmp-type mismatch"); 1100 nomatch++; 1101 } 1102 1103 if (rule_consistent(r) < 0 || nomatch) 1104 yyerror("skipping rule " 1105 "due to errors"); 1106 else 1107 pfctl_add_rule(pf, r); 1108 dst_port = dst_port->next; 1109 } 1110 dst_host = dst_host->next; 1111 } 1112 src_port = src_port->next; 1113 } 1114 src_host = src_host->next; 1115 } 1116} 1117 1118void expand_rule_protos(struct pf_rule *r, 1119 struct node_if *interface, struct node_proto *protos, 1120 struct node_host *src_hosts, struct node_port *src_ports, 1121 struct node_host *dst_hosts, struct node_port *dst_ports, 1122 struct node_icmp *icmp_types) 1123{ 1124 struct node_proto *proto; 1125 struct node_icmp *icmp_type; 1126 1127 proto = protos; 1128 while (proto != NULL) { 1129 icmp_type = icmp_types; 1130 while (icmp_type != NULL) { 1131 expand_rule_hosts(r, interface, proto, src_hosts, 1132 src_ports, dst_hosts, dst_ports, icmp_type); 1133 icmp_type = icmp_type->next; 1134 } 1135 proto = proto->next; 1136 } 1137} 1138 1139void 1140expand_rule(struct pf_rule *r, 1141 struct node_if *interfaces, struct node_proto *protos, 1142 struct node_host *src_hosts, struct node_port *src_ports, 1143 struct node_host *dst_hosts, struct node_port *dst_ports, 1144 struct node_icmp *icmp_types) 1145{ 1146 struct node_if *interface; 1147 1148 CHECK_ROOT(struct node_if, interfaces); 1149 CHECK_ROOT(struct node_proto, protos); 1150 CHECK_ROOT(struct node_host, src_hosts); 1151 CHECK_ROOT(struct node_port, src_ports); 1152 CHECK_ROOT(struct node_host, dst_hosts); 1153 CHECK_ROOT(struct node_port, dst_ports); 1154 CHECK_ROOT(struct node_icmp, icmp_types); 1155 1156 interface = interfaces; 1157 while (interface != NULL) { 1158 expand_rule_protos(r, interface, protos, src_hosts, 1159 src_ports, dst_hosts, dst_ports, icmp_types); 1160 interface = interface->next; 1161 } 1162 1163 FREE_LIST(struct node_if, interfaces); 1164 FREE_LIST(struct node_proto, protos); 1165 FREE_LIST(struct node_host, src_hosts); 1166 FREE_LIST(struct node_port, src_ports); 1167 FREE_LIST(struct node_host, dst_hosts); 1168 FREE_LIST(struct node_port, dst_ports); 1169 FREE_LIST(struct node_icmp, icmp_types); 1170 1171} 1172 1173#undef FREE_LIST 1174#undef CHECK_ROOT 1175 1176int 1177lookup(char *s) 1178{ 1179 int i; 1180 struct keywords { 1181 char *k_name; 1182 int k_val; 1183 } keywords[] = { 1184 { "all", ALL}, 1185 { "allow-opts", ALLOWOPTS}, 1186 { "any", ANY}, 1187 { "binat", BINAT}, 1188 { "block", BLOCK}, 1189 { "code", CODE}, 1190 { "flags", FLAGS}, 1191 { "from", FROM}, 1192 { "icmp-type", ICMPTYPE}, 1193 { "ipv6-icmp-type", ICMP6TYPE}, 1194 { "in", IN}, 1195 { "inet", INET}, 1196 { "inet6", INET6}, 1197 { "keep", KEEP}, 1198 { "log", LOG}, 1199 { "log-all", LOGALL}, 1200 { "min-ttl", MINTTL}, 1201 { "modulate", MODULATE}, 1202 { "nat", NAT}, 1203 { "no-df", NODF}, 1204 { "on", ON}, 1205 { "out", OUT}, 1206 { "pass", PASS}, 1207 { "port", PORT}, 1208 { "proto", PROTO}, 1209 { "quick", QUICK}, 1210 { "rdr", RDR}, 1211 { "return", RETURN}, 1212 { "return-icmp",RETURNICMP}, 1213 { "return-icmp6",RETURNICMP6}, 1214 { "return-rst", RETURNRST}, 1215 { "scrub", SCRUB}, 1216 { "state", STATE}, 1217 { "to", TO}, 1218 { NULL, 0 }, 1219 }; 1220 1221 for (i = 0; keywords[i].k_name != NULL; i++) { 1222 if (strcmp(s, keywords[i].k_name) == 0) { 1223 if (debug > 1) 1224 fprintf(stderr, "%s: %d\n", s, 1225 keywords[i].k_val); 1226 return (keywords[i].k_val); 1227 } 1228 } 1229 if (debug > 1) 1230 fprintf(stderr, "string: %s\n", s); 1231 return (STRING); 1232} 1233 1234char *parsebuf; 1235int parseindex; 1236 1237int 1238lgetc(FILE *fin) 1239{ 1240 int c, next; 1241 1242restart: 1243 if (parsebuf) { 1244 /* Reading characters from the parse buffer, instead of input */ 1245 c = parsebuf[parseindex++]; 1246 if (c != '\0') 1247 return (c); 1248 free(parsebuf); 1249 parsebuf = NULL; 1250 parseindex = 0; 1251 goto restart; 1252 } 1253 1254 c = getc(fin); 1255 if (c == '\\') { 1256 next = getc(fin); 1257 if (next != '\n') { 1258 ungetc(next, fin); 1259 return (c); 1260 } 1261 yylval.lineno = lineno; 1262 lineno++; 1263 goto restart; 1264 } 1265 return (c); 1266} 1267 1268int 1269lungetc(int c, FILE *fin) 1270{ 1271 if (parsebuf && parseindex) { 1272 /* XXX breaks on index 0 */ 1273 parseindex--; 1274 return (c); 1275 } 1276 return ungetc(c, fin); 1277} 1278 1279int 1280findeol() 1281{ 1282 int c; 1283 1284 if (parsebuf) { 1285 free(parsebuf); 1286 parsebuf = NULL; 1287 parseindex = 0; 1288 } 1289 1290 /* skip to either EOF or the first real EOL */ 1291 while (1) { 1292 c = lgetc(fin); 1293 if (c == '\\') { 1294 c = lgetc(fin); 1295 if (c == '\n') 1296 continue; 1297 } 1298 if (c == EOF || c == '\n') 1299 break; 1300 } 1301 return (ERROR); 1302} 1303 1304int 1305yylex(void) 1306{ 1307 char buf[8096], *p, *val; 1308 int endc, c, next; 1309 int token; 1310 1311top: 1312 p = buf; 1313 while ((c = lgetc(fin)) == ' ' || c == '\t') 1314 ; 1315 1316 yylval.lineno = lineno; 1317 if (c == '#') 1318 while ((c = lgetc(fin)) != '\n' && c != EOF) 1319 ; 1320 if (c == '$' && parsebuf == NULL) { 1321 while (1) { 1322 if ((c = lgetc(fin)) == EOF) 1323 return (0); 1324 if (p + 1 >= buf + sizeof(buf) - 1) { 1325 yyerror("string too long"); 1326 return (findeol()); 1327 } 1328 if (isalnum(c) || c == '_') { 1329 *p++ = (char)c; 1330 continue; 1331 } 1332 *p = '\0'; 1333 lungetc(c, fin); 1334 break; 1335 } 1336 val = symget(buf); 1337 if (val == NULL) 1338 return (ERROR); 1339 parsebuf = strdup(val); 1340 if (parsebuf == NULL) 1341 err(1, "parsebuf: strdup"); 1342 parseindex = 0; 1343 goto top; 1344 } 1345 1346 switch (c) { 1347 case '\'': 1348 case '"': 1349 endc = c; 1350 while (1) { 1351 if ((c = lgetc(fin)) == EOF) 1352 return (0); 1353 if (c == endc) { 1354 *p = '\0'; 1355 break; 1356 } 1357 if (c == '\n') 1358 continue; 1359 if (p + 1 >= buf + sizeof(buf) - 1) { 1360 yyerror("string too long"); 1361 return (findeol()); 1362 } 1363 *p++ = (char)c; 1364 } 1365 yylval.v.string = strdup(buf); 1366 if (yylval.v.string == NULL) 1367 err(1, "yylex: strdup"); 1368 return (STRING); 1369 case '=': 1370 yylval.v.i = PF_OP_EQ; 1371 return (PORTUNARY); 1372 case '!': 1373 next = lgetc(fin); 1374 if (next == '=') { 1375 yylval.v.i = PF_OP_NE; 1376 return (PORTUNARY); 1377 } 1378 lungetc(next, fin); 1379 break; 1380 case '<': 1381 next = lgetc(fin); 1382 if (next == '>') { 1383 yylval.v.i = PF_OP_XRG; 1384 return (PORTBINARY); 1385 } else if (next == '=') { 1386 yylval.v.i = PF_OP_LE; 1387 } else { 1388 yylval.v.i = PF_OP_LT; 1389 lungetc(next, fin); 1390 } 1391 return (PORTUNARY); 1392 break; 1393 case '>': 1394 next = lgetc(fin); 1395 if (next == '<') { 1396 yylval.v.i = PF_OP_IRG; 1397 return (PORTBINARY); 1398 } else if (next == '=') { 1399 yylval.v.i = PF_OP_GE; 1400 } else { 1401 yylval.v.i = PF_OP_GT; 1402 lungetc(next, fin); 1403 } 1404 return (PORTUNARY); 1405 break; 1406 case '-': 1407 next = lgetc(fin); 1408 if (next == '>') 1409 return (ARROW); 1410 lungetc(next, fin); 1411 break; 1412 } 1413 1414 /* Need to parse v6 addresses before tokenizing numbers. ick */ 1415 if (isxdigit(c) || c == ':') { 1416 struct node_host *node = NULL; 1417 u_int32_t addr[4]; 1418 char lookahead[46]; 1419 int i = 0, notv6addr = 0; 1420 1421 lookahead[i] = c; 1422 1423 while (i < sizeof(lookahead) && 1424 (isxdigit(c) || c == ':' || c == '.')) { 1425 lookahead[++i] = c = lgetc(fin); 1426 } 1427 1428 /* quick check avoids calling inet_pton too often */ 1429 if (isalnum(c)) { 1430 notv6addr++; 1431 } 1432 lungetc(lookahead[i], fin); 1433 lookahead[i] = '\0'; 1434 1435 if(!notv6addr && inet_pton(AF_INET6, lookahead, &addr) == 1) { 1436 node = calloc(1, sizeof(struct node_host)); 1437 node->af = AF_INET6; 1438 memcpy (&node->addr, &addr, sizeof(addr)); 1439 yylval.v.host = node; 1440 return IPV6ADDR; 1441 } else { 1442 free(node); 1443 while (i > 1) { 1444 lungetc(lookahead[--i], fin); 1445 } 1446 c = lookahead[--i]; 1447 } 1448 } 1449 1450 if (isdigit(c)) { 1451 int index = 0, base = 10; 1452 u_int64_t n = 0; 1453 1454 yylval.v.number = 0; 1455 while (1) { 1456 if (base == 10) { 1457 if (!isdigit(c)) 1458 break; 1459 c -= '0'; 1460 } else if (base == 16) { 1461 if (isdigit(c)) 1462 c -= '0'; 1463 else if (c >= 'a' && c <= 'f') 1464 c -= 'a'; 1465 else if (c >= 'A' && c <= 'F') 1466 c -= 'A'; 1467 else 1468 break; 1469 } 1470 n = n * base + c; 1471 1472 if (n > UINT_MAX) { 1473 yyerror("number is too large"); 1474 return (ERROR); 1475 } 1476 c = lgetc(fin); 1477 if (c == EOF) 1478 break; 1479 if (index++ == 0 && n == 0 && c == 'x') { 1480 base = 16; 1481 c = lgetc(fin); 1482 if (c == EOF) 1483 break; 1484 } 1485 } 1486 yylval.v.number = (u_int32_t)n; 1487 1488 if (c != EOF) 1489 lungetc(c, fin); 1490 if (debug > 1) 1491 fprintf(stderr, "number: %d\n", yylval.v.number); 1492 return (NUMBER); 1493 } 1494 1495#define allowed_in_string(x) \ 1496 isalnum(x) || (ispunct(x) && x != '(' && x != ')' && x != '<' && \ 1497 x != '>' && x != '!' && x != '=' && x != '/' && x != '#' && x != ',') 1498 1499 if (isalnum(c)) { 1500 do { 1501 *p++ = c; 1502 if (p-buf >= sizeof buf) { 1503 yyerror("string too long"); 1504 return (ERROR); 1505 } 1506 } while ((c = lgetc(fin)) != EOF && (allowed_in_string(c))); 1507 lungetc(c, fin); 1508 *p = '\0'; 1509 token = lookup(buf); 1510 yylval.v.string = strdup(buf); 1511 if (yylval.v.string == NULL) 1512 err(1, "yylex: strdup"); 1513 return (token); 1514 } 1515 if (c == '\n') { 1516 yylval.lineno = lineno; 1517 lineno++; 1518 } 1519 if (c == EOF) 1520 return (0); 1521 return (c); 1522} 1523 1524int 1525parse_rules(FILE *input, struct pfctl *xpf) 1526{ 1527 natmode = 0; 1528 fin = input; 1529 pf = xpf; 1530 errors = 0; 1531 yyparse(); 1532 return (errors ? -1 : 0); 1533} 1534 1535int 1536parse_nat(FILE *input, struct pfctl *xpf) 1537{ 1538 natmode = 1; 1539 fin = input; 1540 pf = xpf; 1541 errors = 0; 1542 yyparse(); 1543 return (errors ? -1 : 0); 1544} 1545 1546void 1547ipmask(struct pf_addr *m, u_int8_t b, int af) 1548{ 1549 int i, j = 0; 1550 1551 while (b >= 32) { 1552 m->addr32[j++] = 0xffffffff; 1553 b -= 32; 1554 } 1555 for (i = 31; i > 31-b; --i) 1556 m->addr32[j] |= (1 << i); 1557 if (b) 1558 m->addr32[j] = htonl(m->addr32[j]); 1559} 1560 1561struct pf_rule_addr * 1562new_addr(void) 1563{ 1564 struct pf_rule_addr *ra; 1565 1566 ra = malloc(sizeof(struct pf_rule_addr)); 1567 if (ra == NULL) 1568 err(1, "new_addr: malloc failed"); 1569 memset(ra, 0, sizeof(*ra)); 1570 return (ra); 1571} 1572 1573/* 1574 * Over-designed efficiency is a French and German concept, so how about 1575 * we wait until they discover this ugliness and make it all fancy. 1576 */ 1577int 1578symset(char *nam, char *val) 1579{ 1580 struct sym *sym; 1581 1582 sym = calloc(1, sizeof(*sym)); 1583 if (sym == NULL) 1584 return (-1); 1585 sym->nam = strdup(nam); 1586 if (sym->nam == NULL) { 1587 free(sym); 1588 return (-1); 1589 } 1590 sym->val = strdup(val); 1591 if (sym->val == NULL) { 1592 free(sym->nam); 1593 free(sym); 1594 return (-1); 1595 } 1596 sym->next = symhead; 1597 symhead = sym; 1598 return (0); 1599} 1600 1601char * 1602symget(char *nam) 1603{ 1604 struct sym *sym; 1605 1606 for (sym = symhead; sym; sym = sym->next) 1607 if (strcmp(nam, sym->nam) == 0) 1608 return (sym->val); 1609 return (NULL); 1610} 1611 1612struct ifaddrs **ifa0tab, **ifa4tab, **ifa6tab; 1613int ifa0len, ifa4len, ifa6len; 1614 1615int 1616ifa_comp(const void *p1, const void *p2) 1617{ 1618 struct ifaddrs *ifa1 = *(struct ifaddrs **)p1; 1619 struct ifaddrs *ifa2 = *(struct ifaddrs **)p2; 1620 1621 return strcmp(ifa1->ifa_name, ifa2->ifa_name); 1622} 1623 1624void 1625ifa_load(void) 1626{ 1627 struct ifaddrs *ifap, *ifa; 1628 int ifalen = 0; 1629 1630 if (getifaddrs(&ifap) < 0) 1631 err(1, "getifaddrs"); 1632 for (ifa = ifap; ifa; ifa = ifa->ifa_next) 1633 ifalen++; 1634 /* (over-)allocate tables */ 1635 ifa0tab = malloc(ifalen * sizeof(void *)); 1636 ifa4tab = malloc(ifalen * sizeof(void *)); 1637 ifa6tab = malloc(ifalen * sizeof(void *)); 1638 if (!ifa0tab || !ifa4tab || !ifa6tab) 1639 err(1, "malloc"); 1640 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 1641 if (ifa->ifa_addr->sa_family == AF_LINK) { 1642 if (bsearch(&ifa, ifa0tab, ifa0len, sizeof(void *), 1643 ifa_comp)) 1644 continue; /* take only the first LINK address */ 1645 ifa0tab[ifa0len++] = ifa; 1646 qsort(ifa0tab, ifa0len, sizeof(void *), ifa_comp); 1647 } 1648 if (ifa->ifa_addr->sa_family == AF_INET) { 1649 if (bsearch(&ifa, ifa4tab, ifa4len, sizeof(void *), 1650 ifa_comp)) 1651 continue; /* take only the first IPv4 address */ 1652 ifa4tab[ifa4len++] = ifa; 1653 qsort(ifa4tab, ifa4len, sizeof(void *), ifa_comp); 1654 } 1655 if (ifa->ifa_addr->sa_family == AF_INET6) { 1656 /* XXX - better address selection required! */ 1657 if (bsearch(&ifa, ifa6tab, ifa6len, sizeof(void *), 1658 ifa_comp)) 1659 continue; /* take only the first IPv6 address */ 1660 ifa6tab[ifa6len++] = ifa; 1661 qsort(ifa6tab, ifa6len, sizeof(void *), ifa_comp); 1662 } 1663 } 1664 /* shrink tables */ 1665 ifa0tab = realloc(ifa0tab, ifa0len * sizeof(void *)); 1666 ifa4tab = realloc(ifa4tab, ifa4len * sizeof(void *)); 1667 ifa6tab = realloc(ifa6tab, ifa6len * sizeof(void *)); 1668 if (!ifa0tab || !ifa4tab || !ifa6tab) 1669 err(1, "realloc"); 1670} 1671 1672struct ifaddrs * 1673ifa0_lookup(char *ifa_name) 1674{ 1675 struct ifaddrs ifa, *ifp = &ifa, **ifpp; 1676 1677 if (!ifa0tab) 1678 ifa_load(); 1679 ifa.ifa_name = ifa_name; 1680 ifpp = bsearch(&ifp, ifa0tab, ifa0len, sizeof(void *), ifa_comp); 1681 return ifpp ? *ifpp : NULL; 1682} 1683 1684struct ifaddrs * 1685ifa4_lookup(char *ifa_name) 1686{ 1687 struct ifaddrs ifa, *ifp = &ifa, **ifpp; 1688 1689 if (!ifa4tab) 1690 ifa_load(); 1691 ifa.ifa_name = ifa_name; 1692 ifpp = bsearch(&ifp, ifa4tab, ifa4len, sizeof(void *), ifa_comp); 1693 return ifpp ? *ifpp : NULL; 1694} 1695 1696struct ifaddrs * 1697ifa6_lookup(char *ifa_name) 1698{ 1699 struct ifaddrs ifa, *ifp = &ifa, **ifpp; 1700 1701 if (!ifa6tab) 1702 ifa_load(); 1703 ifa.ifa_name = ifa_name; 1704 ifpp = bsearch(&ifp, ifa6tab, ifa6len, sizeof(void *), ifa_comp); 1705 return ifpp ? *ifpp : NULL; 1706} 1707 1708