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