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