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(int docont)64 static int 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
yyunputc(int c)101 static void yyunputc(int c)
102 {
103 if (c == '\n')
104 yylineNum--;
105 yytext[--yypos] = c;
106 }
107
108
yyswallow(int last)109 static int yyswallow(int last)
110 {
111 int c;
112
113 while (((c = yygetc(0)) > '\0') && (c != last))
114 ;
115
116 if (c != EOF)
117 yyunputc(c);
118 if (c == last)
119 return (0);
120 return (-1);
121 }
122
123
yytexttochar(void)124 static char *yytexttochar(void)
125 {
126 int i;
127
128 for (i = 0; i < yypos; i++)
129 yychars[i] = (char)(yytext[i] & 0xff);
130 yychars[i] = '\0';
131 return (yychars);
132 }
133
134
yystrtotext(char * str)135 static void yystrtotext(char *str)
136 {
137 int len;
138 char *s;
139
140 len = strlen(str);
141 if (len > YYBUFSIZ)
142 len = YYBUFSIZ;
143
144 for (s = str; *s != '\0' && len > 0; s++, len--)
145 yytext[yylast++] = *s;
146 yytext[yylast] = '\0';
147 }
148
149
yytexttostr(int offset,int max)150 static char *yytexttostr(int offset, int max)
151 {
152 char *str;
153 int i;
154
155 if ((yytext[offset] == '\'' || yytext[offset] == '"') &&
156 (yytext[offset] == yytext[offset + max - 1])) {
157 offset++;
158 max--;
159 }
160
161 if (max > yylast)
162 max = yylast;
163 str = malloc(max + 1);
164 if (str != NULL) {
165 for (i = offset; i < max; i++)
166 str[i - offset] = (char)(yytext[i] & 0xff);
167 str[i - offset] = '\0';
168 }
169 return (str);
170 }
171
172
173 int
yylex(void)174 yylex(void)
175 {
176 int c, n, isbuilding, rval, lnext, nokey = 0;
177 char *name;
178
179 isbuilding = 0;
180 lnext = 0;
181 rval = 0;
182
183 if (yystr != NULL) {
184 free(yystr);
185 yystr = NULL;
186 }
187
188 nextchar:
189 c = yygetc(0);
190 if (yydebug > 1)
191 printf("yygetc = (%x) %c [%*.*s]\n", c, c, yypos, yypos,
192 yytexttochar());
193
194 switch (c) {
195 case '\n' :
196 lnext = 0;
197 nokey = 0;
198 /* FALLTHROUGH */
199 case '\t' :
200 case '\r' :
201 case ' ' :
202 if (isbuilding == 1) {
203 yyunputc(c);
204 goto done;
205 }
206 if (yylast > yypos) {
207 bcopy(yytext + yypos, yytext,
208 sizeof (yytext[0]) * (yylast - yypos + 1));
209 }
210 yylast -= yypos;
211 yypos = 0;
212 lnext = 0;
213 nokey = 0;
214 goto nextchar;
215
216 case '\\' :
217 if (lnext == 0) {
218 lnext = 1;
219 if (yylast == yypos) {
220 yylast--;
221 yypos--;
222 } else
223 yypos--;
224 if (yypos == 0)
225 nokey = 1;
226 goto nextchar;
227 }
228 break;
229 }
230
231 if (lnext == 1) {
232 lnext = 0;
233 if ((isbuilding == 0) && !ISALNUM(c)) {
234 return (c);
235 }
236 goto nextchar;
237 }
238
239 switch (c) {
240 case '#' :
241 if (isbuilding == 1) {
242 yyunputc(c);
243 goto done;
244 }
245 yyswallow('\n');
246 rval = YY_COMMENT;
247 goto done;
248
249 case '$' :
250 if (isbuilding == 1) {
251 yyunputc(c);
252 goto done;
253 }
254 n = yygetc(0);
255 if (n == '{') {
256 if (yyswallow('}') == -1) {
257 rval = -2;
258 goto done;
259 }
260 (void) yygetc(0);
261 } else {
262 if (!ISALPHA(n)) {
263 yyunputc(n);
264 break;
265 }
266 do {
267 n = yygetc(1);
268 } while (ISALPHA(n) || ISDIGIT(n) || n == '_');
269 yyunputc(n);
270 }
271
272 name = yytexttostr(1, yypos); /* skip $ */
273
274 if (name != NULL) {
275 string_val = get_variable(name, NULL, yylineNum);
276 free(name);
277 if (string_val != NULL) {
278 name = yytexttostr(yypos, yylast);
279 if (name != NULL) {
280 yypos = 0;
281 yylast = 0;
282 yystrtotext(string_val);
283 yystrtotext(name);
284 free(string_val);
285 free(name);
286 goto nextchar;
287 }
288 free(string_val);
289 }
290 }
291 break;
292
293 case '\'':
294 case '"' :
295 if (isbuilding == 1) {
296 goto done;
297 }
298 do {
299 n = yygetc(1);
300 if (n == EOF || n == TOOLONG) {
301 rval = -2;
302 goto done;
303 }
304 if (n == '\n') {
305 yyunputc(' ');
306 yypos++;
307 }
308 } while (n != c);
309 rval = YY_STR;
310 goto done;
311 /* NOTREACHED */
312
313 case EOF :
314 yylineNum = 1;
315 yypos = 0;
316 yylast = -1;
317 yyexpectaddr = 0;
318 yybreakondot = 0;
319 yyvarnext = 0;
320 yytokentype = 0;
321 return (0);
322 }
323
324 if (strchr("=,/;{}()@", c) != NULL) {
325 if (isbuilding == 1) {
326 yyunputc(c);
327 goto done;
328 }
329 rval = c;
330 goto done;
331 } else if (c == '.') {
332 if (isbuilding == 0) {
333 rval = c;
334 goto done;
335 }
336 if (yybreakondot != 0) {
337 yyunputc(c);
338 goto done;
339 }
340 }
341
342 switch (c) {
343 case '-' :
344 if (yyexpectaddr)
345 break;
346 if (isbuilding == 1)
347 break;
348 n = yygetc(0);
349 if (n == '>') {
350 isbuilding = 1;
351 goto done;
352 }
353 yyunputc(n);
354 rval = '-';
355 goto done;
356
357 case '!' :
358 if (isbuilding == 1) {
359 yyunputc(c);
360 goto done;
361 }
362 n = yygetc(0);
363 if (n == '=') {
364 rval = YY_CMP_NE;
365 goto done;
366 }
367 yyunputc(n);
368 rval = '!';
369 goto done;
370
371 case '<' :
372 if (yyexpectaddr)
373 break;
374 if (isbuilding == 1) {
375 yyunputc(c);
376 goto done;
377 }
378 n = yygetc(0);
379 if (n == '=') {
380 rval = YY_CMP_LE;
381 goto done;
382 }
383 if (n == '>') {
384 rval = YY_RANGE_OUT;
385 goto done;
386 }
387 yyunputc(n);
388 rval = YY_CMP_LT;
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_GE;
401 goto done;
402 }
403 if (n == '<') {
404 rval = YY_RANGE_IN;
405 goto done;
406 }
407 yyunputc(n);
408 rval = YY_CMP_GT;
409 goto done;
410 }
411
412 /*
413 * Now for the reason this is here...IPv6 address parsing.
414 * The longest string we can expect is of this form:
415 * 0000:0000:0000:0000:0000:0000:000.000.000.000
416 * not:
417 * 0000:0000:0000:0000:0000:0000:0000:0000
418 */
419 #ifdef USE_INET6
420 if (isbuilding == 0 && (ishex(c) || c == ':')) {
421 char ipv6buf[45 + 1], *s, oc;
422 int start;
423
424 start = yypos;
425 s = ipv6buf;
426 oc = c;
427
428 /*
429 * Perhaps we should implement stricter controls on what we
430 * swallow up here, but surely it would just be duplicating
431 * the code in inet_pton() anyway.
432 */
433 do {
434 *s++ = c;
435 c = yygetc(1);
436 } while ((ishex(c) || c == ':' || c == '.') &&
437 (s - ipv6buf < 46));
438 yyunputc(c);
439 *s = '\0';
440
441 if (inet_pton(AF_INET6, ipv6buf, &yylval.ip6) == 1) {
442 rval = YY_IPV6;
443 yyexpectaddr = 0;
444 goto done;
445 }
446 yypos = start;
447 c = oc;
448 }
449 #endif
450
451 if (c == ':') {
452 if (isbuilding == 1) {
453 yyunputc(c);
454 goto done;
455 }
456 rval = ':';
457 goto done;
458 }
459
460 if (isbuilding == 0 && c == '0') {
461 n = yygetc(0);
462 if (n == 'x') {
463 do {
464 n = yygetc(1);
465 } while (ishex(n));
466 yyunputc(n);
467 rval = YY_HEX;
468 goto done;
469 }
470 yyunputc(n);
471 }
472
473 /*
474 * No negative numbers with leading - sign..
475 */
476 if (isbuilding == 0 && ISDIGIT(c)) {
477 do {
478 n = yygetc(1);
479 } while (ISDIGIT(n));
480 yyunputc(n);
481 rval = YY_NUMBER;
482 goto done;
483 }
484
485 isbuilding = 1;
486 goto nextchar;
487
488 done:
489 yystr = yytexttostr(0, yypos);
490
491 if (yydebug)
492 printf("isbuilding %d yyvarnext %d nokey %d\n",
493 isbuilding, yyvarnext, nokey);
494 if (isbuilding == 1) {
495 wordtab_t *w;
496
497 w = NULL;
498 isbuilding = 0;
499
500 if ((yyvarnext == 0) && (nokey == 0)) {
501 w = yyfindkey(yystr);
502 if (w == NULL && yywordtab != NULL) {
503 yyresetdict();
504 w = yyfindkey(yystr);
505 }
506 } else
507 yyvarnext = 0;
508 if (w != NULL)
509 rval = w->w_value;
510 else
511 rval = YY_STR;
512 }
513
514 if (rval == YY_STR && yysavedepth > 0)
515 yyresetdict();
516
517 yytokentype = rval;
518
519 if (yydebug)
520 printf("lexed(%s) [%d,%d,%d] => %d @%d\n", yystr, string_start,
521 string_end, pos, rval, yysavedepth);
522
523 switch (rval) {
524 case YY_NUMBER :
525 sscanf(yystr, "%u", &yylval.num);
526 break;
527
528 case YY_HEX :
529 sscanf(yystr, "0x%x", (uint_t *)&yylval.num);
530 break;
531
532 case YY_STR :
533 yylval.str = strdup(yystr);
534 break;
535
536 default :
537 break;
538 }
539
540 if (yylast > 0) {
541 bcopy(yytext + yypos, yytext,
542 sizeof (yytext[0]) * (yylast - yypos + 1));
543 yylast -= yypos;
544 yypos = 0;
545 }
546
547 return (rval);
548 }
549
550
yyfindkey(char * key)551 static wordtab_t *yyfindkey(char *key)
552 {
553 wordtab_t *w;
554
555 if (yywordtab == NULL)
556 return (NULL);
557
558 for (w = yywordtab; w->w_word != 0; w++)
559 if (strcasecmp(key, w->w_word) == 0)
560 return (w);
561 return (NULL);
562 }
563
564
565 char *
yykeytostr(int num)566 yykeytostr(int num)
567 {
568 wordtab_t *w;
569
570 if (yywordtab == NULL)
571 return ("<unknown>");
572
573 for (w = yywordtab; w->w_word; w++)
574 if (w->w_value == num)
575 return (w->w_word);
576 return ("<unknown>");
577 }
578
579
580 wordtab_t *
yysettab(wordtab_t * words)581 yysettab(wordtab_t *words)
582 {
583 wordtab_t *save;
584
585 save = yywordtab;
586 yywordtab = words;
587 return (save);
588 }
589
590
591 int
yyerror(const char * msg)592 yyerror(const char *msg)
593 {
594 char *txt, letter[2];
595 int freetxt = 0;
596
597 if (yytokentype < 256) {
598 letter[0] = yytokentype;
599 letter[1] = '\0';
600 txt = letter;
601 } else if (yytokentype == YY_STR || yytokentype == YY_HEX ||
602 yytokentype == YY_NUMBER) {
603 if (yystr == NULL) {
604 txt = yytexttostr(yypos, YYBUFSIZ);
605 if (txt == NULL) {
606 fprintf(stderr, "sorry, out of memory,"
607 " bailing out\n");
608 exit(1);
609 }
610 freetxt = 1;
611 } else
612 txt = yystr;
613 } else {
614 txt = yykeytostr(yytokentype);
615 if (txt == NULL) {
616 fprintf(stderr, "sorry, out of memory,"
617 " bailing out\n");
618 exit(1);
619 }
620 }
621 fprintf(stderr, "%s error at \"%s\", line %d\n", msg, txt, yylineNum);
622 if (freetxt == 1)
623 free(txt);
624 exit(1);
625 }
626
627
628 void
yysetdict(wordtab_t * newdict)629 yysetdict(wordtab_t *newdict)
630 {
631 if (yysavedepth == sizeof (yysavewords) / sizeof (yysavewords[0])) {
632 fprintf(stderr, "%d: at maximum dictionary depth\n",
633 yylineNum);
634 return;
635 }
636
637 yysavewords[yysavedepth++] = yysettab(newdict);
638 if (yydebug)
639 printf("yysavedepth++ => %d\n", yysavedepth);
640 }
641
642 void
yyresetdict(void)643 yyresetdict(void)
644 {
645 if (yydebug)
646 printf("yyresetdict(%d)\n", yysavedepth);
647 if (yysavedepth > 0) {
648 yysettab(yysavewords[--yysavedepth]);
649 if (yydebug)
650 printf("yysavedepth-- => %d\n", yysavedepth);
651 }
652 }
653
654
655
656 #ifdef TEST_LEXER
657 int
main(int argc,char * argv[])658 main(int argc, char *argv[])
659 {
660 int n;
661
662 yyin = stdin;
663
664 while ((n = yylex()) != 0)
665 printf("%d.n = %d [%s] %d %d\n",
666 yylineNum, n, yystr, yypos, yylast);
667 }
668 #endif
669