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