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(docont)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
yyunputc(c)102 static void yyunputc(c)
103 int c;
104 {
105 if (c == '\n')
106 yylineNum--;
107 yytext[--yypos] = c;
108 }
109
110
yyswallow(last)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
yytexttochar()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
yystrtotext(str)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
yytexttostr(offset,max)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
yylex()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
yyfindkey(key)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
yykeytostr(num)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
yysettab(words)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
yyerror(msg)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
yysetdict(newdict)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
yyresetdict()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
main(argc,argv)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