parse.y revision 1.22
1/* $OpenBSD: parse.y,v 1.22 2001/08/23 05:36:53 millert 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 <net/pfvar.h> 37#include <arpa/inet.h> 38 39#include <stdio.h> 40#include <netdb.h> 41#include <stdarg.h> 42#include <errno.h> 43#include <string.h> 44#include <ctype.h> 45#include <err.h> 46 47#include "pfctl_parser.h" 48 49static struct pfctl *pf = NULL; 50static FILE *fin = NULL; 51static int debug = 0; 52static int lineno = 1; 53static int errors = 0; 54static int natmode = 0; 55 56struct node_proto { 57 u_int8_t proto; 58 struct node_proto *next; 59}; 60 61struct node_host { 62 u_int32_t addr; 63 u_int32_t mask; 64 u_int8_t not; 65 struct node_host *next; 66}; 67 68struct node_port { 69 u_int16_t port[2]; 70 u_int8_t op; 71 struct node_port *next; 72}; 73 74struct peer { 75 struct node_host *host; 76 struct node_port *port; 77}; 78 79int rule_consistent(struct pf_rule *); 80int yyparse(void); 81struct pf_rule_addr *new_addr(void); 82u_int32_t ipmask(u_int8_t); 83void expand_rule(struct pf_rule *, struct node_proto *, 84 struct node_host *, struct node_port *, 85 struct node_host *, struct node_port *); 86 87struct sym { 88 struct sym *next; 89 char *nam; 90 char *val; 91}; 92struct sym *symhead = NULL; 93 94int symset(char *name, char *val); 95char * symget(char *name); 96 97typedef struct { 98 union { 99 u_int32_t number; 100 int i; 101 char *string; 102 struct { 103 char *string; 104 int not; 105 } iface; 106 struct { 107 u_int8_t b1; 108 u_int8_t b2; 109 u_int16_t w; 110 } b; 111 struct { 112 int a; 113 int b; 114 int t; 115 } range; 116 struct node_proto *proto; 117 struct node_host *host; 118 struct node_port *port; 119 struct peer peer; 120 struct { 121 struct peer src, dst; 122 } fromto; 123 } v; 124 int lineno; 125} YYSTYPE; 126 127%} 128 129%token PASS BLOCK SCRUB RETURN IN OUT LOG LOGALL QUICK ON FROM TO FLAGS 130%token RETURNRST RETURNICMP PROTO ALL ANY ICMPTYPE CODE KEEP STATE PORT 131%token RDR NAT ARROW NODF MINTTL ERROR 132%token <v.string> STRING 133%token <v.number> NUMBER 134%token <v.i> PORTUNARY PORTBINARY 135%type <v.iface> iface natiface 136%type <v.number> port icmptype minttl 137%type <v.i> dir log quick keep nodf 138%type <v.b> action icmpspec flag flags blockspec 139%type <v.range> dport rport 140%type <v.proto> proto proto_list proto_item 141%type <v.fromto> fromto 142%type <v.peer> ipportspec 143%type <v.host> ipspec host address host_list 144%type <v.port> portspec port_list port_item 145%% 146 147ruleset : /* empty */ 148 | ruleset '\n' 149 | ruleset pfrule '\n' 150 | ruleset natrule '\n' 151 | ruleset rdrrule '\n' 152 | ruleset varset '\n' 153 | ruleset error '\n' { errors++; } 154 ; 155 156varset : STRING PORTUNARY STRING 157 { 158 printf("%s = %s\n", $1, $3); 159 if (symset($1, $3) == -1) { 160 yyerror("cannot store variable %s", $1); 161 YYERROR; 162 } 163 } 164 ; 165 166pfrule : action dir log quick iface proto fromto flags icmpspec keep nodf minttl 167 { 168 struct pf_rule r; 169 170 if (natmode) { 171 yyerror("filter rule not permitted in nat mode"); 172 YYERROR; 173 } 174 memset(&r, 0, sizeof(r)); 175 176 r.action = $1.b1; 177 if ($1.b2) 178 r.rule_flag |= PFRULE_RETURNRST; 179 else 180 r.return_icmp = $1.w; 181 r.direction = $2; 182 r.log = $3; 183 r.quick = $4; 184 if ($5.string) 185 memcpy(r.ifname, $5.string, sizeof(r.ifname)); 186 187 r.flags = $8.b1; 188 r.flagset = $8.b2; 189 r.type = $9.b1; 190 r.code = $9.b2; 191 r.keep_state = $10; 192 193 if ($11) 194 r.rule_flag |= PFRULE_NODF; 195 if ($12) 196 r.min_ttl = $12; 197 198 expand_rule(&r, $6, $7.src.host, $7.src.port, 199 $7.dst.host, $7.dst.port); 200 } 201 ; 202 203action : PASS { $$.b1 = PF_PASS; } 204 | BLOCK blockspec { $$ = $2; $$.b1 = PF_DROP; } 205 | SCRUB { $$.b1 = PF_SCRUB; } 206 ; 207 208blockspec : /* empty */ { $$.b2 = 0; $$.w = 0; } 209 | RETURNRST { $$.b2 = 1; $$.w = 0;} 210 | RETURNICMP { 211 $$.b2 = 0; 212 $$.w = (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT; 213 } 214 | RETURNICMP '(' STRING ')' { 215 struct icmpcodeent *p; 216 217 if ((p = geticmpcodebyname(ICMP_UNREACH, $3)) == NULL) { 218 yyerror("unknown icmp code %s", $3); 219 YYERROR; 220 } 221 $$.w = (p->type << 8) | p->code; 222 $$.b2 = 0; 223 } 224 ; 225 226dir : IN { $$ = PF_IN; } 227 | OUT { $$ = PF_OUT; } 228 ; 229 230log : /* empty */ { $$ = 0; } 231 | LOG { $$ = 1; } 232 | LOGALL { $$ = 2; } 233 ; 234 235quick : /* empty */ { $$ = 0; } 236 | QUICK { $$ = 1; } 237 ; 238 239natiface : iface 240 | ON '!' STRING { 241 $$.string = strdup($3); $$.not = 1; 242 } 243 ; 244iface : /* empty */ { $$.string = NULL; } 245 | ON STRING { $$.string = strdup($2); } 246 ; 247 248proto : /* empty */ { $$ = NULL; } 249 | PROTO proto_item { $$ = $2; } 250 | PROTO '{' proto_list '}' { $$ = $3; } 251 ; 252 253proto_list : proto_item { $$ = $1; } 254 | proto_list ',' proto_item { $3->next = $1; $$ = $3; } 255 ; 256 257proto_item : NUMBER { 258 struct protoent *p; 259 260 if ((p = getprotobynumber($1)) == NULL) { 261 yyerror("unknown protocol %d", $1); 262 YYERROR; 263 } 264 $$ = malloc(sizeof(struct node_proto)); 265 $$->proto = p->p_proto; 266 $$->next = NULL; 267 } 268 | STRING { 269 struct protoent *p; 270 271 if ((p = getprotobyname($1)) == NULL) { 272 yyerror("unknown protocol %s", $1); 273 YYERROR; 274 } 275 $$ = malloc(sizeof(struct node_proto)); 276 $$->proto = p->p_proto; 277 $$->next = NULL; 278 } 279 ; 280 281fromto : ALL { 282 $$.src.host = NULL; 283 $$.src.port = NULL; 284 $$.dst.host = NULL; 285 $$.dst.port = NULL; 286 } 287 | FROM ipportspec TO ipportspec { 288 $$.src = $2; 289 $$.dst = $4; 290 } 291 ; 292 293ipportspec : ipspec { $$.host = $1; $$.port = NULL; } 294 | ipspec PORT portspec { 295 $$.host = $1; 296 $$.port = $3; 297 } 298 ; 299 300ipspec : ANY { $$ = NULL; } 301 | '!' host { $$ = $2; $$->not = 1; } 302 | host { $$ = $1; $$->not = 0; } 303 | '{' host_list '}' { $$ = $2; } 304 ; 305 306host_list : host { $$ = $1; } 307 | host_list ',' host { $3->next = $1; $$ = $3; } 308 309host : address { 310 $$ = $1; 311 $$->mask = 0xffffffff; 312 } 313 | address '/' NUMBER { 314 if ($3 < 0 || $3 > 32) { 315 yyerror("illegal netmask value %d", $3); 316 YYERROR; 317 } 318 $$ = $1; 319 $$->mask = ipmask($3); 320 } 321 ; 322 323address : STRING { 324 struct hostent *hp; 325 326 if ((hp = gethostbyname($1)) == NULL) { 327 yyerror("cannot resolve %s", $1); 328 YYERROR; 329 } 330 $$ = calloc(1, sizeof(struct node_host)); 331 memcpy(&$$->addr, hp->h_addr, sizeof(u_int32_t)); 332 } 333 | NUMBER '.' NUMBER '.' NUMBER '.' NUMBER { 334 if ($1 < 0 || $3 < 0 || $5 < 0 || $7 < 0 || 335 $1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) { 336 yyerror("illegal ip address %d.%d.%d.%d", 337 $1, $3, $5, $7); 338 YYERROR; 339 } 340 $$ = calloc(1, sizeof(struct node_host)); 341 $$->addr = htonl(($1 << 24) | ($3 << 16) | ($5 << 8) | $7); 342 } 343 ; 344 345portspec : port_item { $$ = $1; } 346 | '{' port_list '}' { $$ = $2; } 347 ; 348 349port_list : port_item { $$ = $1; } 350 | port_list ',' port_item { $3->next = $1; $$ = $3; } 351 ; 352 353port_item : port { 354 $$ = malloc(sizeof(struct node_port)); 355 $$->port[0] = $1; 356 $$->port[1] = $1; 357 $$->op = PF_OP_EQ; 358 $$->next = NULL; 359 } 360 | PORTUNARY port { 361 $$ = malloc(sizeof(struct node_port)); 362 $$->port[0] = $2; 363 $$->port[1] = $2; 364 $$->op = $1; 365 $$->next = NULL; 366 } 367 | port PORTBINARY port { 368 $$ = malloc(sizeof(struct node_port)); 369 $$->port[0] = $1; 370 $$->port[1] = $3; 371 $$->op = $2; 372 $$->next = NULL; 373 } 374 ; 375 376port : NUMBER { 377 if (0 > $1 || $1 > 65535) { 378 yyerror("illegal port value %d", $1); 379 YYERROR; 380 } 381 $$ = htons($1); 382 } 383 | STRING { 384 struct servent *s = NULL; 385 386 s = getservbyname($1, "tcp"); 387 if (s == NULL) 388 s = getservbyname($1, "udp"); 389 if (s == NULL) { 390 yyerror("unknown protocol %s", $1); 391 YYERROR; 392 } 393 $$ = s->s_port; 394 } 395 ; 396 397flag : STRING { 398 int f; 399 400 if ((f = parse_flags($1)) < 0) { 401 yyerror("bad flags %s", $1); 402 YYERROR; 403 } 404 $$.b1 = f; 405 } 406 ; 407 408flags : /* empty */ { $$.b1 = 0; $$.b2 = 0; } 409 | FLAGS flag { $$.b1 = $2.b1; $$.b2 = 63; } 410 | FLAGS flag "/" flag { $$.b1 = $2.b1; $$.b2 = $4.b1; } 411 | FLAGS "/" flag { $$.b1 = 0; $$.b2 = $3.b1; } 412 ; 413 414icmpspec : /* empty */ { $$.b1 = 0; $$.b2 = 0; } 415 | ICMPTYPE icmptype { $$.b1 = $2; $$.b2 = 0; } 416 | ICMPTYPE icmptype CODE NUMBER { 417 if ($4 < 0 || $4 > 255) { 418 yyerror("illegal icmp code %d", $4); 419 YYERROR; 420 } 421 $$.b1 = $2; 422 $$.b2 = $4 + 1; 423 } 424 | ICMPTYPE icmptype CODE STRING { 425 struct icmpcodeent *p; 426 427 $$.b1 = $2; 428 if ((p = geticmpcodebyname($2, $4)) == NULL) { 429 yyerror("unknown icmp-code %s", $4); 430 YYERROR; 431 } 432 $$.b2 = p->code + 1; 433 } 434 ; 435 436icmptype : STRING { 437 struct icmptypeent *p; 438 439 if ((p = geticmptypebyname($1)) == NULL) { 440 yyerror("unknown icmp-type %s", $1); 441 YYERROR; 442 } 443 $$ = p->type + 1; 444 } 445 | NUMBER { 446 if ($1 < 0 || $1 > 255) { 447 yyerror("illegal icmp type %d", $1); 448 YYERROR; 449 } 450 $$ = $1 + 1; 451 } 452 ; 453 454 455keep : /* empty */ { $$ = 0; } 456 | KEEP STATE { $$ = 1; } 457 ; 458 459minttl : /* empty */ { $$ = 0; } 460 | MINTTL NUMBER { 461 if ($2 < 0 || $2 > 255) { 462 yyerror("illegal min-ttl value %d", $2); 463 YYERROR; 464 } 465 $$ = $2; 466 } 467 ; 468 469nodf : /* empty */ { $$ = 0; } 470 | NODF { $$ = 1; } 471 ; 472 473natrule : NAT natiface proto FROM ipspec TO ipspec ARROW address 474 { 475 struct pf_nat nat; 476 477 if (!natmode) { 478 yyerror("nat rule not permitted in filter mode"); 479 YYERROR; 480 } 481 memset(&nat, 0, sizeof(nat)); 482 483 if ($2.string) { 484 memcpy(nat.ifname, $2.string, 485 sizeof(nat.ifname)); 486 nat.ifnot = $2.not; 487 } 488 if ($3 != NULL) { 489 nat.proto = $3->proto; 490 free($3); 491 } 492 if ($5 != NULL) { 493 nat.saddr = $5->addr; 494 nat.smask = $5->mask; 495 nat.snot = $5->not; 496 free($5); 497 } 498 if ($7 != NULL) { 499 nat.daddr = $7->addr; 500 nat.dmask = $7->mask; 501 nat.dnot = $7->not; 502 free($7); 503 } 504 505 if ($9 == NULL) { 506 yyerror("nat rule requires redirection address"); 507 YYERROR; 508 } 509 nat.raddr = $9->addr; 510 free($9); 511 pfctl_add_nat(pf, &nat); 512 } 513 ; 514 515rdrrule : RDR natiface proto FROM ipspec TO ipspec dport ARROW address rport 516 { 517 struct pf_rdr rdr; 518 519 if (!natmode) { 520 yyerror("rdr rule not permitted in filter mode"); 521 YYERROR; 522 } 523 memset(&rdr, 0, sizeof(rdr)); 524 525 if ($2.string) { 526 memcpy(rdr.ifname, $2.string, 527 sizeof(rdr.ifname)); 528 rdr.ifnot = $2.not; 529 } 530 if ($3 != NULL) { 531 rdr.proto = $3->proto; 532 free($3); 533 } 534 if ($5 != NULL) { 535 rdr.saddr = $5->addr; 536 rdr.smask = $5->mask; 537 rdr.snot = $5->not; 538 free($5); 539 } 540 if ($7 != NULL) { 541 rdr.daddr = $7->addr; 542 rdr.dmask = $7->mask; 543 rdr.dnot = $7->not; 544 free($7); 545 } 546 547 rdr.dport = $8.a; 548 rdr.dport2 = $8.b; 549 rdr.opts |= $8.t; 550 551 if ($10 == NULL) { 552 yyerror("rdr rule requires redirection address"); 553 YYERROR; 554 } 555 rdr.raddr = $10->addr; 556 free($10); 557 558 rdr.rport = $11.a; 559 rdr.opts |= $11.t; 560 561 pfctl_add_rdr(pf, &rdr); 562 } 563 ; 564 565dport : PORT port { 566 $$.a = $2; 567 $$.b = $$.t = 0; 568 } 569 | PORT port ':' port { 570 $$.a = $2; 571 $$.b = $4; 572 $$.t = PF_DPORT_RANGE; 573 } 574 ; 575 576rport : PORT port { 577 $$.a = $2; 578 $$.b = $$.t = 0; 579 } 580 | PORT port ':' '*' { 581 $$.a = $2; 582 $$.b = 0; 583 $$.t = PF_RPORT_RANGE; 584 } 585 ; 586%% 587 588int 589yyerror(char *fmt, ...) 590{ 591 va_list ap; 592 extern char *infile; 593 errors = 1; 594 595 va_start(ap, fmt); 596 fprintf(stderr, "%s:%d: ", infile, yyval.lineno); 597 vfprintf(stderr, fmt, ap); 598 fprintf(stderr, "\n"); 599 va_end(ap); 600 return (0); 601} 602 603int 604rule_consistent(struct pf_rule *r) 605{ 606 int problems = 0; 607 608 if (r->action == PF_SCRUB) { 609 if (r->quick) { 610 yyerror("quick does not apply to scrub"); 611 problems++; 612 } 613 if (r->keep_state) { 614 yyerror("keep state does not apply to scrub"); 615 problems++; 616 } 617 if (r->src.port_op) { 618 yyerror("src port does not apply to scrub"); 619 problems++; 620 } 621 if (r->dst.port_op) { 622 yyerror("dst port does not apply to scrub"); 623 problems++; 624 } 625 if (r->type || r->code) { 626 yyerror("icmp-type/code does not apply to scrub"); 627 problems++; 628 } 629 } else { 630 if (r->rule_flag & PFRULE_NODF) { 631 yyerror("nodf only applies to scrub"); 632 problems++; 633 } 634 if (r->min_ttl) { 635 yyerror("min-ttl only applies to scrub"); 636 problems++; 637 } 638 } 639 if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP && 640 (r->src.port_op || r->dst.port_op)) { 641 yyerror("port only applies to tcp/udp"); 642 problems++; 643 } 644 if (r->proto != IPPROTO_ICMP && (r->type || r->code)) { 645 yyerror("icmp-type/code only applies to icmp"); 646 problems++; 647 } 648 return (-problems); 649} 650 651#define CHECK_ROOT(T,r) \ 652 do { \ 653 if (r == NULL) { \ 654 r = malloc(sizeof(T)); \ 655 memset(r, 0, sizeof(T)); \ 656 } \ 657 } while (0) 658 659#define FREE_LIST(T,r) \ 660 do { \ 661 T *p, *n = r; \ 662 while (n != NULL) { \ 663 p = n; \ 664 n = n->next; \ 665 free(p); \ 666 } \ 667 } while (0) 668 669void 670expand_rule(struct pf_rule *r, struct node_proto *protos, 671 struct node_host *src_hosts, struct node_port *src_ports, 672 struct node_host *dst_hosts, struct node_port *dst_ports) 673{ 674 struct node_proto *proto; 675 struct node_host *src_host, *dst_host; 676 struct node_port *src_port, *dst_port; 677 678 CHECK_ROOT(struct node_proto, protos); 679 CHECK_ROOT(struct node_host, src_hosts); 680 CHECK_ROOT(struct node_port, src_ports); 681 CHECK_ROOT(struct node_host, dst_hosts); 682 CHECK_ROOT(struct node_port, dst_ports); 683 684 proto = protos; 685 while (proto != NULL) { 686 src_host = src_hosts; 687 while (src_host != NULL) { 688 src_port = src_ports; 689 while (src_port != NULL) { 690 dst_host = dst_hosts; 691 while (dst_host != NULL) { 692 dst_port = dst_ports; 693 while (dst_port != NULL) { 694 r->proto = proto->proto; 695 r->src.addr = src_host->addr; 696 r->src.mask = src_host->mask; 697 r->src.not = src_host->not; 698 r->src.port[0] = src_port->port[0]; 699 r->src.port[1] = src_port->port[1]; 700 r->src.port_op = src_port->op; 701 r->dst.addr = dst_host->addr; 702 r->dst.mask = dst_host->mask; 703 r->dst.not = dst_host->not; 704 r->dst.port[0] = dst_port->port[0]; 705 r->dst.port[1] = dst_port->port[1]; 706 r->dst.port_op = dst_port->op; 707 if (rule_consistent(r) < 0) 708 yyerror("skipping rule " 709 "due to errors"); 710 else 711 pfctl_add_rule(pf, r); 712 dst_port = dst_port->next; 713 } 714 dst_host = dst_host->next; 715 } 716 src_port = src_port->next; 717 } 718 src_host = src_host->next; 719 } 720 proto = proto->next; 721 } 722 723 FREE_LIST(struct node_proto, protos); 724 FREE_LIST(struct node_host, src_hosts); 725 FREE_LIST(struct node_port, src_ports); 726 FREE_LIST(struct node_host, dst_hosts); 727 FREE_LIST(struct node_port, dst_ports); 728} 729 730#undef FREE_LIST 731#undef CHECK_ROOT 732 733int 734lookup(char *s) 735{ 736 int i; 737 struct keywords { 738 char *k_name; 739 int k_val; 740 } keywords[] = { 741 { "all", ALL}, 742 { "any", ANY}, 743 { "block", BLOCK}, 744 { "code", CODE}, 745 { "flags", FLAGS}, 746 { "from", FROM}, 747 { "icmp-type", ICMPTYPE}, 748 { "in", IN}, 749 { "keep", KEEP}, 750 { "log", LOG}, 751 { "log-all", LOGALL}, 752 { "min-ttl", MINTTL}, 753 { "nat", NAT}, 754 { "no-df", NODF}, 755 { "on", ON}, 756 { "out", OUT}, 757 { "pass", PASS}, 758 { "port", PORT}, 759 { "proto", PROTO}, 760 { "quick", QUICK}, 761 { "rdr", RDR}, 762 { "return", RETURN}, 763 { "return-icmp",RETURNICMP}, 764 { "return-rst", RETURNRST}, 765 { "scrub", SCRUB}, 766 { "state", STATE}, 767 { "to", TO}, 768 { NULL, 0 }, 769 }; 770 771 for (i = 0; keywords[i].k_name != NULL; i++) { 772 if (strcmp(s, keywords[i].k_name) == 0) { 773 if (debug > 1) 774 fprintf(stderr, "%s: %d\n", s, 775 keywords[i].k_val); 776 return (keywords[i].k_val); 777 } 778 } 779 if (debug > 1) 780 fprintf(stderr, "string: %s\n", s); 781 return (STRING); 782} 783 784char *parsebuf; 785int parseindex; 786 787int 788lgetc(FILE *fin) 789{ 790 int c, next; 791 792restart: 793 if (parsebuf) { 794 /* Reading characters from the parse buffer, instead of input */ 795 c = parsebuf[parseindex++]; 796 if (c != '\0') 797 return (c); 798 free(parsebuf); 799 parsebuf = NULL; 800 parseindex = 0; 801 goto restart; 802 } 803 804 c = getc(fin); 805 if (c == '\\') { 806 next = getc(fin); 807 if (next != '\n') { 808 ungetc(next, fin); 809 return (c); 810 } 811 yylval.lineno = lineno; 812 lineno++; 813 goto restart; 814 } 815 return (c); 816} 817 818int 819lungetc(int c, FILE *fin) 820{ 821 if (parsebuf && parseindex) { 822 /* XXX breaks on index 0 */ 823 parseindex--; 824 return (c); 825 } 826 return ungetc(c, fin); 827} 828 829int 830findeol() 831{ 832 int c; 833 834 if (parsebuf) { 835 free(parsebuf); 836 parsebuf = NULL; 837 parseindex = 0; 838 } 839 840 /* skip to either EOF or the first real EOL */ 841 while (1) { 842 c = lgetc(fin); 843 if (c == '\\') { 844 c = lgetc(fin); 845 if (c == '\n') 846 continue; 847 } 848 if (c == EOF || c == '\n') 849 break; 850 } 851 return (ERROR); 852} 853 854int 855yylex(void) 856{ 857 char buf[8096], *p, *val; 858 int endc, c, next; 859 int token; 860 861top: 862 p = buf; 863 while ((c = lgetc(fin)) == ' ' || c == '\t') 864 ; 865 866 yylval.lineno = lineno; 867 if (c == '#') 868 while ((c = lgetc(fin)) != '\n' && c != EOF) 869 ; 870 if (c == '$' && parsebuf == NULL) { 871 while (1) { 872 if ((c = lgetc(fin)) == EOF) 873 return (0); 874 if (p + 1 >= buf + sizeof(buf) - 1) { 875 yyerror("string too long"); 876 return (findeol()); 877 } 878 if (isalnum(c)) { 879 *p++ = (char)c; 880 continue; 881 } 882 *p = '\0'; 883 lungetc(c, fin); 884 break; 885 } 886 val = symget(buf); 887 if (val == NULL) 888 return (ERROR); 889 parsebuf = strdup(val); 890 parseindex = 0; 891 goto top; 892 } 893 894 switch (c) { 895 case '\'': 896 case '"': 897 endc = c; 898 while (1) { 899 if ((c = lgetc(fin)) == EOF) 900 return (0); 901 if (c == endc) { 902 *p = '\0'; 903 break; 904 } 905 if (c == '\n') 906 continue; 907 if (p + 1 >= buf + sizeof(buf) - 1) { 908 yyerror("string too long"); 909 return (findeol()); 910 } 911 *p++ = (char)c; 912 } 913 yylval.v.string = strdup(buf); 914 return (STRING); 915 case '=': 916 yylval.v.i = PF_OP_EQ; 917 return (PORTUNARY); 918 case '!': 919 next = lgetc(fin); 920 if (next == '=') { 921 yylval.v.i = PF_OP_NE; 922 return (PORTUNARY); 923 } 924 lungetc(next, fin); 925 break; 926 case '<': 927 next = lgetc(fin); 928 if (next == '>') { 929 yylval.v.i = PF_OP_XRG; 930 return (PORTBINARY); 931 } else if (next == '=') { 932 yylval.v.i = PF_OP_LE; 933 } else { 934 yylval.v.i = PF_OP_LT; 935 lungetc(next, fin); 936 } 937 return (PORTUNARY); 938 break; 939 case '>': 940 next = lgetc(fin); 941 if (next == '<') { 942 yylval.v.i = PF_OP_IRG; 943 return (PORTBINARY); 944 } else if (next == '=') { 945 yylval.v.i = PF_OP_GE; 946 } else { 947 yylval.v.i = PF_OP_GT; 948 lungetc(next, fin); 949 } 950 return (PORTUNARY); 951 break; 952 case '-': 953 next = lgetc(fin); 954 if (next == '>') 955 return (ARROW); 956 lungetc(next, fin); 957 break; 958 } 959 960 if (isdigit(c)) { 961 int index = 0, base = 10; 962 u_int64_t n = 0; 963 964 yylval.v.number = 0; 965 while (1) { 966 if (base == 10) { 967 if (!isdigit(c)) 968 break; 969 c -= '0'; 970 } else if (base == 16) { 971 if (isdigit(c)) 972 c -= '0'; 973 else if (c >= 'a' && c <= 'f') 974 c -= 'a'; 975 else if (c >= 'A' && c <= 'F') 976 c -= 'A'; 977 else 978 break; 979 } 980 n = n * base + c; 981 982 if (n > UINT_MAX) { 983 yyerror("number is too large"); 984 return (ERROR); 985 } 986 c = lgetc(fin); 987 if (c == EOF) 988 break; 989 if (index++ == 0 && n == 0 && c == 'x') { 990 base = 16; 991 c = lgetc(fin); 992 if (c == EOF) 993 break; 994 } 995 } 996 yylval.v.number = (u_int32_t)n; 997 998 if (c != EOF) 999 lungetc(c, fin); 1000 if (debug > 1) 1001 fprintf(stderr, "number: %d\n", yylval.v.number); 1002 return (NUMBER); 1003 } 1004 1005#define allowed_in_string(x) \ 1006 isalnum(x) || (ispunct(x) && x != '(' && x != ')' && x != '<' && \ 1007 x != '>' && x != '!' && x != '=' && x != '/' && x != '#' && x != ',') 1008 1009 if (isalnum(c)) { 1010 do { 1011 *p++ = c; 1012 if (p-buf >= sizeof buf) { 1013 yyerror("string too long"); 1014 return (ERROR); 1015 } 1016 } while ((c = lgetc(fin)) != EOF && (allowed_in_string(c))); 1017 lungetc(c, fin); 1018 *p = '\0'; 1019 token = lookup(buf); 1020 yylval.v.string = strdup(buf); 1021 return (token); 1022 } 1023 if (c == '\n') { 1024 yylval.lineno = lineno; 1025 lineno++; 1026 } 1027 if (c == EOF) 1028 return (0); 1029 return (c); 1030} 1031 1032int 1033parse_rules(FILE *input, struct pfctl *xpf) 1034{ 1035 natmode = 0; 1036 fin = input; 1037 pf = xpf; 1038 errors = 0; 1039 yyparse(); 1040 return (errors ? -1 : 0); 1041} 1042 1043int 1044parse_nat(FILE *input, struct pfctl *xpf) 1045{ 1046 natmode = 1; 1047 fin = input; 1048 pf = xpf; 1049 errors = 0; 1050 yyparse(); 1051 return (errors ? -1 : 0); 1052} 1053 1054u_int32_t 1055ipmask(u_int8_t b) 1056{ 1057 u_int32_t m = 0; 1058 int i; 1059 1060 for (i = 31; i > 31-b; --i) 1061 m |= (1 << i); 1062 return (htonl(m)); 1063} 1064 1065struct pf_rule_addr * 1066new_addr(void) 1067{ 1068 struct pf_rule_addr *ra; 1069 1070 ra = malloc(sizeof(struct pf_rule_addr)); 1071 if (ra == NULL) 1072 err(1, "new_addr: malloc failed"); 1073 memset(ra, 0, sizeof(*ra)); 1074 return (ra); 1075} 1076 1077/* 1078 * Over-designed efficiency is a French and German concept, so how about 1079 * we wait until they discover this ugliness and make it all fancy. 1080 */ 1081int 1082symset(char *nam, char *val) 1083{ 1084 struct sym *sym; 1085 1086 sym = calloc(1, sizeof(*sym)); 1087 if (sym == NULL) 1088 return (-1); 1089 sym->nam = strdup(nam); 1090 if (sym->nam == NULL) { 1091 free(sym); 1092 return (-1); 1093 } 1094 sym->val = strdup(val); 1095 if (sym->val == NULL) { 1096 free(sym->nam); 1097 free(sym); 1098 return (-1); 1099 } 1100 sym->next = symhead; 1101 symhead = sym; 1102 return (0); 1103} 1104 1105char * 1106symget(char *nam) 1107{ 1108 struct sym *sym; 1109 1110 for (sym = symhead; sym; sym = sym->next) 1111 if (strcmp(nam, sym->nam) == 0) 1112 return (sym->val); 1113 return (NULL); 1114} 1115