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