parse.y revision 1.20
1/* $OpenBSD: parse.y,v 1.20 2001/08/19 16:16:41 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 <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 87typedef struct { 88 union { 89 u_int32_t number; 90 int i; 91 char *string; 92 struct { 93 char *string; 94 int not; 95 } iface; 96 struct { 97 u_int8_t b1; 98 u_int8_t b2; 99 u_int16_t w; 100 } b; 101 struct { 102 int a; 103 int b; 104 int t; 105 } range; 106 struct node_proto *proto; 107 struct node_host *host; 108 struct node_port *port; 109 struct peer peer; 110 struct { 111 struct peer src, dst; 112 } fromto; 113 } v; 114 int lineno; 115} YYSTYPE; 116 117%} 118 119%token PASS BLOCK SCRUB RETURN IN OUT LOG LOGALL QUICK ON FROM TO FLAGS 120%token RETURNRST RETURNICMP PROTO ALL ANY ICMPTYPE CODE KEEP STATE PORT 121%token RDR NAT ARROW NODF MINTTL ERROR 122%token <v.string> STRING 123%token <v.number> NUMBER 124%token <v.i> PORTUNARY PORTBINARY 125%type <v.iface> iface natiface 126%type <v.number> port icmptype minttl 127%type <v.i> direction log quick keep nodf 128%type <v.b> action icmpspec flag flags blockspec 129%type <v.range> dport rport 130%type <v.proto> proto proto_list proto_item 131%type <v.fromto> fromto 132%type <v.peer> ipportspec 133%type <v.host> ipspec host address host_list 134%type <v.port> portspec port_list port_item 135%% 136 137ruleset: /* empty */ 138 | ruleset '\n' 139 | ruleset pfrule '\n' 140 | ruleset natrule '\n' 141 | ruleset rdrrule '\n' 142 | ruleset error '\n' { errors++; } 143 ; 144 145pfrule: action direction log quick iface proto fromto flags icmpspec keep nodf minttl 146 { 147 struct pf_rule r; 148 149 if (natmode) { 150 yyerror("filter rule not permitted in nat mode"); 151 YYERROR; 152 } 153 memset(&r, 0, sizeof(r)); 154 155 r.action = $1.b1; 156 if ($1.b2) 157 r.rule_flag |= PFRULE_RETURNRST; 158 else 159 r.return_icmp = $1.w; 160 r.direction = $2; 161 r.log = $3; 162 r.quick = $4; 163 if ($5.string) 164 memcpy(r.ifname, $5.string, sizeof(r.ifname)); 165 166 r.flags = $8.b1; 167 r.flagset = $8.b2; 168 r.type = $9.b1; 169 r.code = $9.b2; 170 r.keep_state = $10; 171 172 if ($11) 173 r.rule_flag |= PFRULE_NODF; 174 if ($12) 175 r.min_ttl = $12; 176 177 expand_rule(&r, $6, $7.src.host, $7.src.port, 178 $7.dst.host, $7.dst.port); 179 } 180 ; 181 182action: PASS { $$.b1 = PF_PASS; } 183 | BLOCK blockspec { $$ = $2; $$.b1 = PF_DROP; } 184 | SCRUB { $$.b1 = PF_SCRUB; } 185 ; 186 187blockspec: { $$.b2 = 0; $$.w = 0; } 188 | RETURNRST { $$.b2 = 1; $$.w = 0;} 189 | RETURNICMP { 190 $$.b2 = 0; 191 $$.w = (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT; 192 } 193 | RETURNICMP '(' STRING ')' { 194 struct icmpcodeent *p; 195 196 if ((p = geticmpcodebyname(ICMP_UNREACH, $3)) == NULL) { 197 yyerror("unknown icmp code %s", $3); 198 YYERROR; 199 } 200 $$.w = (p->type << 8) | p->code; 201 $$.b2 = 0; 202 } 203 ; 204 205direction: IN { $$ = PF_IN; } 206 | OUT { $$ = PF_OUT; } 207 ; 208 209log: { $$ = 0; } 210 | LOG { $$ = 1; } 211 | LOGALL { $$ = 2; } 212 ; 213 214quick: { $$ = 0; } 215 | QUICK { $$ = 1; } 216 ; 217 218natiface: iface 219 | ON '!' STRING { 220 $$.string = strdup($3); $$.not = 1; 221 } 222 ; 223iface: { $$.string = NULL; } 224 | ON STRING { $$.string = strdup($2); } 225 ; 226 227proto: { $$ = NULL; } 228 | PROTO proto_item { $$ = $2; } 229 | PROTO '{' proto_list '}' { $$ = $3; } 230 ; 231 232proto_list: proto_item { $$ = $1; } 233 | proto_list ',' proto_item { $3->next = $1; $$ = $3; } 234 ; 235 236proto_item: NUMBER { 237 struct protoent *p; 238 239 if ((p = getprotobynumber($1)) == NULL) { 240 yyerror("unknown protocol %d", $1); 241 YYERROR; 242 } 243 $$ = malloc(sizeof(struct node_proto)); 244 $$->proto = p->p_proto; 245 $$->next = NULL; 246 } 247 | STRING { 248 struct protoent *p; 249 250 if ((p = getprotobyname($1)) == NULL) { 251 yyerror("unknown protocol %s", $1); 252 YYERROR; 253 } 254 $$ = malloc(sizeof(struct node_proto)); 255 $$->proto = p->p_proto; 256 $$->next = NULL; 257 } 258 ; 259 260fromto: ALL { 261 $$.src.host = NULL; 262 $$.src.port = NULL; 263 $$.dst.host = NULL; 264 $$.dst.port = NULL; 265 } 266 | FROM ipportspec TO ipportspec { 267 $$.src = $2; 268 $$.dst = $4; 269 } 270 ; 271 272ipportspec: ipspec { $$.host = $1; $$.port = NULL; } 273 | ipspec PORT portspec { 274 $$.host = $1; 275 $$.port = $3; 276 } 277 ; 278 279ipspec: ANY { $$ = NULL; } 280 | '!' host { $$ = $2; $$->not = 1; } 281 | host { $$ = $1; $$->not = 0; } 282 | '{' host_list '}' { $$ = $2; } 283 ; 284 285host_list: host { $$ = $1; } 286 | host_list ',' host { $3->next = $1; $$ = $3; } 287 288host: address { 289 $$ = $1; 290 $$->mask = 0xffffffff; 291 } 292 | address '/' NUMBER { 293 if ($3 < 0 || $3 > 32) { 294 yyerror("illegal netmask value %d", $3); 295 YYERROR; 296 } 297 $$ = $1; 298 $$->mask = ipmask($3); 299 } 300 ; 301 302address: STRING { 303 struct hostent *hp; 304 305 if ((hp = gethostbyname($1)) == NULL) { 306 yyerror("cannot resolve %s", $1); 307 YYERROR; 308 } 309 $$ = malloc(sizeof(struct node_host)); 310 memcpy(&$$->addr, hp->h_addr, sizeof(u_int32_t)); 311 } 312 | NUMBER '.' NUMBER '.' NUMBER '.' NUMBER { 313 if ($1 < 0 || $3 < 0 || $5 < 0 || $7 < 0 || 314 $1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) { 315 yyerror("illegal ip address %d.%d.%d.%d", 316 $1, $3, $5, $7); 317 YYERROR; 318 } 319 $$ = malloc(sizeof(struct node_host)); 320 $$->addr = htonl(($1 << 24) | ($3 << 16) | ($5 << 8) | $7); 321 } 322 ; 323 324portspec: port_item { $$ = $1; } 325 | '{' port_list '}' { $$ = $2; } 326 ; 327 328port_list: port_item { $$ = $1; } 329 | port_list ',' port_item { $3->next = $1; $$ = $3; } 330 ; 331 332port_item: port { 333 $$ = malloc(sizeof(struct node_port)); 334 $$->port[0] = $1; 335 $$->port[1] = $1; 336 $$->op = PF_OP_EQ; 337 } 338 | PORTUNARY port { 339 $$ = malloc(sizeof(struct node_port)); 340 $$->port[0] = $2; 341 $$->port[1] = $2; 342 $$->op = $1; 343 } 344 | port PORTBINARY port { 345 $$ = malloc(sizeof(struct node_port)); 346 $$->port[0] = $1; 347 $$->port[1] = $3; 348 $$->op = $2; 349 } 350 ; 351 352port: NUMBER { 353 if (0 > $1 || $1 > 65535) { 354 yyerror("illegal port value %d", $1); 355 YYERROR; 356 } 357 $$ = htons($1); 358 } 359 | STRING { 360 struct servent *s = NULL; 361 362 s = getservbyname($1, "tcp"); 363 if (s == NULL) 364 s = getservbyname($1, "udp"); 365 if (s == NULL) { 366 yyerror("unknown protocol %s", $1); 367 YYERROR; 368 } 369 $$ = s->s_port; 370 } 371 ; 372 373flag: STRING { 374 int f; 375 376 if ((f = parse_flags($1)) < 0) { 377 yyerror("bad flags %s", $1); 378 YYERROR; 379 } 380 $$.b1 = f; 381 } 382 ; 383 384flags: { $$.b1 = 0; $$.b2 = 0; } 385 | FLAGS flag { $$.b1 = $2.b1; $$.b2 = 63; } 386 | FLAGS flag "/" flag { $$.b1 = $2.b1; $$.b2 = $4.b1; } 387 | FLAGS "/" flag { $$.b1 = 0; $$.b2 = $3.b1; } 388 ; 389 390icmpspec: { $$.b1 = 0; $$.b2 = 0; } 391 | ICMPTYPE icmptype { $$.b1 = $2; $$.b2 = 0; } 392 | ICMPTYPE icmptype CODE NUMBER { 393 if ($4 < 0 || $4 > 255) { 394 yyerror("illegal icmp code %d", $4); 395 YYERROR; 396 } 397 $$.b1 = $2; 398 $$.b2 = $4 + 1; 399 } 400 | ICMPTYPE icmptype CODE STRING { 401 struct icmpcodeent *p; 402 403 $$.b1 = $2; 404 if ((p = geticmpcodebyname($2, $4)) == NULL) { 405 yyerror("unknown icmp-code %s", $4); 406 YYERROR; 407 } 408 $$.b2 = p->code + 1; 409 } 410 ; 411 412icmptype: STRING { 413 struct icmptypeent *p; 414 415 if ((p = geticmptypebyname($1)) == NULL) { 416 yyerror("unknown icmp-type %s", $1); 417 YYERROR; 418 } 419 $$ = p->type + 1; 420 } 421 | NUMBER { 422 if ($1 < 0 || $1 > 255) { 423 yyerror("illegal icmp type %d", $1); 424 YYERROR; 425 } 426 $$ = $1 + 1; 427 } 428 ; 429 430 431keep: { $$ = 0; } 432 | KEEP STATE { $$ = 1; } 433 ; 434 435minttl: { $$ = 0; } 436 | MINTTL NUMBER { 437 if ($2 < 0 || $2 > 255) { 438 yyerror("illegal min-ttl value %d", $2); 439 YYERROR; 440 } 441 $$ = $2; 442 } 443 ; 444 445nodf: { $$ = 0; } 446 | NODF { $$ = 1; } 447 ; 448 449natrule: NAT natiface proto FROM ipspec TO ipspec ARROW address 450 { 451 struct pf_nat nat; 452 453 if (!natmode) { 454 yyerror("nat rule not permitted in filter mode"); 455 YYERROR; 456 } 457 458 memset(&nat, 0, sizeof(nat)); 459 460 if ($2.string) { 461 memcpy(nat.ifname, $2.string, 462 sizeof(nat.ifname)); 463 nat.ifnot = $2.not; 464 } 465 if ($3 != NULL) { 466 nat.proto = $3->proto; 467 free($3); 468 } 469 if ($5 != NULL) { 470 nat.saddr = $5->addr; 471 nat.smask = $5->mask; 472 nat.snot = $5->not; 473 free($5); 474 } 475 if ($7 != NULL) { 476 nat.daddr = $7->addr; 477 nat.dmask = $7->mask; 478 nat.dnot = $7->not; 479 free($7); 480 } 481 482 if ($9 == NULL) { 483 yyerror("nat rule requires redirection address"); 484 YYERROR; 485 } 486 nat.raddr = $9->addr; 487 free($9); 488 489 pfctl_add_nat(pf, &nat); 490 } 491 ; 492 493rdrrule: RDR natiface proto FROM ipspec TO ipspec dport ARROW address rport 494 { 495 struct pf_rdr rdr; 496 497 if (!natmode) { 498 yyerror("rdr rule not permitted in filter mode"); 499 YYERROR; 500 } 501 502 memset(&rdr, 0, sizeof(rdr)); 503 504 if ($2.string) { 505 memcpy(rdr.ifname, $2.string, 506 sizeof(rdr.ifname)); 507 rdr.ifnot = $2.not; 508 } 509 if ($3 != NULL) { 510 rdr.proto = $3->proto; 511 free($3); 512 } 513 if ($5 != NULL) { 514 rdr.saddr = $5->addr; 515 rdr.smask = $5->mask; 516 rdr.snot = $5->not; 517 free($5); 518 } 519 if ($7 != NULL) { 520 rdr.daddr = $7->addr; 521 rdr.dmask = $7->mask; 522 rdr.dnot = $7->not; 523 free($7); 524 } 525 526 rdr.dport = $8.a; 527 rdr.dport2 = $8.b; 528 rdr.opts |= $8.t; 529 530 if ($10 == NULL) { 531 yyerror("rdr rule requires redirection address"); 532 YYERROR; 533 } 534 rdr.raddr = $10->addr; 535 free($10); 536 537 rdr.rport = $11.a; 538 rdr.opts |= $11.t; 539 540 pfctl_add_rdr(pf, &rdr); 541 } 542 ; 543 544dport: PORT port { 545 $$.a = $2; 546 $$.b = $$.t = 0; 547 } 548 | PORT port ':' port { 549 $$.a = $2; 550 $$.b = $4; 551 $$.t = PF_DPORT_RANGE; 552 } 553 ; 554 555rport: PORT port { 556 $$.a = $2; 557 $$.b = $$.t = 0; 558 } 559 | PORT port ':' '*' { 560 $$.a = $2; 561 $$.b = 0; 562 $$.t = PF_RPORT_RANGE; 563 } 564 ; 565 566%% 567 568int 569yyerror(char *fmt, ...) 570{ 571 va_list ap; 572 extern char *infile; 573 errors = 1; 574 575 va_start(ap, fmt); 576 fprintf(stderr, "%s:%d: ", infile, yyval.lineno); 577 vfprintf(stderr, fmt, ap); 578 fprintf(stderr, "\n"); 579 va_end(ap); 580 return (0); 581} 582 583int 584rule_consistent(struct pf_rule *r) 585{ 586 int problems = 0; 587 588 if (r->action == PF_SCRUB) { 589 if (r->quick) { 590 yyerror("quick does not apply to scrub"); 591 problems++; 592 } 593 if (r->keep_state) { 594 yyerror("keep state does not apply to scrub"); 595 problems++; 596 } 597 if (r->src.port_op) { 598 yyerror("src port does not apply to scrub"); 599 problems++; 600 } 601 if (r->dst.port_op) { 602 yyerror("dst port does not apply to scrub"); 603 problems++; 604 } 605 if (r->type || r->code) { 606 yyerror("icmp-type/code does not apply to scrub"); 607 problems++; 608 } 609 } else { 610 if (r->rule_flag & PFRULE_NODF) { 611 yyerror("nodf only applies to scrub"); 612 problems++; 613 } 614 if (r->min_ttl) { 615 yyerror("min-ttl only applies to scrub"); 616 problems++; 617 } 618 } 619 if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP && 620 (r->src.port_op || r->dst.port_op)) { 621 yyerror("port only applies to tcp/udp"); 622 problems++; 623 } 624 if (r->proto != IPPROTO_ICMP && (r->type || r->code)) { 625 yyerror("icmp-type/code only applies to icmp"); 626 problems++; 627 } 628 return (-problems); 629} 630 631#define CHECK_ROOT(T,r) \ 632 do { \ 633 if (r == NULL) { \ 634 r = malloc(sizeof(T)); \ 635 memset(r, 0, sizeof(T)); \ 636 } \ 637 } while (0) 638 639#define FREE_LIST(T,r) \ 640 do { \ 641 T *p, *n = r; \ 642 while (n != NULL) { \ 643 p = n; \ 644 n = n->next; \ 645 free(p); \ 646 } \ 647 } while (0) 648 649void 650expand_rule(struct pf_rule *r, struct node_proto *protos, 651 struct node_host *src_hosts, struct node_port *src_ports, 652 struct node_host *dst_hosts, struct node_port *dst_ports) 653{ 654 struct node_proto *proto; 655 struct node_host *src_host, *dst_host; 656 struct node_port *src_port, *dst_port; 657 658 CHECK_ROOT(struct node_proto, protos); 659 CHECK_ROOT(struct node_host, src_hosts); 660 CHECK_ROOT(struct node_port, src_ports); 661 CHECK_ROOT(struct node_host, dst_hosts); 662 CHECK_ROOT(struct node_port, dst_ports); 663 664 proto = protos; 665 while (proto != NULL) { 666 src_host = src_hosts; 667 while (src_host != NULL) { 668 src_port = src_ports; 669 while (src_port != NULL) { 670 dst_host = dst_hosts; 671 while (dst_host != NULL) { 672 dst_port = dst_ports; 673 while (dst_port != NULL) { 674 r->proto = proto->proto; 675 r->src.addr = src_host->addr; 676 r->src.mask = src_host->mask; 677 r->src.not = src_host->not; 678 r->src.port[0] = src_port->port[0]; 679 r->src.port[1] = src_port->port[1]; 680 r->src.port_op = src_port->op; 681 r->dst.addr = dst_host->addr; 682 r->dst.mask = dst_host->mask; 683 r->dst.not = dst_host->not; 684 r->dst.port[0] = dst_port->port[0]; 685 r->dst.port[1] = dst_port->port[1]; 686 r->dst.port_op = dst_port->op; 687 if (rule_consistent(r) < 0) 688 yyerror("skipping rule " 689 "due to errors"); 690 else 691 pfctl_add_rule(pf, r); 692 dst_port = dst_port->next; 693 } 694 dst_host = dst_host->next; 695 } 696 src_port = src_port->next; 697 } 698 src_host = src_host->next; 699 } 700 proto = proto->next; 701 } 702 703 FREE_LIST(struct node_proto, protos); 704 FREE_LIST(struct node_host, src_hosts); 705 FREE_LIST(struct node_port, src_ports); 706 FREE_LIST(struct node_host, dst_hosts); 707 FREE_LIST(struct node_port, dst_ports); 708} 709 710#undef FREE_LIST 711#undef CHECK_ROOT 712 713int 714lookup(char *s) 715{ 716 int i; 717 struct keywords { 718 char *k_name; 719 int k_val; 720 } keywords[] = { 721 { "all", ALL}, 722 { "any", ANY}, 723 { "block", BLOCK}, 724 { "code", CODE}, 725 { "flags", FLAGS}, 726 { "from", FROM}, 727 { "icmp-type", ICMPTYPE}, 728 { "in", IN}, 729 { "keep", KEEP}, 730 { "log", LOG}, 731 { "log-all", LOGALL}, 732 { "min-ttl", MINTTL}, 733 { "nat", NAT}, 734 { "no-df", NODF}, 735 { "on", ON}, 736 { "out", OUT}, 737 { "pass", PASS}, 738 { "port", PORT}, 739 { "proto", PROTO}, 740 { "quick", QUICK}, 741 { "rdr", RDR}, 742 { "return", RETURN}, 743 { "return-icmp",RETURNICMP}, 744 { "return-rst", RETURNRST}, 745 { "scrub", SCRUB}, 746 { "state", STATE}, 747 { "to", TO}, 748 { NULL, 0 }, 749 }; 750 751 for (i = 0; keywords[i].k_name != NULL; i++) { 752 if (strcmp(s, keywords[i].k_name) == 0) { 753 if (debug > 1) 754 fprintf(stderr, "%s: %d\n", s, 755 keywords[i].k_val); 756 return (keywords[i].k_val); 757 } 758 } 759 if (debug > 1) 760 fprintf(stderr, "string: %s\n", s); 761 return (STRING); 762} 763 764int 765lgetc(FILE *fin) 766{ 767 int c, next; 768 769restart: 770 c = getc(fin); 771 if (c == '\\') { 772 next = getc(fin); 773 if (next != '\n') { 774 ungetc(next, fin); 775 return (c); 776 } 777 yylval.lineno = lineno; 778 lineno++; 779 goto restart; 780 } 781 return (c); 782} 783 784int 785yylex(void) 786{ 787 char *p, buf[8096]; 788 int c, next; 789 int token; 790 791 while ((c = lgetc(fin)) == ' ' || c == '\t') 792 ; 793 794 yylval.lineno = lineno; 795 if (c == '#') 796 while ((c = lgetc(fin)) != '\n' && c != EOF) 797 ; 798 if (c == '-') { 799 next = lgetc(fin); 800 if (next == '>') 801 return (ARROW); 802 ungetc(next, fin); 803 } 804 switch (c) { 805 case '=': 806 yylval.v.i = PF_OP_EQ; 807 return (PORTUNARY); 808 case '!': 809 next = lgetc(fin); 810 if (next == '=') { 811 yylval.v.i = PF_OP_NE; 812 return (PORTUNARY); 813 } 814 ungetc(next, fin); 815 break; 816 case '<': 817 next = lgetc(fin); 818 if (next == '>') { 819 yylval.v.i = PF_OP_XRG; 820 return (PORTBINARY); 821 } else if (next == '=') { 822 yylval.v.i = PF_OP_LE; 823 } else { 824 yylval.v.i = PF_OP_LT; 825 ungetc(next, fin); 826 } 827 return (PORTUNARY); 828 break; 829 case '>': 830 next = lgetc(fin); 831 if (next == '<') { 832 yylval.v.i = PF_OP_IRG; 833 return (PORTBINARY); 834 } else if (next == '=') { 835 yylval.v.i = PF_OP_GE; 836 } else { 837 yylval.v.i = PF_OP_GT; 838 ungetc(next, fin); 839 } 840 return (PORTUNARY); 841 break; 842 } 843 if (isdigit(c)) { 844 yylval.v.number = 0; 845 do { 846 u_int64_t n = (u_int64_t)yylval.v.number * 10 + c - '0'; 847 if (n > 0xffffffff) { 848 yyerror("number is too large"); 849 return (ERROR); 850 } 851 yylval.v.number = (u_int32_t)n; 852 } while ((c = lgetc(fin)) != EOF && isdigit(c)); 853 ungetc(c, fin); 854 if (debug > 1) 855 fprintf(stderr, "number: %d\n", yylval.v.number); 856 return (NUMBER); 857 } 858 859#define allowed_in_string(x) \ 860 isalnum(x) || (ispunct(x) && x != '(' && x != ')' && x != '<' \ 861 && x != '>' && x != '!' && x != '=' && x != '/' && x != '#' && x != ',') 862 863 if (isalnum(c)) { 864 p = buf; 865 do { 866 *p++ = c; 867 if (p-buf >= sizeof buf) { 868 yyerror("string too long"); 869 return (ERROR); 870 } 871 } while ((c = lgetc(fin)) != EOF && (allowed_in_string(c))); 872 ungetc(c, fin); 873 *p = '\0'; 874 token = lookup(buf); 875 yylval.v.string = strdup(buf); 876 return (token); 877 } 878 if (c == '\n') { 879 yylval.lineno = lineno; 880 lineno++; 881 } 882 if (c == EOF) 883 return (0); 884 return (c); 885} 886 887int 888parse_rules(FILE *input, struct pfctl *xpf) 889{ 890 natmode = 0; 891 fin = input; 892 pf = xpf; 893 errors = 0; 894 yyparse(); 895 return (errors ? -1 : 0); 896} 897 898int 899parse_nat(FILE *input, struct pfctl *xpf) 900{ 901 natmode = 1; 902 fin = input; 903 pf = xpf; 904 errors = 0; 905 yyparse(); 906 return (errors ? -1 : 0); 907} 908 909u_int32_t 910ipmask(u_int8_t b) 911{ 912 u_int32_t m = 0; 913 int i; 914 915 for (i = 31; i > 31-b; --i) 916 m |= (1 << i); 917 return (htonl(m)); 918} 919 920struct pf_rule_addr * 921new_addr(void) 922{ 923 struct pf_rule_addr *ra; 924 925 ra = malloc(sizeof(struct pf_rule_addr)); 926 if (ra == NULL) 927 err(1, "new_addr: malloc failed"); 928 memset(ra, 0, sizeof(*ra)); 929 return (ra); 930} 931