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