1 /* $FreeBSD$ */
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 static int prior = 0;
180 static int priornum = 0;
181 int c, n, isbuilding, rval, lnext, nokey = 0;
182 char *name;
183 int triedv6 = 0;
184
185 isbuilding = 0;
186 lnext = 0;
187 rval = 0;
188
189 if (yystr != NULL) {
190 free(yystr);
191 yystr = NULL;
192 }
193
194 nextchar:
195 c = yygetc(0);
196 if (yydebug > 1)
197 printf("yygetc = (%x) %c [%*.*s]\n",
198 c, c, yypos, yypos, yytexttochar());
199
200 switch (c)
201 {
202 case '\n' :
203 lnext = 0;
204 nokey = 0;
205 case '\t' :
206 case '\r' :
207 case ' ' :
208 if (isbuilding == 1) {
209 yyunputc(c);
210 goto done;
211 }
212 if (yylast > yypos) {
213 bcopy(yytext + yypos, yytext,
214 sizeof(yytext[0]) * (yylast - yypos + 1));
215 }
216 yylast -= yypos;
217 if (yyexpectaddr == 2)
218 yyexpectaddr = 0;
219 yypos = 0;
220 lnext = 0;
221 nokey = 0;
222 goto nextchar;
223
224 case '\\' :
225 if (lnext == 0) {
226 lnext = 1;
227 if (yylast == yypos) {
228 yylast--;
229 yypos--;
230 } else
231 yypos--;
232 if (yypos == 0)
233 nokey = 1;
234 goto nextchar;
235 }
236 break;
237 }
238
239 if (lnext == 1) {
240 lnext = 0;
241 if ((isbuilding == 0) && !ISALNUM(c)) {
242 prior = c;
243 return c;
244 }
245 goto nextchar;
246 }
247
248 switch (c)
249 {
250 case '#' :
251 if (isbuilding == 1) {
252 yyunputc(c);
253 goto done;
254 }
255 yyswallow('\n');
256 rval = YY_COMMENT;
257 goto done;
258
259 case '$' :
260 if (isbuilding == 1) {
261 yyunputc(c);
262 goto done;
263 }
264 n = yygetc(0);
265 if (n == '{') {
266 if (yyswallow('}') == -1) {
267 rval = -2;
268 goto done;
269 }
270 (void) yygetc(0);
271 } else {
272 if (!ISALPHA(n)) {
273 yyunputc(n);
274 break;
275 }
276 do {
277 n = yygetc(1);
278 } while (ISALPHA(n) || ISDIGIT(n) || n == '_');
279 yyunputc(n);
280 }
281
282 name = yytexttostr(1, yypos); /* skip $ */
283
284 if (name != NULL) {
285 string_val = get_variable(name, NULL, yylineNum);
286 free(name);
287 if (string_val != NULL) {
288 name = yytexttostr(yypos, yylast);
289 if (name != NULL) {
290 yypos = 0;
291 yylast = 0;
292 yystrtotext(string_val);
293 yystrtotext(name);
294 free(string_val);
295 free(name);
296 goto nextchar;
297 }
298 free(string_val);
299 }
300 }
301 break;
302
303 case '\'':
304 case '"' :
305 if (isbuilding == 1) {
306 goto done;
307 }
308 do {
309 n = yygetc(1);
310 if (n == EOF || n == TOOLONG) {
311 rval = -2;
312 goto done;
313 }
314 if (n == '\n') {
315 yyunputc(' ');
316 yypos++;
317 }
318 } while (n != c);
319 rval = YY_STR;
320 goto done;
321 /* NOTREACHED */
322
323 case EOF :
324 yylineNum = 1;
325 yypos = 0;
326 yylast = -1;
327 yyexpectaddr = 0;
328 yybreakondot = 0;
329 yyvarnext = 0;
330 yytokentype = 0;
331 if (yydebug)
332 fprintf(stderr, "reset at EOF\n");
333 prior = 0;
334 return 0;
335 }
336
337 if (strchr("=,/;{}()@", c) != NULL) {
338 if (isbuilding == 1) {
339 yyunputc(c);
340 goto done;
341 }
342 rval = c;
343 goto done;
344 } else if (c == '.') {
345 if (isbuilding == 0) {
346 rval = c;
347 goto done;
348 }
349 if (yybreakondot != 0) {
350 yyunputc(c);
351 goto done;
352 }
353 }
354
355 switch (c)
356 {
357 case '-' :
358 n = yygetc(0);
359 if (n == '>') {
360 isbuilding = 1;
361 goto done;
362 }
363 yyunputc(n);
364 if (yyexpectaddr) {
365 if (isbuilding == 1)
366 yyunputc(c);
367 else
368 rval = '-';
369 goto done;
370 }
371 if (isbuilding == 1)
372 break;
373 rval = '-';
374 goto done;
375
376 case '!' :
377 if (isbuilding == 1) {
378 yyunputc(c);
379 goto done;
380 }
381 n = yygetc(0);
382 if (n == '=') {
383 rval = YY_CMP_NE;
384 goto done;
385 }
386 yyunputc(n);
387 rval = '!';
388 goto done;
389
390 case '<' :
391 if (yyexpectaddr)
392 break;
393 if (isbuilding == 1) {
394 yyunputc(c);
395 goto done;
396 }
397 n = yygetc(0);
398 if (n == '=') {
399 rval = YY_CMP_LE;
400 goto done;
401 }
402 if (n == '>') {
403 rval = YY_RANGE_OUT;
404 goto done;
405 }
406 yyunputc(n);
407 rval = YY_CMP_LT;
408 goto done;
409
410 case '>' :
411 if (yyexpectaddr)
412 break;
413 if (isbuilding == 1) {
414 yyunputc(c);
415 goto done;
416 }
417 n = yygetc(0);
418 if (n == '=') {
419 rval = YY_CMP_GE;
420 goto done;
421 }
422 if (n == '<') {
423 rval = YY_RANGE_IN;
424 goto done;
425 }
426 yyunputc(n);
427 rval = YY_CMP_GT;
428 goto done;
429 }
430
431 /*
432 * Now for the reason this is here...IPv6 address parsing.
433 * The longest string we can expect is of this form:
434 * 0000:0000:0000:0000:0000:0000:000.000.000.000
435 * not:
436 * 0000:0000:0000:0000:0000:0000:0000:0000
437 */
438 #ifdef USE_INET6
439 if (yyexpectaddr != 0 && isbuilding == 0 &&
440 (ishex(c) || isdigit(c) || c == ':')) {
441 char ipv6buf[45 + 1], *s, oc;
442 int start;
443
444 buildipv6:
445 start = yypos;
446 s = ipv6buf;
447 oc = c;
448
449 if (prior == YY_NUMBER && c == ':') {
450 sprintf(s, "%d", priornum);
451 s += strlen(s);
452 }
453
454 /*
455 * Perhaps we should implement stricter controls on what we
456 * swallow up here, but surely it would just be duplicating
457 * the code in inet_pton() anyway.
458 */
459 do {
460 *s++ = c;
461 c = yygetc(1);
462 } while ((ishex(c) || c == ':' || c == '.') &&
463 (s - ipv6buf < 46));
464 yyunputc(c);
465 *s = '\0';
466
467 if (inet_pton(AF_INET6, ipv6buf, &yylval.ip6) == 1) {
468 rval = YY_IPV6;
469 yyexpectaddr = 0;
470 goto done;
471 }
472 yypos = start;
473 c = oc;
474 }
475 #endif
476
477 if ((c == ':') && (rval != YY_IPV6) && (triedv6 == 0)) {
478 #ifdef USE_INET6
479 yystr = yytexttostr(0, yypos - 1);
480 if (yystr != NULL) {
481 char *s;
482
483 for (s = yystr; *s && ishex(*s); s++)
484 ;
485 if (!*s && *yystr) {
486 isbuilding = 0;
487 c = *yystr;
488 free(yystr);
489 triedv6 = 1;
490 yypos = 1;
491 goto buildipv6;
492 }
493 free(yystr);
494 }
495 #endif
496 if (isbuilding == 1) {
497 yyunputc(c);
498 goto done;
499 }
500 rval = ':';
501 goto done;
502 }
503
504 if (isbuilding == 0 && c == '0') {
505 n = yygetc(0);
506 if (n == 'x') {
507 do {
508 n = yygetc(1);
509 } while (ishex(n));
510 yyunputc(n);
511 rval = YY_HEX;
512 goto done;
513 }
514 yyunputc(n);
515 }
516
517 /*
518 * No negative numbers with leading - sign..
519 */
520 if (isbuilding == 0 && ISDIGIT(c)) {
521 do {
522 n = yygetc(1);
523 } while (ISDIGIT(n));
524 yyunputc(n);
525 rval = YY_NUMBER;
526 goto done;
527 }
528
529 isbuilding = 1;
530 goto nextchar;
531
532 done:
533 yystr = yytexttostr(0, yypos);
534
535 if (yydebug)
536 printf("isbuilding %d yyvarnext %d nokey %d fixed %d addr %d\n",
537 isbuilding, yyvarnext, nokey, yydictfixed, yyexpectaddr);
538 if (isbuilding == 1) {
539 wordtab_t *w;
540
541 w = NULL;
542 isbuilding = 0;
543
544 if ((yyvarnext == 0) && (nokey == 0)) {
545 w = yyfindkey(yystr);
546 if (w == NULL && yywordtab != NULL && !yydictfixed) {
547 yyresetdict();
548 w = yyfindkey(yystr);
549 }
550 } else
551 yyvarnext = 0;
552 if (w != NULL)
553 rval = w->w_value;
554 else
555 rval = YY_STR;
556 }
557
558 if (rval == YY_STR) {
559 if (yysavedepth > 0 && !yydictfixed)
560 yyresetdict();
561 if (yyexpectaddr != 0)
562 yyexpectaddr = 0;
563 }
564
565 yytokentype = rval;
566
567 if (yydebug)
568 printf("lexed(%s) %d,%d,%d [%d,%d,%d] => %d @%d\n",
569 yystr, isbuilding, yyexpectaddr, yysavedepth,
570 string_start, string_end, pos, rval, yysavedepth);
571
572 switch (rval)
573 {
574 case YY_NUMBER :
575 sscanf(yystr, "%u", &yylval.num);
576 break;
577
578 case YY_HEX :
579 sscanf(yystr, "0x%x", (u_int *)&yylval.num);
580 break;
581
582 case YY_STR :
583 yylval.str = strdup(yystr);
584 break;
585
586 default :
587 break;
588 }
589
590 if (yylast > 0) {
591 bcopy(yytext + yypos, yytext,
592 sizeof(yytext[0]) * (yylast - yypos + 1));
593 yylast -= yypos;
594 yypos = 0;
595 }
596
597 if (rval == YY_NUMBER)
598 priornum = yylval.num;
599 prior = rval;
600 return rval;
601 }
602
603
yyfindkey(key)604 static wordtab_t *yyfindkey(key)
605 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
yykeytostr(num)619 char *yykeytostr(num)
620 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
yysettab(words)634 wordtab_t *yysettab(words)
635 wordtab_t *words;
636 {
637 wordtab_t *save;
638
639 save = yywordtab;
640 yywordtab = words;
641 return save;
642 }
643
644
yyerror(msg)645 void yyerror(msg)
646 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
yysetfixeddict(newdict)672 void yysetfixeddict(newdict)
673 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
yysetdict(newdict)691 void yysetdict(newdict)
692 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
yyresetdict()708 void yyresetdict()
709 {
710 if (yydebug)
711 printf("yyresetdict(%d)\n", yysavedepth);
712 if (yysavedepth > 0) {
713 yysettab(yysavewords[--yysavedepth]);
714 if (yydebug)
715 printf("yysavedepth-- => %d\n", yysavedepth);
716 }
717 yydictfixed = 0;
718 }
719
720
721
722 #ifdef TEST_LEXER
main(argc,argv)723 int main(argc, argv)
724 int argc;
725 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