1 2 /* 3 * Copyright (C) 2012 by Darren Reed. 4 * 5 * See the IPFILTER.LICENCE file for details on licencing. 6 */ 7 #include <ctype.h> 8 #include "ipf.h" 9 #ifdef IPFILTER_SCAN 10 # include "netinet/ip_scan.h" 11 #endif 12 #include <sys/ioctl.h> 13 #include <syslog.h> 14 #ifdef TEST_LEXER 15 # define NO_YACC 16 union { 17 int num; 18 char *str; 19 struct in_addr ipa; 20 i6addr_t ip6; 21 } yylval; 22 #endif 23 #include "lexer.h" 24 #include "y.tab.h" 25 26 FILE *yyin; 27 28 #define ishex(c) (ISDIGIT(c) || ((c) >= 'a' && (c) <= 'f') || \ 29 ((c) >= 'A' && (c) <= 'F')) 30 #define TOOLONG -3 31 32 extern int string_start; 33 extern int string_end; 34 extern char *string_val; 35 extern int pos; 36 extern int yydebug; 37 38 char *yystr = NULL; 39 int yytext[YYBUFSIZ+1]; 40 char yychars[YYBUFSIZ+1]; 41 int yylineNum = 1; 42 int yypos = 0; 43 int yylast = -1; 44 int yydictfixed = 0; 45 int yyexpectaddr = 0; 46 int yybreakondot = 0; 47 int yyvarnext = 0; 48 int yytokentype = 0; 49 wordtab_t *yywordtab = NULL; 50 int yysavedepth = 0; 51 wordtab_t *yysavewords[30]; 52 53 54 static wordtab_t *yyfindkey(char *); 55 static int yygetc(int); 56 static void yyunputc(int); 57 static int yyswallow(int); 58 static char *yytexttostr(int, int); 59 static void yystrtotext(char *); 60 static char *yytexttochar(void); 61 62 static int 63 yygetc(int docont) 64 { 65 int c; 66 67 if (yypos < yylast) { 68 c = yytext[yypos++]; 69 if (c == '\n') 70 yylineNum++; 71 return (c); 72 } 73 74 if (yypos == YYBUFSIZ) 75 return (TOOLONG); 76 77 if (pos >= string_start && pos <= string_end) { 78 c = string_val[pos - string_start]; 79 yypos++; 80 } else { 81 c = fgetc(yyin); 82 if (docont && (c == '\\')) { 83 c = fgetc(yyin); 84 if (c == '\n') { 85 yylineNum++; 86 c = fgetc(yyin); 87 } 88 } 89 } 90 if (c == '\n') 91 yylineNum++; 92 yytext[yypos++] = c; 93 yylast = yypos; 94 yytext[yypos] = '\0'; 95 96 return (c); 97 } 98 99 100 static void 101 yyunputc(int c) 102 { 103 if (c == '\n') 104 yylineNum--; 105 yytext[--yypos] = c; 106 } 107 108 109 static int 110 yyswallow(int last) 111 { 112 int c; 113 114 while (((c = yygetc(0)) > '\0') && (c != last)) 115 ; 116 117 if (c != EOF) 118 yyunputc(c); 119 if (c == last) 120 return (0); 121 return (-1); 122 } 123 124 125 static char * 126 yytexttochar(void) 127 { 128 int i; 129 130 for (i = 0; i < yypos; i++) 131 yychars[i] = (char)(yytext[i] & 0xff); 132 yychars[i] = '\0'; 133 return (yychars); 134 } 135 136 137 static void 138 yystrtotext(char *str) 139 { 140 int len; 141 char *s; 142 143 len = strlen(str); 144 if (len > YYBUFSIZ) 145 len = YYBUFSIZ; 146 147 for (s = str; *s != '\0' && len > 0; s++, len--) 148 yytext[yylast++] = *s; 149 yytext[yylast] = '\0'; 150 } 151 152 153 static char * 154 yytexttostr(int offset, int max) 155 { 156 char *str; 157 int i; 158 159 if ((yytext[offset] == '\'' || yytext[offset] == '"') && 160 (yytext[offset] == yytext[offset + max - 1])) { 161 offset++; 162 max--; 163 } 164 165 if (max > yylast) 166 max = yylast; 167 str = malloc(max + 1); 168 if (str != NULL) { 169 for (i = offset; i < max; i++) 170 str[i - offset] = (char)(yytext[i] & 0xff); 171 str[i - offset] = '\0'; 172 } 173 return (str); 174 } 175 176 177 int 178 yylex(void) 179 { 180 static int prior = 0; 181 static int priornum = 0; 182 int c, n, isbuilding, rval, lnext, nokey = 0; 183 char *name; 184 int triedv6 = 0; 185 186 isbuilding = 0; 187 lnext = 0; 188 rval = 0; 189 190 if (yystr != NULL) { 191 free(yystr); 192 yystr = NULL; 193 } 194 195 nextchar: 196 c = yygetc(0); 197 if (yydebug > 1) 198 printf("yygetc = (%x) %c [%*.*s]\n", 199 c, c, yypos, yypos, yytexttochar()); 200 201 switch (c) 202 { 203 case '\n' : 204 lnext = 0; 205 nokey = 0; 206 case '\t' : 207 case '\r' : 208 case ' ' : 209 if (isbuilding == 1) { 210 yyunputc(c); 211 goto done; 212 } 213 if (yylast > yypos) { 214 bcopy(yytext + yypos, yytext, 215 sizeof(yytext[0]) * (yylast - yypos + 1)); 216 } 217 yylast -= yypos; 218 if (yyexpectaddr == 2) 219 yyexpectaddr = 0; 220 yypos = 0; 221 lnext = 0; 222 nokey = 0; 223 goto nextchar; 224 225 case '\\' : 226 if (lnext == 0) { 227 lnext = 1; 228 if (yylast == yypos) { 229 yylast--; 230 yypos--; 231 } else 232 yypos--; 233 if (yypos == 0) 234 nokey = 1; 235 goto nextchar; 236 } 237 break; 238 } 239 240 if (lnext == 1) { 241 lnext = 0; 242 if ((isbuilding == 0) && !ISALNUM(c)) { 243 prior = c; 244 return (c); 245 } 246 goto nextchar; 247 } 248 249 switch (c) 250 { 251 case '#' : 252 if (isbuilding == 1) { 253 yyunputc(c); 254 goto done; 255 } 256 yyswallow('\n'); 257 rval = YY_COMMENT; 258 goto done; 259 260 case '$' : 261 if (isbuilding == 1) { 262 yyunputc(c); 263 goto done; 264 } 265 n = yygetc(0); 266 if (n == '{') { 267 if (yyswallow('}') == -1) { 268 rval = -2; 269 goto done; 270 } 271 (void) yygetc(0); 272 } else { 273 if (!ISALPHA(n)) { 274 yyunputc(n); 275 break; 276 } 277 do { 278 n = yygetc(1); 279 } while (ISALPHA(n) || ISDIGIT(n) || n == '_'); 280 yyunputc(n); 281 } 282 283 name = yytexttostr(1, yypos); /* skip $ */ 284 285 if (name != NULL) { 286 string_val = get_variable(name, NULL, yylineNum); 287 free(name); 288 if (string_val != NULL) { 289 name = yytexttostr(yypos, yylast); 290 if (name != NULL) { 291 yypos = 0; 292 yylast = 0; 293 yystrtotext(string_val); 294 yystrtotext(name); 295 free(string_val); 296 free(name); 297 goto nextchar; 298 } 299 free(string_val); 300 } 301 } 302 break; 303 304 case '\'': 305 case '"' : 306 if (isbuilding == 1) { 307 goto done; 308 } 309 do { 310 n = yygetc(1); 311 if (n == EOF || n == TOOLONG) { 312 rval = -2; 313 goto done; 314 } 315 if (n == '\n') { 316 yyunputc(' '); 317 yypos++; 318 } 319 } while (n != c); 320 rval = YY_STR; 321 goto done; 322 /* NOTREACHED */ 323 324 case EOF : 325 yylineNum = 1; 326 yypos = 0; 327 yylast = -1; 328 yyexpectaddr = 0; 329 yybreakondot = 0; 330 yyvarnext = 0; 331 yytokentype = 0; 332 if (yydebug) 333 fprintf(stderr, "reset at EOF\n"); 334 prior = 0; 335 return (0); 336 } 337 338 if (strchr("=,/;{}()@", c) != NULL) { 339 if (isbuilding == 1) { 340 yyunputc(c); 341 goto done; 342 } 343 rval = c; 344 goto done; 345 } else if (c == '.') { 346 if (isbuilding == 0) { 347 rval = c; 348 goto done; 349 } 350 if (yybreakondot != 0) { 351 yyunputc(c); 352 goto done; 353 } 354 } 355 356 switch (c) 357 { 358 case '-' : 359 n = yygetc(0); 360 if (n == '>') { 361 isbuilding = 1; 362 goto done; 363 } 364 yyunputc(n); 365 if (yyexpectaddr) { 366 if (isbuilding == 1) 367 yyunputc(c); 368 else 369 rval = '-'; 370 goto done; 371 } 372 if (isbuilding == 1) 373 break; 374 rval = '-'; 375 goto done; 376 377 case '!' : 378 if (isbuilding == 1) { 379 yyunputc(c); 380 goto done; 381 } 382 n = yygetc(0); 383 if (n == '=') { 384 rval = YY_CMP_NE; 385 goto done; 386 } 387 yyunputc(n); 388 rval = '!'; 389 goto done; 390 391 case '<' : 392 if (yyexpectaddr) 393 break; 394 if (isbuilding == 1) { 395 yyunputc(c); 396 goto done; 397 } 398 n = yygetc(0); 399 if (n == '=') { 400 rval = YY_CMP_LE; 401 goto done; 402 } 403 if (n == '>') { 404 rval = YY_RANGE_OUT; 405 goto done; 406 } 407 yyunputc(n); 408 rval = YY_CMP_LT; 409 goto done; 410 411 case '>' : 412 if (yyexpectaddr) 413 break; 414 if (isbuilding == 1) { 415 yyunputc(c); 416 goto done; 417 } 418 n = yygetc(0); 419 if (n == '=') { 420 rval = YY_CMP_GE; 421 goto done; 422 } 423 if (n == '<') { 424 rval = YY_RANGE_IN; 425 goto done; 426 } 427 yyunputc(n); 428 rval = YY_CMP_GT; 429 goto done; 430 } 431 432 /* 433 * Now for the reason this is here...IPv6 address parsing. 434 * The longest string we can expect is of this form: 435 * 0000:0000:0000:0000:0000:0000:000.000.000.000 436 * not: 437 * 0000:0000:0000:0000:0000:0000:0000:0000 438 */ 439 #ifdef USE_INET6 440 if (yyexpectaddr != 0 && isbuilding == 0 && 441 (ishex(c) || isdigit(c) || c == ':')) { 442 char ipv6buf[45 + 1], *s, oc; 443 int start; 444 445 buildipv6: 446 start = yypos; 447 s = ipv6buf; 448 oc = c; 449 450 if (prior == YY_NUMBER && c == ':') { 451 snprintf(s, sizeof(s), "%d", priornum); 452 s += strlen(s); 453 } 454 455 /* 456 * Perhaps we should implement stricter controls on what we 457 * swallow up here, but surely it would just be duplicating 458 * the code in inet_pton() anyway. 459 */ 460 do { 461 *s++ = c; 462 c = yygetc(1); 463 } while ((ishex(c) || c == ':' || c == '.') && 464 (s - ipv6buf < 46)); 465 yyunputc(c); 466 *s = '\0'; 467 468 if (inet_pton(AF_INET6, ipv6buf, &yylval.ip6) == 1) { 469 rval = YY_IPV6; 470 yyexpectaddr = 0; 471 goto done; 472 } 473 yypos = start; 474 c = oc; 475 } 476 #endif 477 478 if ((c == ':') && (rval != YY_IPV6) && (triedv6 == 0)) { 479 #ifdef USE_INET6 480 yystr = yytexttostr(0, yypos - 1); 481 if (yystr != NULL) { 482 char *s; 483 484 for (s = yystr; *s && ishex(*s); s++) 485 ; 486 if (!*s && *yystr) { 487 isbuilding = 0; 488 c = *yystr; 489 free(yystr); 490 triedv6 = 1; 491 yypos = 1; 492 goto buildipv6; 493 } 494 free(yystr); 495 } 496 #endif 497 if (isbuilding == 1) { 498 yyunputc(c); 499 goto done; 500 } 501 rval = ':'; 502 goto done; 503 } 504 505 if (isbuilding == 0 && c == '0') { 506 n = yygetc(0); 507 if (n == 'x') { 508 do { 509 n = yygetc(1); 510 } while (ishex(n)); 511 yyunputc(n); 512 rval = YY_HEX; 513 goto done; 514 } 515 yyunputc(n); 516 } 517 518 /* 519 * No negative numbers with leading - sign.. 520 */ 521 if (isbuilding == 0 && ISDIGIT(c)) { 522 do { 523 n = yygetc(1); 524 } while (ISDIGIT(n)); 525 yyunputc(n); 526 rval = YY_NUMBER; 527 goto done; 528 } 529 530 isbuilding = 1; 531 goto nextchar; 532 533 done: 534 yystr = yytexttostr(0, yypos); 535 536 if (yydebug) 537 printf("isbuilding %d yyvarnext %d nokey %d fixed %d addr %d\n", 538 isbuilding, yyvarnext, nokey, yydictfixed, yyexpectaddr); 539 if (isbuilding == 1) { 540 wordtab_t *w; 541 542 w = NULL; 543 isbuilding = 0; 544 545 if ((yyvarnext == 0) && (nokey == 0)) { 546 w = yyfindkey(yystr); 547 if (w == NULL && yywordtab != NULL && !yydictfixed) { 548 yyresetdict(); 549 w = yyfindkey(yystr); 550 } 551 } else 552 yyvarnext = 0; 553 if (w != NULL) 554 rval = w->w_value; 555 else 556 rval = YY_STR; 557 } 558 559 if (rval == YY_STR) { 560 if (yysavedepth > 0 && !yydictfixed) 561 yyresetdict(); 562 if (yyexpectaddr != 0) 563 yyexpectaddr = 0; 564 } 565 566 yytokentype = rval; 567 568 if (yydebug) 569 printf("lexed(%s) %d,%d,%d [%d,%d,%d] => %d @%d\n", 570 yystr, isbuilding, yyexpectaddr, yysavedepth, 571 string_start, string_end, pos, rval, yysavedepth); 572 573 switch (rval) 574 { 575 case YY_NUMBER : 576 sscanf(yystr, "%u", &yylval.num); 577 break; 578 579 case YY_HEX : 580 sscanf(yystr, "0x%x", (u_int *)&yylval.num); 581 break; 582 583 case YY_STR : 584 yylval.str = strdup(yystr); 585 break; 586 587 default : 588 break; 589 } 590 591 if (yylast > 0) { 592 bcopy(yytext + yypos, yytext, 593 sizeof(yytext[0]) * (yylast - yypos + 1)); 594 yylast -= yypos; 595 yypos = 0; 596 } 597 598 if (rval == YY_NUMBER) 599 priornum = yylval.num; 600 prior = rval; 601 return (rval); 602 } 603 604 605 static wordtab_t *yyfindkey(char *key) 606 { 607 wordtab_t *w; 608 609 if (yywordtab == NULL) 610 return (NULL); 611 612 for (w = yywordtab; w->w_word != 0; w++) 613 if (strcasecmp(key, w->w_word) == 0) 614 return (w); 615 return (NULL); 616 } 617 618 619 char * 620 yykeytostr(int num) 621 { 622 wordtab_t *w; 623 624 if (yywordtab == NULL) 625 return ("<unknown>"); 626 627 for (w = yywordtab; w->w_word; w++) 628 if (w->w_value == num) 629 return (w->w_word); 630 return ("<unknown>"); 631 } 632 633 634 wordtab_t * 635 yysettab(wordtab_t *words) 636 { 637 wordtab_t *save; 638 639 save = yywordtab; 640 yywordtab = words; 641 return (save); 642 } 643 644 645 void 646 yyerror(char *msg) 647 { 648 char *txt, letter[2]; 649 int freetxt = 0; 650 651 if (yytokentype < 256) { 652 letter[0] = yytokentype; 653 letter[1] = '\0'; 654 txt = letter; 655 } else if (yytokentype == YY_STR || yytokentype == YY_HEX || 656 yytokentype == YY_NUMBER) { 657 if (yystr == NULL) { 658 txt = yytexttostr(yypos, YYBUFSIZ); 659 freetxt = 1; 660 } else 661 txt = yystr; 662 } else { 663 txt = yykeytostr(yytokentype); 664 } 665 fprintf(stderr, "%s error at \"%s\", line %d\n", msg, txt, yylineNum); 666 if (freetxt == 1) 667 free(txt); 668 exit(1); 669 } 670 671 672 void 673 yysetfixeddict(wordtab_t *newdict) 674 { 675 if (yydebug) 676 printf("yysetfixeddict(%lx)\n", (u_long)newdict); 677 678 if (yysavedepth == sizeof(yysavewords)/sizeof(yysavewords[0])) { 679 fprintf(stderr, "%d: at maximum dictionary depth\n", 680 yylineNum); 681 return; 682 } 683 684 yysavewords[yysavedepth++] = yysettab(newdict); 685 if (yydebug) 686 printf("yysavedepth++ => %d\n", yysavedepth); 687 yydictfixed = 1; 688 } 689 690 691 void 692 yysetdict(wordtab_t *newdict) 693 { 694 if (yydebug) 695 printf("yysetdict(%lx)\n", (u_long)newdict); 696 697 if (yysavedepth == sizeof(yysavewords)/sizeof(yysavewords[0])) { 698 fprintf(stderr, "%d: at maximum dictionary depth\n", 699 yylineNum); 700 return; 701 } 702 703 yysavewords[yysavedepth++] = yysettab(newdict); 704 if (yydebug) 705 printf("yysavedepth++ => %d\n", yysavedepth); 706 } 707 708 void 709 yyresetdict(void) 710 { 711 if (yydebug) 712 printf("yyresetdict(%d)\n", yysavedepth); 713 if (yysavedepth > 0) { 714 yysettab(yysavewords[--yysavedepth]); 715 if (yydebug) 716 printf("yysavedepth-- => %d\n", yysavedepth); 717 } 718 yydictfixed = 0; 719 } 720 721 722 723 #ifdef TEST_LEXER 724 int 725 main(int argc, char *argv[]) 726 { 727 int n; 728 729 yyin = stdin; 730 731 while ((n = yylex()) != 0) 732 printf("%d.n = %d [%s] %d %d\n", 733 yylineNum, n, yystr, yypos, yylast); 734 } 735 #endif 736