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