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