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