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