]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/ipfilter/tools/lexer.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / ipfilter / tools / lexer.c
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
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
101 static void yyunputc(c)
102         int c;
103 {
104         if (c == '\n')
105                 yylineNum--;
106         yytext[--yypos] = c;
107 }
108
109
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
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
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
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
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
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
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
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
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
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
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
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
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