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 case '\t' : 204 case '\r' : 205 case ' ' : 206 if (isbuilding == 1) { 207 yyunputc(c); 208 goto done; 209 } 210 if (yylast > yypos) { 211 bcopy(yytext + yypos, yytext, 212 sizeof(yytext[0]) * (yylast - yypos + 1)); 213 } 214 yylast -= yypos; 215 yypos = 0; 216 lnext = 0; 217 nokey = 0; 218 goto nextchar; 219 220 case '\\' : 221 if (lnext == 0) { 222 lnext = 1; 223 if (yylast == yypos) { 224 yylast--; 225 yypos--; 226 } else 227 yypos--; 228 if (yypos == 0) 229 nokey = 1; 230 goto nextchar; 231 } 232 break; 233 } 234 235 if (lnext == 1) { 236 lnext = 0; 237 if ((isbuilding == 0) && !ISALNUM(c)) { 238 return c; 239 } 240 goto nextchar; 241 } 242 243 switch (c) 244 { 245 case '#' : 246 if (isbuilding == 1) { 247 yyunputc(c); 248 goto done; 249 } 250 yyswallow('\n'); 251 rval = YY_COMMENT; 252 goto done; 253 254 case '$' : 255 if (isbuilding == 1) { 256 yyunputc(c); 257 goto done; 258 } 259 n = yygetc(0); 260 if (n == '{') { 261 if (yyswallow('}') == -1) { 262 rval = -2; 263 goto done; 264 } 265 (void) yygetc(0); 266 } else { 267 if (!ISALPHA(n)) { 268 yyunputc(n); 269 break; 270 } 271 do { 272 n = yygetc(1); 273 } while (ISALPHA(n) || ISDIGIT(n) || n == '_'); 274 yyunputc(n); 275 } 276 277 name = yytexttostr(1, yypos); /* skip $ */ 278 279 if (name != NULL) { 280 string_val = get_variable(name, NULL, yylineNum); 281 free(name); 282 if (string_val != NULL) { 283 name = yytexttostr(yypos, yylast); 284 if (name != NULL) { 285 yypos = 0; 286 yylast = 0; 287 yystrtotext(string_val); 288 yystrtotext(name); 289 free(string_val); 290 free(name); 291 goto nextchar; 292 } 293 free(string_val); 294 } 295 } 296 break; 297 298 case '\'': 299 case '"' : 300 if (isbuilding == 1) { 301 goto done; 302 } 303 do { 304 n = yygetc(1); 305 if (n == EOF || n == TOOLONG) { 306 rval = -2; 307 goto done; 308 } 309 if (n == '\n') { 310 yyunputc(' '); 311 yypos++; 312 } 313 } while (n != c); 314 rval = YY_STR; 315 goto done; 316 /* NOTREACHED */ 317 318 case EOF : 319 yylineNum = 1; 320 yypos = 0; 321 yylast = -1; 322 yyexpectaddr = 0; 323 yybreakondot = 0; 324 yyvarnext = 0; 325 yytokentype = 0; 326 return 0; 327 } 328 329 if (strchr("=,/;{}()@", c) != NULL) { 330 if (isbuilding == 1) { 331 yyunputc(c); 332 goto done; 333 } 334 rval = c; 335 goto done; 336 } else if (c == '.') { 337 if (isbuilding == 0) { 338 rval = c; 339 goto done; 340 } 341 if (yybreakondot != 0) { 342 yyunputc(c); 343 goto done; 344 } 345 } 346 347 switch (c) 348 { 349 case '-' : 350 if (yyexpectaddr) 351 break; 352 if (isbuilding == 1) 353 break; 354 n = yygetc(0); 355 if (n == '>') { 356 isbuilding = 1; 357 goto done; 358 } 359 yyunputc(n); 360 rval = '-'; 361 goto done; 362 363 case '!' : 364 if (isbuilding == 1) { 365 yyunputc(c); 366 goto done; 367 } 368 n = yygetc(0); 369 if (n == '=') { 370 rval = YY_CMP_NE; 371 goto done; 372 } 373 yyunputc(n); 374 rval = '!'; 375 goto done; 376 377 case '<' : 378 if (yyexpectaddr) 379 break; 380 if (isbuilding == 1) { 381 yyunputc(c); 382 goto done; 383 } 384 n = yygetc(0); 385 if (n == '=') { 386 rval = YY_CMP_LE; 387 goto done; 388 } 389 if (n == '>') { 390 rval = YY_RANGE_OUT; 391 goto done; 392 } 393 yyunputc(n); 394 rval = YY_CMP_LT; 395 goto done; 396 397 case '>' : 398 if (yyexpectaddr) 399 break; 400 if (isbuilding == 1) { 401 yyunputc(c); 402 goto done; 403 } 404 n = yygetc(0); 405 if (n == '=') { 406 rval = YY_CMP_GE; 407 goto done; 408 } 409 if (n == '<') { 410 rval = YY_RANGE_IN; 411 goto done; 412 } 413 yyunputc(n); 414 rval = YY_CMP_GT; 415 goto done; 416 } 417 418 /* 419 * Now for the reason this is here...IPv6 address parsing. 420 * The longest string we can expect is of this form: 421 * 0000:0000:0000:0000:0000:0000:000.000.000.000 422 * not: 423 * 0000:0000:0000:0000:0000:0000:0000:0000 424 */ 425 #ifdef USE_INET6 426 if (isbuilding == 0 && (ishex(c) || c == ':')) { 427 char ipv6buf[45 + 1], *s, oc; 428 int start; 429 430 start = yypos; 431 s = ipv6buf; 432 oc = c; 433 434 /* 435 * Perhaps we should implement stricter controls on what we 436 * swallow up here, but surely it would just be duplicating 437 * the code in inet_pton() anyway. 438 */ 439 do { 440 *s++ = c; 441 c = yygetc(1); 442 } while ((ishex(c) || c == ':' || c == '.') && 443 (s - ipv6buf < 46)); 444 yyunputc(c); 445 *s = '\0'; 446 447 if (inet_pton(AF_INET6, ipv6buf, &yylval.ip6) == 1) { 448 rval = YY_IPV6; 449 yyexpectaddr = 0; 450 goto done; 451 } 452 yypos = start; 453 c = oc; 454 } 455 #endif 456 457 if (c == ':') { 458 if (isbuilding == 1) { 459 yyunputc(c); 460 goto done; 461 } 462 rval = ':'; 463 goto done; 464 } 465 466 if (isbuilding == 0 && c == '0') { 467 n = yygetc(0); 468 if (n == 'x') { 469 do { 470 n = yygetc(1); 471 } while (ishex(n)); 472 yyunputc(n); 473 rval = YY_HEX; 474 goto done; 475 } 476 yyunputc(n); 477 } 478 479 /* 480 * No negative numbers with leading - sign.. 481 */ 482 if (isbuilding == 0 && ISDIGIT(c)) { 483 do { 484 n = yygetc(1); 485 } while (ISDIGIT(n)); 486 yyunputc(n); 487 rval = YY_NUMBER; 488 goto done; 489 } 490 491 isbuilding = 1; 492 goto nextchar; 493 494 done: 495 yystr = yytexttostr(0, yypos); 496 497 if (yydebug) 498 printf("isbuilding %d yyvarnext %d nokey %d\n", 499 isbuilding, yyvarnext, nokey); 500 if (isbuilding == 1) { 501 wordtab_t *w; 502 503 w = NULL; 504 isbuilding = 0; 505 506 if ((yyvarnext == 0) && (nokey == 0)) { 507 w = yyfindkey(yystr); 508 if (w == NULL && yywordtab != NULL) { 509 yyresetdict(); 510 w = yyfindkey(yystr); 511 } 512 } else 513 yyvarnext = 0; 514 if (w != NULL) 515 rval = w->w_value; 516 else 517 rval = YY_STR; 518 } 519 520 if (rval == YY_STR && yysavedepth > 0) 521 yyresetdict(); 522 523 yytokentype = rval; 524 525 if (yydebug) 526 printf("lexed(%s) [%d,%d,%d] => %d @%d\n", yystr, string_start, 527 string_end, pos, rval, yysavedepth); 528 529 switch (rval) 530 { 531 case YY_NUMBER : 532 sscanf(yystr, "%u", &yylval.num); 533 break; 534 535 case YY_HEX : 536 sscanf(yystr, "0x%x", (u_int *)&yylval.num); 537 break; 538 539 case YY_STR : 540 yylval.str = strdup(yystr); 541 break; 542 543 default : 544 break; 545 } 546 547 if (yylast > 0) { 548 bcopy(yytext + yypos, yytext, 549 sizeof(yytext[0]) * (yylast - yypos + 1)); 550 yylast -= yypos; 551 yypos = 0; 552 } 553 554 return rval; 555 } 556 557 558 static wordtab_t *yyfindkey(key) 559 char *key; 560 { 561 wordtab_t *w; 562 563 if (yywordtab == NULL) 564 return NULL; 565 566 for (w = yywordtab; w->w_word != 0; w++) 567 if (strcasecmp(key, w->w_word) == 0) 568 return w; 569 return NULL; 570 } 571 572 573 char *yykeytostr(num) 574 int num; 575 { 576 wordtab_t *w; 577 578 if (yywordtab == NULL) 579 return "<unknown>"; 580 581 for (w = yywordtab; w->w_word; w++) 582 if (w->w_value == num) 583 return w->w_word; 584 return "<unknown>"; 585 } 586 587 588 wordtab_t *yysettab(words) 589 wordtab_t *words; 590 { 591 wordtab_t *save; 592 593 save = yywordtab; 594 yywordtab = words; 595 return save; 596 } 597 598 599 void yyerror(msg) 600 char *msg; 601 { 602 char *txt, letter[2]; 603 int freetxt = 0; 604 605 if (yytokentype < 256) { 606 letter[0] = yytokentype; 607 letter[1] = '\0'; 608 txt = letter; 609 } else if (yytokentype == YY_STR || yytokentype == YY_HEX || 610 yytokentype == YY_NUMBER) { 611 if (yystr == NULL) { 612 txt = yytexttostr(yypos, YYBUFSIZ); 613 if (txt == NULL) { 614 fprintf(stderr, "sorry, out of memory," 615 " bailing out\n"); 616 exit(1); 617 } 618 freetxt = 1; 619 } else 620 txt = yystr; 621 } else { 622 txt = yykeytostr(yytokentype); 623 if (txt == NULL) { 624 fprintf(stderr, "sorry, out of memory," 625 " bailing out\n"); 626 exit(1); 627 } 628 } 629 fprintf(stderr, "%s error at \"%s\", line %d\n", msg, txt, yylineNum); 630 if (freetxt == 1) 631 free(txt); 632 exit(1); 633 } 634 635 636 void yysetdict(newdict) 637 wordtab_t *newdict; 638 { 639 if (yysavedepth == sizeof(yysavewords)/sizeof(yysavewords[0])) { 640 fprintf(stderr, "%d: at maximum dictionary depth\n", 641 yylineNum); 642 return; 643 } 644 645 yysavewords[yysavedepth++] = yysettab(newdict); 646 if (yydebug) 647 printf("yysavedepth++ => %d\n", yysavedepth); 648 } 649 650 void yyresetdict() 651 { 652 if (yydebug) 653 printf("yyresetdict(%d)\n", yysavedepth); 654 if (yysavedepth > 0) { 655 yysettab(yysavewords[--yysavedepth]); 656 if (yydebug) 657 printf("yysavedepth-- => %d\n", yysavedepth); 658 } 659 } 660 661 662 663 #ifdef TEST_LEXER 664 int main(argc, argv) 665 int argc; 666 char *argv[]; 667 { 668 int n; 669 670 yyin = stdin; 671 672 while ((n = yylex()) != 0) 673 printf("%d.n = %d [%s] %d %d\n", 674 yylineNum, n, yystr, yypos, yylast); 675 } 676 #endif 677