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 <sys/param.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(char *);
56 static int yygetc(int);
57 static void yyunputc(int);
58 static int yyswallow(int);
59 static char *yytexttostr(int, int);
60 static void yystrtotext(char *);
61 static char *yytexttochar(void);
62
63 static int
yygetc(int docont)64 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
101 static void
yyunputc(int c)102 yyunputc(int c)
103 {
104 if (c == '\n')
105 yylineNum--;
106 yytext[--yypos] = c;
107 }
108
109
110 static int
yyswallow(int last)111 yyswallow(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
126 static char *
yytexttochar(void)127 yytexttochar(void)
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
138 static void
yystrtotext(char * str)139 yystrtotext(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
154 static char *
yytexttostr(int offset,int max)155 yytexttostr(int offset, int 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
178 int
yylex(void)179 yylex(void)
180 {
181 static int prior = 0;
182 static int priornum = 0;
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 prior = c;
245 return (c);
246 }
247 goto nextchar;
248 }
249
250 switch (c)
251 {
252 case '#' :
253 if (isbuilding == 1) {
254 yyunputc(c);
255 goto done;
256 }
257 yyswallow('\n');
258 rval = YY_COMMENT;
259 goto done;
260
261 case '$' :
262 if (isbuilding == 1) {
263 yyunputc(c);
264 goto done;
265 }
266 n = yygetc(0);
267 if (n == '{') {
268 if (yyswallow('}') == -1) {
269 rval = -2;
270 goto done;
271 }
272 (void) yygetc(0);
273 } else {
274 if (!ISALPHA(n)) {
275 yyunputc(n);
276 break;
277 }
278 do {
279 n = yygetc(1);
280 } while (ISALPHA(n) || ISDIGIT(n) || n == '_');
281 yyunputc(n);
282 }
283
284 name = yytexttostr(1, yypos); /* skip $ */
285
286 if (name != NULL) {
287 string_val = get_variable(name, NULL, yylineNum);
288 free(name);
289 if (string_val != NULL) {
290 name = yytexttostr(yypos, yylast);
291 if (name != NULL) {
292 yypos = 0;
293 yylast = 0;
294 yystrtotext(string_val);
295 yystrtotext(name);
296 free(string_val);
297 free(name);
298 goto nextchar;
299 }
300 free(string_val);
301 }
302 }
303 break;
304
305 case '\'':
306 case '"' :
307 if (isbuilding == 1) {
308 goto done;
309 }
310 do {
311 n = yygetc(1);
312 if (n == EOF || n == TOOLONG) {
313 rval = -2;
314 goto done;
315 }
316 if (n == '\n') {
317 yyunputc(' ');
318 yypos++;
319 }
320 } while (n != c);
321 rval = YY_STR;
322 goto done;
323 /* NOTREACHED */
324
325 case EOF :
326 yylineNum = 1;
327 yypos = 0;
328 yylast = -1;
329 yyexpectaddr = 0;
330 yybreakondot = 0;
331 yyvarnext = 0;
332 yytokentype = 0;
333 if (yydebug)
334 fprintf(stderr, "reset at EOF\n");
335 prior = 0;
336 return (0);
337 }
338
339 if (strchr("=,/;{}()@", c) != NULL) {
340 if (isbuilding == 1) {
341 yyunputc(c);
342 goto done;
343 }
344 rval = c;
345 goto done;
346 } else if (c == '.') {
347 if (isbuilding == 0) {
348 rval = c;
349 goto done;
350 }
351 if (yybreakondot != 0) {
352 yyunputc(c);
353 goto done;
354 }
355 }
356
357 switch (c)
358 {
359 case '-' :
360 n = yygetc(0);
361 if (n == '>') {
362 isbuilding = 1;
363 goto done;
364 }
365 yyunputc(n);
366 if (yyexpectaddr) {
367 if (isbuilding == 1)
368 yyunputc(c);
369 else
370 rval = '-';
371 goto done;
372 }
373 if (isbuilding == 1)
374 break;
375 rval = '-';
376 goto done;
377
378 case '!' :
379 if (isbuilding == 1) {
380 yyunputc(c);
381 goto done;
382 }
383 n = yygetc(0);
384 if (n == '=') {
385 rval = YY_CMP_NE;
386 goto done;
387 }
388 yyunputc(n);
389 rval = '!';
390 goto done;
391
392 case '<' :
393 if (yyexpectaddr)
394 break;
395 if (isbuilding == 1) {
396 yyunputc(c);
397 goto done;
398 }
399 n = yygetc(0);
400 if (n == '=') {
401 rval = YY_CMP_LE;
402 goto done;
403 }
404 if (n == '>') {
405 rval = YY_RANGE_OUT;
406 goto done;
407 }
408 yyunputc(n);
409 rval = YY_CMP_LT;
410 goto done;
411
412 case '>' :
413 if (yyexpectaddr)
414 break;
415 if (isbuilding == 1) {
416 yyunputc(c);
417 goto done;
418 }
419 n = yygetc(0);
420 if (n == '=') {
421 rval = YY_CMP_GE;
422 goto done;
423 }
424 if (n == '<') {
425 rval = YY_RANGE_IN;
426 goto done;
427 }
428 yyunputc(n);
429 rval = YY_CMP_GT;
430 goto done;
431 }
432
433 /*
434 * Now for the reason this is here...IPv6 address parsing.
435 * The longest string we can expect is of this form:
436 * 0000:0000:0000:0000:0000:0000:000.000.000.000
437 * not:
438 * 0000:0000:0000:0000:0000:0000:0000:0000
439 */
440 #ifdef USE_INET6
441 if (yyexpectaddr != 0 && isbuilding == 0 &&
442 (ishex(c) || isdigit(c) || c == ':')) {
443 char ipv6buf[45 + 1], *s, oc;
444 int start;
445
446 buildipv6:
447 start = yypos;
448 s = ipv6buf;
449 oc = c;
450
451 if (prior == YY_NUMBER && c == ':') {
452 snprintf(s, sizeof(ipv6buf), "%d", priornum);
453 s += strlen(s);
454 }
455
456 /*
457 * Perhaps we should implement stricter controls on what we
458 * swallow up here, but surely it would just be duplicating
459 * the code in inet_pton() anyway.
460 */
461 do {
462 *s++ = c;
463 c = yygetc(1);
464 } while ((ishex(c) || c == ':' || c == '.') &&
465 (s - ipv6buf < 46));
466 yyunputc(c);
467 *s = '\0';
468
469 if (inet_pton(AF_INET6, ipv6buf, &yylval.ip6) == 1) {
470 rval = YY_IPV6;
471 yyexpectaddr = 0;
472 goto done;
473 }
474 yypos = start;
475 c = oc;
476 }
477 #endif
478
479 if ((c == ':') && (rval != YY_IPV6) && (triedv6 == 0)) {
480 #ifdef USE_INET6
481 yystr = yytexttostr(0, yypos - 1);
482 if (yystr != NULL) {
483 char *s;
484
485 for (s = yystr; *s && ishex(*s); s++)
486 ;
487 if (!*s && *yystr) {
488 isbuilding = 0;
489 c = *yystr;
490 free(yystr);
491 triedv6 = 1;
492 yypos = 1;
493 goto buildipv6;
494 }
495 free(yystr);
496 }
497 #endif
498 if (isbuilding == 1) {
499 yyunputc(c);
500 goto done;
501 }
502 rval = ':';
503 goto done;
504 }
505
506 if (isbuilding == 0 && c == '0') {
507 n = yygetc(0);
508 if (n == 'x') {
509 do {
510 n = yygetc(1);
511 } while (ishex(n));
512 yyunputc(n);
513 rval = YY_HEX;
514 goto done;
515 }
516 yyunputc(n);
517 }
518
519 /*
520 * No negative numbers with leading - sign..
521 */
522 if (isbuilding == 0 && ISDIGIT(c)) {
523 do {
524 n = yygetc(1);
525 } while (ISDIGIT(n));
526 yyunputc(n);
527 rval = YY_NUMBER;
528 goto done;
529 }
530
531 isbuilding = 1;
532 goto nextchar;
533
534 done:
535 yystr = yytexttostr(0, yypos);
536
537 if (yydebug)
538 printf("isbuilding %d yyvarnext %d nokey %d fixed %d addr %d\n",
539 isbuilding, yyvarnext, nokey, yydictfixed, yyexpectaddr);
540 if (isbuilding == 1) {
541 wordtab_t *w;
542
543 w = NULL;
544 isbuilding = 0;
545
546 if ((yyvarnext == 0) && (nokey == 0)) {
547 w = yyfindkey(yystr);
548 if (w == NULL && yywordtab != NULL && !yydictfixed) {
549 yyresetdict();
550 w = yyfindkey(yystr);
551 }
552 } else
553 yyvarnext = 0;
554 if (w != NULL)
555 rval = w->w_value;
556 else
557 rval = YY_STR;
558 }
559
560 if (rval == YY_STR) {
561 if (yysavedepth > 0 && !yydictfixed)
562 yyresetdict();
563 if (yyexpectaddr != 0)
564 yyexpectaddr = 0;
565 }
566
567 yytokentype = rval;
568
569 if (yydebug)
570 printf("lexed(%s) %d,%d,%d [%d,%d,%d] => %d @%d\n",
571 yystr, isbuilding, yyexpectaddr, yysavedepth,
572 string_start, string_end, pos, rval, yysavedepth);
573
574 switch (rval)
575 {
576 case YY_NUMBER :
577 sscanf(yystr, "%u", &yylval.num);
578 break;
579
580 case YY_HEX :
581 sscanf(yystr, "0x%x", (u_int *)&yylval.num);
582 break;
583
584 case YY_STR :
585 yylval.str = strdup(yystr);
586 break;
587
588 default :
589 break;
590 }
591
592 if (yylast > 0) {
593 bcopy(yytext + yypos, yytext,
594 sizeof(yytext[0]) * (yylast - yypos + 1));
595 yylast -= yypos;
596 yypos = 0;
597 }
598
599 if (rval == YY_NUMBER)
600 priornum = yylval.num;
601 prior = rval;
602 return (rval);
603 }
604
605
yyfindkey(char * key)606 static wordtab_t *yyfindkey(char *key)
607 {
608 wordtab_t *w;
609
610 if (yywordtab == NULL)
611 return (NULL);
612
613 for (w = yywordtab; w->w_word != 0; w++)
614 if (strcasecmp(key, w->w_word) == 0)
615 return (w);
616 return (NULL);
617 }
618
619
620 char *
yykeytostr(int num)621 yykeytostr(int num)
622 {
623 wordtab_t *w;
624
625 if (yywordtab == NULL)
626 return ("<unknown>");
627
628 for (w = yywordtab; w->w_word; w++)
629 if (w->w_value == num)
630 return (w->w_word);
631 return ("<unknown>");
632 }
633
634
635 wordtab_t *
yysettab(wordtab_t * words)636 yysettab(wordtab_t *words)
637 {
638 wordtab_t *save;
639
640 save = yywordtab;
641 yywordtab = words;
642 return (save);
643 }
644
645
646 void
yyerror(char * msg)647 yyerror(char *msg)
648 {
649 char *txt, letter[2];
650 int freetxt = 0;
651
652 if (yytokentype < 256) {
653 letter[0] = yytokentype;
654 letter[1] = '\0';
655 txt = letter;
656 } else if (yytokentype == YY_STR || yytokentype == YY_HEX ||
657 yytokentype == YY_NUMBER) {
658 if (yystr == NULL) {
659 txt = yytexttostr(yypos, YYBUFSIZ);
660 freetxt = 1;
661 } else
662 txt = yystr;
663 } else {
664 txt = yykeytostr(yytokentype);
665 }
666 fprintf(stderr, "%s error at \"%s\", line %d\n", msg, txt, yylineNum);
667 if (freetxt == 1)
668 free(txt);
669 exit(1);
670 }
671
672
673 void
yysetfixeddict(wordtab_t * newdict)674 yysetfixeddict(wordtab_t *newdict)
675 {
676 if (yydebug)
677 printf("yysetfixeddict(%lx)\n", (u_long)newdict);
678
679 if (yysavedepth == nitems(yysavewords)) {
680 fprintf(stderr, "%d: at maximum dictionary depth\n",
681 yylineNum);
682 return;
683 }
684
685 yysavewords[yysavedepth++] = yysettab(newdict);
686 if (yydebug)
687 printf("yysavedepth++ => %d\n", yysavedepth);
688 yydictfixed = 1;
689 }
690
691
692 void
yysetdict(wordtab_t * newdict)693 yysetdict(wordtab_t *newdict)
694 {
695 if (yydebug)
696 printf("yysetdict(%lx)\n", (u_long)newdict);
697
698 if (yysavedepth == nitems(yysavewords)) {
699 fprintf(stderr, "%d: at maximum dictionary depth\n",
700 yylineNum);
701 return;
702 }
703
704 yysavewords[yysavedepth++] = yysettab(newdict);
705 if (yydebug)
706 printf("yysavedepth++ => %d\n", yysavedepth);
707 }
708
709 void
yyresetdict(void)710 yyresetdict(void)
711 {
712 if (yydebug)
713 printf("yyresetdict(%d)\n", yysavedepth);
714 if (yysavedepth > 0) {
715 yysettab(yysavewords[--yysavedepth]);
716 if (yydebug)
717 printf("yysavedepth-- => %d\n", yysavedepth);
718 }
719 yydictfixed = 0;
720 }
721
722
723
724 #ifdef TEST_LEXER
725 int
main(int argc,char * argv[])726 main(int argc, char *argv[])
727 {
728 int n;
729
730 yyin = stdin;
731
732 while ((n = yylex()) != 0)
733 printf("%d.n = %d [%s] %d %d\n",
734 yylineNum, n, yystr, yypos, yylast);
735 }
736 #endif
737