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