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