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