lexer.c revision 161357
1251876Speter/*	$FreeBSD: head/contrib/ipfilter/tools/lexer.c 161357 2006-08-16 12:23:02Z guido $	*/
2251876Speter
3251876Speter/*
4251876Speter * Copyright (C) 2003 by Darren Reed.
5251876Speter *
6251876Speter * See the IPFILTER.LICENCE file for details on licencing.
7251876Speter */
8251876Speter#include <ctype.h>
9251876Speter#include "ipf.h"
10251876Speter#ifdef	IPFILTER_SCAN
11251876Speter# include "netinet/ip_scan.h"
12251876Speter#endif
13251876Speter#include <sys/ioctl.h>
14251876Speter#include <syslog.h>
15251876Speter#ifdef	TEST_LEXER
16251876Speter# define	NO_YACC
17251876Speterunion	{
18251876Speter	int		num;
19251876Speter	char		*str;
20251876Speter	struct in_addr	ipa;
21251876Speter	i6addr_t	ip6;
22251876Speter} yylval;
23251876Speter#endif
24251876Speter#include "lexer.h"
25251876Speter#include "y.tab.h"
26251876Speter
27251876SpeterFILE *yyin;
28251876Speter
29251876Speter#define	ishex(c)	(ISDIGIT(c) || ((c) >= 'a' && (c) <= 'f') || \
30251876Speter			 ((c) >= 'A' && (c) <= 'F'))
31251876Speter#define	TOOLONG		-3
32251876Speter
33251876Speterextern int	string_start;
34251876Speterextern int	string_end;
35251876Speterextern char	*string_val;
36251876Speterextern int	pos;
37251876Speterextern int	yydebug;
38251876Speter
39251876Speterchar		*yystr = NULL;
40251876Speterint		yytext[YYBUFSIZ+1];
41251876Speterint		yylineNum = 1;
42251876Speterint		yypos = 0;
43251876Speterint		yylast = -1;
44251876Speterint		yyexpectaddr = 0;
45251876Speterint		yybreakondot = 0;
46251876Speterint		yyvarnext = 0;
47251876Speterint		yytokentype = 0;
48251876Speterwordtab_t	*yywordtab = NULL;
49251876Speterint		yysavedepth = 0;
50251876Speterwordtab_t	*yysavewords[30];
51251876Speter
52251876Speter
53251876Speterstatic	wordtab_t	*yyfindkey __P((char *));
54251876Speterstatic	int		yygetc __P((void));
55251876Speterstatic	void		yyunputc __P((int));
56251876Speterstatic	int		yyswallow __P((int));
57251876Speterstatic	char		*yytexttostr __P((int, int));
58251876Speterstatic	void		yystrtotext __P((char *));
59251876Speter
60251876Speterstatic int yygetc()
61251876Speter{
62251876Speter	int c;
63251876Speter
64251876Speter	if (yypos < yylast) {
65251876Speter		c = yytext[yypos++];
66251876Speter		if (c == '\n')
67251876Speter			yylineNum++;
68251876Speter		return c;
69251876Speter	}
70251876Speter
71251876Speter	if (yypos == YYBUFSIZ)
72251876Speter		return TOOLONG;
73251876Speter
74251876Speter	if (pos >= string_start && pos <= string_end) {
75251876Speter		c = string_val[pos - string_start];
76251876Speter		yypos++;
77251876Speter	} else {
78251876Speter		c = fgetc(yyin);
79251876Speter	}
80251876Speter	if (c == '\n')
81251876Speter		yylineNum++;
82251876Speter	yytext[yypos++] = c;
83251876Speter	yylast = yypos;
84251876Speter	yytext[yypos] = '\0';
85251876Speter
86251876Speter	return c;
87251876Speter}
88251876Speter
89251876Speter
90251876Speterstatic void yyunputc(c)
91251876Speterint c;
92251876Speter{
93251876Speter	if (c == '\n')
94251876Speter		yylineNum--;
95251876Speter	yytext[--yypos] = c;
96251876Speter}
97251876Speter
98251876Speter
99251876Speterstatic int yyswallow(last)
100251876Speterint last;
101251876Speter{
102251876Speter	int c;
103251876Speter
104251876Speter	while (((c = yygetc()) > '\0') && (c != last))
105251876Speter		;
106251876Speter
107251876Speter	if (c != EOF)
108251876Speter		yyunputc(c);
109251876Speter	if (c == last)
110251876Speter		return 0;
111251876Speter	return -1;
112251876Speter}
113251876Speter
114251876Speter
115251876Speterstatic void yystrtotext(str)
116251876Speterchar *str;
117251876Speter{
118251876Speter	int len;
119251876Speter	char *s;
120251876Speter
121251876Speter	len = strlen(str);
122251876Speter	if (len > YYBUFSIZ)
123251876Speter		len = YYBUFSIZ;
124251876Speter
125251876Speter	for (s = str; *s != '\0' && len > 0; s++, len--)
126251876Speter		yytext[yylast++] = *s;
127251876Speter	yytext[yylast] = '\0';
128251876Speter}
129251876Speter
130251876Speter
131251876Speterstatic char *yytexttostr(offset, max)
132251876Speterint offset, max;
133251876Speter{
134251876Speter	char *str;
135251876Speter	int i;
136251876Speter
137251876Speter	if ((yytext[offset] == '\'' || yytext[offset] == '"') &&
138251876Speter	    (yytext[offset] == yytext[offset + max - 1])) {
139251876Speter		offset++;
140251876Speter		max--;
141251876Speter	}
142251876Speter
143251876Speter	if (max > yylast)
144251876Speter		max = yylast;
145251876Speter	str = malloc(max + 1);
146251876Speter	if (str != NULL) {
147251876Speter		for (i = offset; i < max; i++)
148251876Speter			str[i - offset] = (char)(yytext[i] & 0xff);
149251876Speter		str[i - offset] = '\0';
150251876Speter	}
151251876Speter	return str;
152251876Speter}
153251876Speter
154251876Speter
155251876Speterint yylex()
156251876Speter{
157251876Speter	int c, n, isbuilding, rval, lnext, nokey = 0;
158251876Speter	char *name;
159251876Speter
160251876Speter	isbuilding = 0;
161251876Speter	lnext = 0;
162251876Speter	rval = 0;
163251876Speter
164251876Speter	if (yystr != NULL) {
165251876Speter		free(yystr);
166251876Speter		yystr = NULL;
167251876Speter	}
168251876Speter
169251876Speternextchar:
170251876Speter	c = yygetc();
171251876Speter
172251876Speter	switch (c)
173251876Speter	{
174251876Speter	case '\n' :
175251876Speter		lnext = 0;
176251876Speter		nokey = 0;
177251876Speter	case '\t' :
178251876Speter	case '\r' :
179251876Speter	case ' ' :
180251876Speter		if (isbuilding == 1) {
181251876Speter			yyunputc(c);
182251876Speter			goto done;
183251876Speter		}
184251876Speter		if (yylast > yypos) {
185251876Speter			bcopy(yytext + yypos, yytext,
186251876Speter			      sizeof(yytext[0]) * (yylast - yypos + 1));
187251876Speter		}
188251876Speter		yylast -= yypos;
189251876Speter		yypos = 0;
190251876Speter		lnext = 0;
191251876Speter		nokey = 0;
192251876Speter		goto nextchar;
193251876Speter
194251876Speter	case '\\' :
195251876Speter		if (lnext == 0) {
196251876Speter			lnext = 1;
197251876Speter			if (yylast == yypos) {
198251876Speter				yylast--;
199251876Speter				yypos--;
200251876Speter			} else
201251876Speter				yypos--;
202251876Speter			if (yypos == 0)
203251876Speter				nokey = 1;
204251876Speter			goto nextchar;
205251876Speter		}
206251876Speter		break;
207251876Speter	}
208251876Speter
209251876Speter	if (lnext == 1) {
210251876Speter		lnext = 0;
211251876Speter		if ((isbuilding == 0) && !ISALNUM(c)) {
212251876Speter			return c;
213251876Speter		}
214251876Speter		goto nextchar;
215251876Speter	}
216251876Speter
217251876Speter	switch (c)
218251876Speter	{
219251876Speter	case '#' :
220251876Speter		if (isbuilding == 1) {
221251876Speter			yyunputc(c);
222251876Speter			goto done;
223251876Speter		}
224251876Speter		yyswallow('\n');
225251876Speter		rval = YY_COMMENT;
226251876Speter		goto nextchar;
227251876Speter
228251876Speter	case '$' :
229251876Speter		if (isbuilding == 1) {
230251876Speter			yyunputc(c);
231251876Speter			goto done;
232251876Speter		}
233251876Speter		n = yygetc();
234251876Speter		if (n == '{') {
235251876Speter			if (yyswallow('}') == -1) {
236251876Speter				rval = -2;
237251876Speter				goto done;
238251876Speter			}
239251876Speter			(void) yygetc();
240251876Speter		} else {
241251876Speter			if (!ISALPHA(n)) {
242251876Speter				yyunputc(n);
243251876Speter				break;
244251876Speter			}
245251876Speter			do {
246251876Speter				n = yygetc();
247251876Speter			} while (ISALPHA(n) || ISDIGIT(n) || n == '_');
248251876Speter			yyunputc(n);
249251876Speter		}
250251876Speter
251251876Speter		name = yytexttostr(1, yypos);		/* skip $ */
252251876Speter
253251876Speter		if (name != NULL) {
254251876Speter			string_val = get_variable(name, NULL, yylineNum);
255251876Speter			free(name);
256251876Speter			if (string_val != NULL) {
257251876Speter				name = yytexttostr(yypos, yylast);
258251876Speter				if (name != NULL) {
259251876Speter					yypos = 0;
260251876Speter					yylast = 0;
261251876Speter					yystrtotext(string_val);
262251876Speter					yystrtotext(name);
263251876Speter					free(string_val);
264251876Speter					free(name);
265251876Speter					goto nextchar;
266251876Speter				}
267251876Speter				free(string_val);
268251876Speter			}
269251876Speter		}
270251876Speter		break;
271251876Speter
272251876Speter	case '\'':
273251876Speter	case '"' :
274251876Speter		if (isbuilding == 1) {
275251876Speter			goto done;
276251876Speter		}
277251876Speter		do {
278251876Speter			n = yygetc();
279251876Speter			if (n == EOF || n == TOOLONG) {
280251876Speter				rval = -2;
281251876Speter				goto done;
282251876Speter			}
283251876Speter			if (n == '\n') {
284251876Speter				yyunputc(' ');
285251876Speter				yypos++;
286251876Speter			}
287251876Speter		} while (n != c);
288251876Speter		yyunputc(n);
289251876Speter		break;
290251876Speter
291251876Speter	case EOF :
292251876Speter		yylineNum = 1;
293251876Speter		yypos = 0;
294251876Speter		yylast = -1;
295251876Speter		yyexpectaddr = 0;
296251876Speter		yybreakondot = 0;
297251876Speter		yyvarnext = 0;
298251876Speter		yytokentype = 0;
299251876Speter		return 0;
300251876Speter	}
301251876Speter
302251876Speter	if (strchr("=,/;{}()@", c) != NULL) {
303251876Speter		if (isbuilding == 1) {
304251876Speter			yyunputc(c);
305251876Speter			goto done;
306251876Speter		}
307251876Speter		rval = c;
308251876Speter		goto done;
309251876Speter	} else if (c == '.') {
310251876Speter		if (isbuilding == 0) {
311251876Speter			rval = c;
312251876Speter			goto done;
313251876Speter		}
314251876Speter		if (yybreakondot != 0) {
315251876Speter			yyunputc(c);
316251876Speter			goto done;
317251876Speter		}
318251876Speter	}
319251876Speter
320251876Speter	switch (c)
321251876Speter	{
322251876Speter	case '-' :
323251876Speter		if (yyexpectaddr)
324251876Speter			break;
325251876Speter		if (isbuilding == 1)
326251876Speter			break;
327251876Speter		n = yygetc();
328253734Speter		if (n == '>') {
329251876Speter			isbuilding = 1;
330251876Speter			goto done;
331251876Speter		}
332251876Speter		yyunputc(n);
333251876Speter		rval = '-';
334251876Speter		goto done;
335251876Speter
336251876Speter	case '!' :
337251876Speter		if (isbuilding == 1) {
338251876Speter			yyunputc(c);
339251876Speter			goto done;
340251876Speter		}
341251876Speter		n = yygetc();
342251876Speter		if (n == '=') {
343251876Speter			rval = YY_CMP_NE;
344251876Speter			goto done;
345251876Speter		}
346251876Speter		yyunputc(n);
347251876Speter		rval = '!';
348251876Speter		goto done;
349251876Speter
350251876Speter	case '<' :
351251876Speter		if (yyexpectaddr)
352251876Speter			break;
353251876Speter		if (isbuilding == 1) {
354251876Speter			yyunputc(c);
355251876Speter			goto done;
356251876Speter		}
357251876Speter		n = yygetc();
358251876Speter		if (n == '=') {
359251876Speter			rval = YY_CMP_LE;
360251876Speter			goto done;
361251876Speter		}
362251876Speter		if (n == '>') {
363251876Speter			rval = YY_RANGE_OUT;
364251876Speter			goto done;
365251876Speter		}
366251876Speter		yyunputc(n);
367251876Speter		rval = YY_CMP_LT;
368251876Speter		goto done;
369251876Speter
370251876Speter	case '>' :
371251876Speter		if (yyexpectaddr)
372251876Speter			break;
373251876Speter		if (isbuilding == 1) {
374251876Speter			yyunputc(c);
375251876Speter			goto done;
376251876Speter		}
377251876Speter		n = yygetc();
378251876Speter		if (n == '=') {
379251876Speter			rval = YY_CMP_GE;
380251876Speter			goto done;
381251876Speter		}
382251876Speter		if (n == '<') {
383251876Speter			rval = YY_RANGE_IN;
384251876Speter			goto done;
385251876Speter		}
386251876Speter		yyunputc(n);
387251876Speter		rval = YY_CMP_GT;
388251876Speter		goto done;
389251876Speter	}
390251876Speter
391251876Speter	/*
392251876Speter	 * Now for the reason this is here...IPv6 address parsing.
393251876Speter	 * The longest string we can expect is of this form:
394251876Speter	 * 0000:0000:0000:0000:0000:0000:000.000.000.000
395251876Speter	 * not:
396251876Speter	 * 0000:0000:0000:0000:0000:0000:0000:0000
397251876Speter	 */
398251876Speter#ifdef	USE_INET6
399251876Speter	if (yyexpectaddr == 1 && isbuilding == 0 && (ishex(c) || c == ':')) {
400251876Speter		char ipv6buf[45 + 1], *s, oc;
401251876Speter		int start;
402251876Speter
403251876Speter		start = yypos;
404251876Speter		s = ipv6buf;
405251876Speter		oc = c;
406251876Speter
407251876Speter		/*
408251876Speter		 * Perhaps we should implement stricter controls on what we
409251876Speter		 * swallow up here, but surely it would just be duplicating
410251876Speter		 * the code in inet_pton() anyway.
411251876Speter		 */
412251876Speter		do {
413251876Speter			*s++ = c;
414251876Speter			c = yygetc();
415251876Speter		} while ((ishex(c) || c == ':' || c == '.') &&
416251876Speter			 (s - ipv6buf < 46));
417251876Speter		yyunputc(c);
418251876Speter		*s = '\0';
419251876Speter
420251876Speter		if (inet_pton(AF_INET6, ipv6buf, &yylval.ip6) == 1) {
421251876Speter			rval = YY_IPV6;
422251876Speter			yyexpectaddr = 0;
423251876Speter			goto done;
424251876Speter		}
425251876Speter		yypos = start;
426251876Speter		c = oc;
427251876Speter	}
428251876Speter#endif
429251876Speter
430251876Speter	if (c == ':') {
431251876Speter		if (isbuilding == 1) {
432251876Speter			yyunputc(c);
433251876Speter			goto done;
434251876Speter		}
435251876Speter		rval = ':';
436251876Speter		goto done;
437251876Speter	}
438251876Speter
439251876Speter	if (isbuilding == 0 && c == '0') {
440251876Speter		n = yygetc();
441251876Speter		if (n == 'x') {
442251876Speter			do {
443251876Speter				n = yygetc();
444251876Speter			} while (ishex(n));
445251876Speter			yyunputc(n);
446251876Speter			rval = YY_HEX;
447251876Speter			goto done;
448251876Speter		}
449251876Speter		yyunputc(n);
450251876Speter	}
451251876Speter
452251876Speter	/*
453251876Speter	 * No negative numbers with leading - sign..
454251876Speter	 */
455251876Speter	if (isbuilding == 0 && ISDIGIT(c)) {
456251876Speter		do {
457251876Speter			n = yygetc();
458251876Speter		} while (ISDIGIT(n));
459251876Speter		yyunputc(n);
460251876Speter		rval = YY_NUMBER;
461251876Speter		goto done;
462251876Speter	}
463251876Speter
464251876Speter	isbuilding = 1;
465251876Speter	goto nextchar;
466251876Speter
467251876Speterdone:
468251876Speter	yystr = yytexttostr(0, yypos);
469251876Speter
470251876Speter	if (isbuilding == 1) {
471251876Speter		wordtab_t *w;
472251876Speter
473251876Speter		w = NULL;
474251876Speter		isbuilding = 0;
475251876Speter
476251876Speter		if ((yyvarnext == 0) && (nokey == 0)) {
477251876Speter			w = yyfindkey(yystr);
478251876Speter			if (w == NULL && yywordtab != NULL) {
479251876Speter				yyresetdict();
480251876Speter				w = yyfindkey(yystr);
481251876Speter			}
482251876Speter		} else
483251876Speter			yyvarnext = 0;
484251876Speter		if (w != NULL)
485251876Speter			rval = w->w_value;
486251876Speter		else
487251876Speter			rval = YY_STR;
488251876Speter	}
489251876Speter
490251876Speter	if (rval == YY_STR && yysavedepth > 0)
491251876Speter		yyresetdict();
492251876Speter
493251876Speter	yytokentype = rval;
494251876Speter
495251876Speter	if (yydebug)
496251876Speter		printf("lexed(%s) [%d,%d,%d] => %d\n", yystr, string_start,
497251876Speter			string_end, pos, rval);
498251876Speter
499251876Speter	switch (rval)
500251876Speter	{
501251876Speter	case YY_NUMBER :
502251876Speter		sscanf(yystr, "%u", &yylval.num);
503251876Speter		break;
504251876Speter
505251876Speter	case YY_HEX :
506251876Speter		sscanf(yystr, "0x%x", (u_int *)&yylval.num);
507251876Speter		break;
508251876Speter
509251876Speter	case YY_STR :
510251876Speter		yylval.str = strdup(yystr);
511251876Speter		break;
512251876Speter
513251876Speter	default :
514251876Speter		break;
515251876Speter	}
516251876Speter
517251876Speter	if (yylast > 0) {
518251876Speter		bcopy(yytext + yypos, yytext,
519251876Speter		      sizeof(yytext[0]) * (yylast - yypos + 1));
520251876Speter		yylast -= yypos;
521251876Speter		yypos = 0;
522251876Speter	}
523251876Speter
524251876Speter	return rval;
525251876Speter}
526251876Speter
527251876Speter
528251876Speterstatic wordtab_t *yyfindkey(key)
529251876Speterchar *key;
530251876Speter{
531251876Speter	wordtab_t *w;
532251876Speter
533251876Speter	if (yywordtab == NULL)
534251876Speter		return NULL;
535251876Speter
536251876Speter	for (w = yywordtab; w->w_word != 0; w++)
537251876Speter		if (strcasecmp(key, w->w_word) == 0)
538251876Speter			return w;
539251876Speter	return NULL;
540251876Speter}
541251876Speter
542251876Speter
543251876Speterchar *yykeytostr(num)
544251876Speterint num;
545251876Speter{
546251876Speter	wordtab_t *w;
547251876Speter
548251876Speter	if (yywordtab == NULL)
549251876Speter		return "<unknown>";
550251876Speter
551251876Speter	for (w = yywordtab; w->w_word; w++)
552251876Speter		if (w->w_value == num)
553251876Speter			return w->w_word;
554251876Speter	return "<unknown>";
555251876Speter}
556251876Speter
557251876Speter
558251876Speterwordtab_t *yysettab(words)
559251876Speterwordtab_t *words;
560251876Speter{
561251876Speter	wordtab_t *save;
562251876Speter
563251876Speter	save = yywordtab;
564251876Speter	yywordtab = words;
565251876Speter	return save;
566251876Speter}
567251876Speter
568251876Speter
569251876Spetervoid yyerror(msg)
570251876Speterchar *msg;
571251876Speter{
572251876Speter	char *txt, letter[2];
573251876Speter	int freetxt = 0;
574251876Speter
575251876Speter	if (yytokentype < 256) {
576251876Speter		letter[0] = yytokentype;
577251876Speter		letter[1] = '\0';
578251876Speter		txt =  letter;
579251876Speter	} else if (yytokentype == YY_STR || yytokentype == YY_HEX ||
580251876Speter		   yytokentype == YY_NUMBER) {
581251876Speter		if (yystr == NULL) {
582251876Speter			txt = yytexttostr(yypos, YYBUFSIZ);
583251876Speter			freetxt = 1;
584251876Speter		} else
585251876Speter			txt = yystr;
586251876Speter	} else {
587251876Speter		txt = yykeytostr(yytokentype);
588251876Speter	}
589251876Speter	fprintf(stderr, "%s error at \"%s\", line %d\n", msg, txt, yylineNum);
590251876Speter	if (freetxt == 1)
591251876Speter		free(txt);
592251876Speter	exit(1);
593251876Speter}
594251876Speter
595251876Speter
596251876Spetervoid yysetdict(newdict)
597251876Speterwordtab_t *newdict;
598251876Speter{
599251876Speter	if (yysavedepth == sizeof(yysavewords)/sizeof(yysavewords[0])) {
600251876Speter		fprintf(stderr, "%d: at maximum dictionary depth\n",
601251876Speter			yylineNum);
602251876Speter		return;
603251876Speter	}
604251876Speter
605251876Speter	yysavewords[yysavedepth++] = yysettab(newdict);
606251876Speter	if (yydebug)
607251876Speter		printf("yysavedepth++ => %d\n", yysavedepth);
608251876Speter}
609251876Speter
610251876Spetervoid yyresetdict()
611251876Speter{
612251876Speter	if (yysavedepth > 0) {
613251876Speter		yysettab(yysavewords[--yysavedepth]);
614251876Speter		if (yydebug)
615251876Speter			printf("yysavedepth-- => %d\n", yysavedepth);
616251876Speter	}
617251876Speter}
618251876Speter
619251876Speter
620251876Speter
621251876Speter#ifdef	TEST_LEXER
622251876Speterint main(argc, argv)
623251876Speterint argc;
624251876Speterchar *argv[];
625251876Speter{
626251876Speter	int n;
627251876Speter
628251876Speter	yyin = stdin;
629251876Speter
630251876Speter	while ((n = yylex()) != 0)
631251876Speter		printf("%d.n = %d [%s] %d %d\n",
632251876Speter			yylineNum, n, yystr, yypos, yylast);
633251876Speter}
634251876Speter#endif
635251876Speter