|  | /* | 
|  | * Copyright (C) 2002-2006 by Darren Reed. | 
|  | * | 
|  | * See the IPFILTER.LICENCE file for details on licencing. | 
|  | */ | 
|  | #include <ctype.h> | 
|  | #include "ipf.h" | 
|  | #ifdef	IPFILTER_SCAN | 
|  | # include "netinet/ip_scan.h" | 
|  | #endif | 
|  | #include <sys/ioctl.h> | 
|  | #include <syslog.h> | 
|  | #ifdef	TEST_LEXER | 
|  | # define	NO_YACC | 
|  | union	{ | 
|  | int		num; | 
|  | char		*str; | 
|  | struct in_addr	ipa; | 
|  | i6addr_t	ip6; | 
|  | } yylval; | 
|  | #endif | 
|  | #include "lexer.h" | 
|  | #include "y.tab.h" | 
|  |  | 
|  | FILE *yyin; | 
|  |  | 
|  | #define	ishex(c)	(ISDIGIT(c) || ((c) >= 'a' && (c) <= 'f') || \ | 
|  | ((c) >= 'A' && (c) <= 'F')) | 
|  | #define	TOOLONG		-3 | 
|  |  | 
|  | extern int	string_start; | 
|  | extern int	string_end; | 
|  | extern char	*string_val; | 
|  | extern int	pos; | 
|  | extern int	yydebug; | 
|  |  | 
|  | char		*yystr = NULL; | 
|  | int		yytext[YYBUFSIZ+1]; | 
|  | char		yychars[YYBUFSIZ+1]; | 
|  | int		yylineNum = 1; | 
|  | int		yypos = 0; | 
|  | int		yylast = -1; | 
|  | int		yyexpectaddr = 0; | 
|  | int		yybreakondot = 0; | 
|  | int		yyvarnext = 0; | 
|  | int		yytokentype = 0; | 
|  | wordtab_t	*yywordtab = NULL; | 
|  | int		yysavedepth = 0; | 
|  | wordtab_t	*yysavewords[30]; | 
|  |  | 
|  |  | 
|  | static	wordtab_t	*yyfindkey __P((char *)); | 
|  | static	int		yygetc __P((int)); | 
|  | static	void		yyunputc __P((int)); | 
|  | static	int		yyswallow __P((int)); | 
|  | static	char		*yytexttostr __P((int, int)); | 
|  | static	void		yystrtotext __P((char *)); | 
|  | static	char		*yytexttochar __P((void)); | 
|  |  | 
|  | static int yygetc(docont) | 
|  | int docont; | 
|  | { | 
|  | int c; | 
|  |  | 
|  | if (yypos < yylast) { | 
|  | c = yytext[yypos++]; | 
|  | if (c == '\n') | 
|  | yylineNum++; | 
|  | return c; | 
|  | } | 
|  |  | 
|  | if (yypos == YYBUFSIZ) | 
|  | return TOOLONG; | 
|  |  | 
|  | if (pos >= string_start && pos <= string_end) { | 
|  | c = string_val[pos - string_start]; | 
|  | yypos++; | 
|  | } else { | 
|  | c = fgetc(yyin); | 
|  | if (docont && (c == '\\')) { | 
|  | c = fgetc(yyin); | 
|  | if (c == '\n') { | 
|  | yylineNum++; | 
|  | c = fgetc(yyin); | 
|  | } | 
|  | } | 
|  | } | 
|  | if (c == '\n') | 
|  | yylineNum++; | 
|  | yytext[yypos++] = c; | 
|  | yylast = yypos; | 
|  | yytext[yypos] = '\0'; | 
|  |  | 
|  | return c; | 
|  | } | 
|  |  | 
|  |  | 
|  | static void yyunputc(c) | 
|  | int c; | 
|  | { | 
|  | if (c == '\n') | 
|  | yylineNum--; | 
|  | yytext[--yypos] = c; | 
|  | } | 
|  |  | 
|  |  | 
|  | static int yyswallow(last) | 
|  | int last; | 
|  | { | 
|  | int c; | 
|  |  | 
|  | while (((c = yygetc(0)) > '\0') && (c != last)) | 
|  | ; | 
|  |  | 
|  | if (c != EOF) | 
|  | yyunputc(c); | 
|  | if (c == last) | 
|  | return 0; | 
|  | return -1; | 
|  | } | 
|  |  | 
|  |  | 
|  | static char *yytexttochar() | 
|  | { | 
|  | int i; | 
|  |  | 
|  | for (i = 0; i < yypos; i++) | 
|  | yychars[i] = (char)(yytext[i] & 0xff); | 
|  | yychars[i] = '\0'; | 
|  | return yychars; | 
|  | } | 
|  |  | 
|  |  | 
|  | static void yystrtotext(str) | 
|  | char *str; | 
|  | { | 
|  | int len; | 
|  | char *s; | 
|  |  | 
|  | len = strlen(str); | 
|  | if (len > YYBUFSIZ) | 
|  | len = YYBUFSIZ; | 
|  |  | 
|  | for (s = str; *s != '\0' && len > 0; s++, len--) | 
|  | yytext[yylast++] = *s; | 
|  | yytext[yylast] = '\0'; | 
|  | } | 
|  |  | 
|  |  | 
|  | static char *yytexttostr(offset, max) | 
|  | int offset, max; | 
|  | { | 
|  | char *str; | 
|  | int i; | 
|  |  | 
|  | if ((yytext[offset] == '\'' || yytext[offset] == '"') && | 
|  | (yytext[offset] == yytext[offset + max - 1])) { | 
|  | offset++; | 
|  | max--; | 
|  | } | 
|  |  | 
|  | if (max > yylast) | 
|  | max = yylast; | 
|  | str = malloc(max + 1); | 
|  | if (str != NULL) { | 
|  | for (i = offset; i < max; i++) | 
|  | str[i - offset] = (char)(yytext[i] & 0xff); | 
|  | str[i - offset] = '\0'; | 
|  | } | 
|  | return str; | 
|  | } | 
|  |  | 
|  |  | 
|  | int yylex() | 
|  | { | 
|  | int c, n, isbuilding, rval, lnext, nokey = 0; | 
|  | char *name; | 
|  |  | 
|  | isbuilding = 0; | 
|  | lnext = 0; | 
|  | rval = 0; | 
|  |  | 
|  | if (yystr != NULL) { | 
|  | free(yystr); | 
|  | yystr = NULL; | 
|  | } | 
|  |  | 
|  | nextchar: | 
|  | c = yygetc(0); | 
|  | if (yydebug > 1) | 
|  | printf("yygetc = (%x) %c [%*.*s]\n", c, c, yypos, yypos, yytexttochar()); | 
|  |  | 
|  | switch (c) | 
|  | { | 
|  | case '\n' : | 
|  | lnext = 0; | 
|  | nokey = 0; | 
|  | case '\t' : | 
|  | case '\r' : | 
|  | case ' ' : | 
|  | if (isbuilding == 1) { | 
|  | yyunputc(c); | 
|  | goto done; | 
|  | } | 
|  | if (yylast > yypos) { | 
|  | bcopy(yytext + yypos, yytext, | 
|  | sizeof(yytext[0]) * (yylast - yypos + 1)); | 
|  | } | 
|  | yylast -= yypos; | 
|  | yypos = 0; | 
|  | lnext = 0; | 
|  | nokey = 0; | 
|  | goto nextchar; | 
|  |  | 
|  | case '\\' : | 
|  | if (lnext == 0) { | 
|  | lnext = 1; | 
|  | if (yylast == yypos) { | 
|  | yylast--; | 
|  | yypos--; | 
|  | } else | 
|  | yypos--; | 
|  | if (yypos == 0) | 
|  | nokey = 1; | 
|  | goto nextchar; | 
|  | } | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (lnext == 1) { | 
|  | lnext = 0; | 
|  | if ((isbuilding == 0) && !ISALNUM(c)) { | 
|  | return c; | 
|  | } | 
|  | goto nextchar; | 
|  | } | 
|  |  | 
|  | switch (c) | 
|  | { | 
|  | case '#' : | 
|  | if (isbuilding == 1) { | 
|  | yyunputc(c); | 
|  | goto done; | 
|  | } | 
|  | yyswallow('\n'); | 
|  | rval = YY_COMMENT; | 
|  | goto nextchar; | 
|  |  | 
|  | case '$' : | 
|  | if (isbuilding == 1) { | 
|  | yyunputc(c); | 
|  | goto done; | 
|  | } | 
|  | n = yygetc(0); | 
|  | if (n == '{') { | 
|  | if (yyswallow('}') == -1) { | 
|  | rval = -2; | 
|  | goto done; | 
|  | } | 
|  | (void) yygetc(0); | 
|  | } else { | 
|  | if (!ISALPHA(n)) { | 
|  | yyunputc(n); | 
|  | break; | 
|  | } | 
|  | do { | 
|  | n = yygetc(1); | 
|  | } while (ISALPHA(n) || ISDIGIT(n) || n == '_'); | 
|  | yyunputc(n); | 
|  | } | 
|  |  | 
|  | name = yytexttostr(1, yypos);		/* skip $ */ | 
|  |  | 
|  | if (name != NULL) { | 
|  | string_val = get_variable(name, NULL, yylineNum); | 
|  | free(name); | 
|  | if (string_val != NULL) { | 
|  | name = yytexttostr(yypos, yylast); | 
|  | if (name != NULL) { | 
|  | yypos = 0; | 
|  | yylast = 0; | 
|  | yystrtotext(string_val); | 
|  | yystrtotext(name); | 
|  | free(string_val); | 
|  | free(name); | 
|  | goto nextchar; | 
|  | } | 
|  | free(string_val); | 
|  | } | 
|  | } | 
|  | break; | 
|  |  | 
|  | case '\'': | 
|  | case '"' : | 
|  | if (isbuilding == 1) { | 
|  | goto done; | 
|  | } | 
|  | do { | 
|  | n = yygetc(1); | 
|  | if (n == EOF || n == TOOLONG) { | 
|  | rval = -2; | 
|  | goto done; | 
|  | } | 
|  | if (n == '\n') { | 
|  | yyunputc(' '); | 
|  | yypos++; | 
|  | } | 
|  | } while (n != c); | 
|  | rval = YY_STR; | 
|  | goto done; | 
|  | /* NOTREACHED */ | 
|  |  | 
|  | case EOF : | 
|  | yylineNum = 1; | 
|  | yypos = 0; | 
|  | yylast = -1; | 
|  | yyexpectaddr = 0; | 
|  | yybreakondot = 0; | 
|  | yyvarnext = 0; | 
|  | yytokentype = 0; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | if (strchr("=,/;{}()@", c) != NULL) { | 
|  | if (isbuilding == 1) { | 
|  | yyunputc(c); | 
|  | goto done; | 
|  | } | 
|  | rval = c; | 
|  | goto done; | 
|  | } else if (c == '.') { | 
|  | if (isbuilding == 0) { | 
|  | rval = c; | 
|  | goto done; | 
|  | } | 
|  | if (yybreakondot != 0) { | 
|  | yyunputc(c); | 
|  | goto done; | 
|  | } | 
|  | } | 
|  |  | 
|  | switch (c) | 
|  | { | 
|  | case '-' : | 
|  | if (yyexpectaddr) | 
|  | break; | 
|  | if (isbuilding == 1) | 
|  | break; | 
|  | n = yygetc(0); | 
|  | if (n == '>') { | 
|  | isbuilding = 1; | 
|  | goto done; | 
|  | } | 
|  | yyunputc(n); | 
|  | rval = '-'; | 
|  | goto done; | 
|  |  | 
|  | case '!' : | 
|  | if (isbuilding == 1) { | 
|  | yyunputc(c); | 
|  | goto done; | 
|  | } | 
|  | n = yygetc(0); | 
|  | if (n == '=') { | 
|  | rval = YY_CMP_NE; | 
|  | goto done; | 
|  | } | 
|  | yyunputc(n); | 
|  | rval = '!'; | 
|  | goto done; | 
|  |  | 
|  | case '<' : | 
|  | if (yyexpectaddr) | 
|  | break; | 
|  | if (isbuilding == 1) { | 
|  | yyunputc(c); | 
|  | goto done; | 
|  | } | 
|  | n = yygetc(0); | 
|  | if (n == '=') { | 
|  | rval = YY_CMP_LE; | 
|  | goto done; | 
|  | } | 
|  | if (n == '>') { | 
|  | rval = YY_RANGE_OUT; | 
|  | goto done; | 
|  | } | 
|  | yyunputc(n); | 
|  | rval = YY_CMP_LT; | 
|  | goto done; | 
|  |  | 
|  | case '>' : | 
|  | if (yyexpectaddr) | 
|  | break; | 
|  | if (isbuilding == 1) { | 
|  | yyunputc(c); | 
|  | goto done; | 
|  | } | 
|  | n = yygetc(0); | 
|  | if (n == '=') { | 
|  | rval = YY_CMP_GE; | 
|  | goto done; | 
|  | } | 
|  | if (n == '<') { | 
|  | rval = YY_RANGE_IN; | 
|  | goto done; | 
|  | } | 
|  | yyunputc(n); | 
|  | rval = YY_CMP_GT; | 
|  | goto done; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Now for the reason this is here...IPv6 address parsing. | 
|  | * The longest string we can expect is of this form: | 
|  | * 0000:0000:0000:0000:0000:0000:000.000.000.000 | 
|  | * not: | 
|  | * 0000:0000:0000:0000:0000:0000:0000:0000 | 
|  | */ | 
|  | #ifdef	USE_INET6 | 
|  | if (yyexpectaddr == 1 && isbuilding == 0 && (ishex(c) || c == ':')) { | 
|  | char ipv6buf[45 + 1], *s, oc; | 
|  | int start; | 
|  |  | 
|  | start = yypos; | 
|  | s = ipv6buf; | 
|  | oc = c; | 
|  |  | 
|  | /* | 
|  | * Perhaps we should implement stricter controls on what we | 
|  | * swallow up here, but surely it would just be duplicating | 
|  | * the code in inet_pton() anyway. | 
|  | */ | 
|  | do { | 
|  | *s++ = c; | 
|  | c = yygetc(1); | 
|  | } while ((ishex(c) || c == ':' || c == '.') && | 
|  | (s - ipv6buf < 46)); | 
|  | yyunputc(c); | 
|  | *s = '\0'; | 
|  |  | 
|  | if (inet_pton(AF_INET6, ipv6buf, &yylval.ip6) == 1) { | 
|  | rval = YY_IPV6; | 
|  | yyexpectaddr = 0; | 
|  | goto done; | 
|  | } | 
|  | yypos = start; | 
|  | c = oc; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | if (c == ':') { | 
|  | if (isbuilding == 1) { | 
|  | yyunputc(c); | 
|  | goto done; | 
|  | } | 
|  | rval = ':'; | 
|  | goto done; | 
|  | } | 
|  |  | 
|  | if (isbuilding == 0 && c == '0') { | 
|  | n = yygetc(0); | 
|  | if (n == 'x') { | 
|  | do { | 
|  | n = yygetc(1); | 
|  | } while (ishex(n)); | 
|  | yyunputc(n); | 
|  | rval = YY_HEX; | 
|  | goto done; | 
|  | } | 
|  | yyunputc(n); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * No negative numbers with leading - sign.. | 
|  | */ | 
|  | if (isbuilding == 0 && ISDIGIT(c)) { | 
|  | do { | 
|  | n = yygetc(1); | 
|  | } while (ISDIGIT(n)); | 
|  | yyunputc(n); | 
|  | rval = YY_NUMBER; | 
|  | goto done; | 
|  | } | 
|  |  | 
|  | isbuilding = 1; | 
|  | goto nextchar; | 
|  |  | 
|  | done: | 
|  | yystr = yytexttostr(0, yypos); | 
|  |  | 
|  | if (yydebug) | 
|  | printf("isbuilding %d yyvarnext %d nokey %d\n", | 
|  | isbuilding, yyvarnext, nokey); | 
|  | if (isbuilding == 1) { | 
|  | wordtab_t *w; | 
|  |  | 
|  | w = NULL; | 
|  | isbuilding = 0; | 
|  |  | 
|  | if ((yyvarnext == 0) && (nokey == 0)) { | 
|  | w = yyfindkey(yystr); | 
|  | if (w == NULL && yywordtab != NULL) { | 
|  | yyresetdict(); | 
|  | w = yyfindkey(yystr); | 
|  | } | 
|  | } else | 
|  | yyvarnext = 0; | 
|  | if (w != NULL) | 
|  | rval = w->w_value; | 
|  | else | 
|  | rval = YY_STR; | 
|  | } | 
|  |  | 
|  | if (rval == YY_STR && yysavedepth > 0) | 
|  | yyresetdict(); | 
|  |  | 
|  | yytokentype = rval; | 
|  |  | 
|  | if (yydebug) | 
|  | printf("lexed(%s) [%d,%d,%d] => %d @%d\n", yystr, string_start, | 
|  | string_end, pos, rval, yysavedepth); | 
|  |  | 
|  | switch (rval) | 
|  | { | 
|  | case YY_NUMBER : | 
|  | sscanf(yystr, "%u", &yylval.num); | 
|  | break; | 
|  |  | 
|  | case YY_HEX : | 
|  | sscanf(yystr, "0x%x", (u_int *)&yylval.num); | 
|  | break; | 
|  |  | 
|  | case YY_STR : | 
|  | yylval.str = strdup(yystr); | 
|  | break; | 
|  |  | 
|  | default : | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (yylast > 0) { | 
|  | bcopy(yytext + yypos, yytext, | 
|  | sizeof(yytext[0]) * (yylast - yypos + 1)); | 
|  | yylast -= yypos; | 
|  | yypos = 0; | 
|  | } | 
|  |  | 
|  | return rval; | 
|  | } | 
|  |  | 
|  |  | 
|  | static wordtab_t *yyfindkey(key) | 
|  | char *key; | 
|  | { | 
|  | wordtab_t *w; | 
|  |  | 
|  | if (yywordtab == NULL) | 
|  | return NULL; | 
|  |  | 
|  | for (w = yywordtab; w->w_word != 0; w++) | 
|  | if (strcasecmp(key, w->w_word) == 0) | 
|  | return w; | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  |  | 
|  | char *yykeytostr(num) | 
|  | int num; | 
|  | { | 
|  | wordtab_t *w; | 
|  |  | 
|  | if (yywordtab == NULL) | 
|  | return "<unknown>"; | 
|  |  | 
|  | for (w = yywordtab; w->w_word; w++) | 
|  | if (w->w_value == num) | 
|  | return w->w_word; | 
|  | return "<unknown>"; | 
|  | } | 
|  |  | 
|  |  | 
|  | wordtab_t *yysettab(words) | 
|  | wordtab_t *words; | 
|  | { | 
|  | wordtab_t *save; | 
|  |  | 
|  | save = yywordtab; | 
|  | yywordtab = words; | 
|  | return save; | 
|  | } | 
|  |  | 
|  |  | 
|  | void yyerror(msg) | 
|  | char *msg; | 
|  | { | 
|  | char *txt, letter[2]; | 
|  | int freetxt = 0; | 
|  |  | 
|  | if (yytokentype < 256) { | 
|  | letter[0] = yytokentype; | 
|  | letter[1] = '\0'; | 
|  | txt =  letter; | 
|  | } else if (yytokentype == YY_STR || yytokentype == YY_HEX || | 
|  | yytokentype == YY_NUMBER) { | 
|  | if (yystr == NULL) { | 
|  | txt = yytexttostr(yypos, YYBUFSIZ); | 
|  | freetxt = 1; | 
|  | } else | 
|  | txt = yystr; | 
|  | } else { | 
|  | txt = yykeytostr(yytokentype); | 
|  | } | 
|  | fprintf(stderr, "%s error at \"%s\", line %d\n", msg, txt, yylineNum); | 
|  | if (freetxt == 1) | 
|  | free(txt); | 
|  | exit(1); | 
|  | } | 
|  |  | 
|  |  | 
|  | void yysetdict(newdict) | 
|  | wordtab_t *newdict; | 
|  | { | 
|  | if (yysavedepth == sizeof(yysavewords)/sizeof(yysavewords[0])) { | 
|  | fprintf(stderr, "%d: at maximum dictionary depth\n", | 
|  | yylineNum); | 
|  | return; | 
|  | } | 
|  |  | 
|  | yysavewords[yysavedepth++] = yysettab(newdict); | 
|  | if (yydebug) | 
|  | printf("yysavedepth++ => %d\n", yysavedepth); | 
|  | } | 
|  |  | 
|  | void yyresetdict() | 
|  | { | 
|  | if (yydebug) | 
|  | printf("yyresetdict(%d)\n", yysavedepth); | 
|  | if (yysavedepth > 0) { | 
|  | yysettab(yysavewords[--yysavedepth]); | 
|  | if (yydebug) | 
|  | printf("yysavedepth-- => %d\n", yysavedepth); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  | #ifdef	TEST_LEXER | 
|  | int main(argc, argv) | 
|  | int argc; | 
|  | char *argv[]; | 
|  | { | 
|  | int n; | 
|  |  | 
|  | yyin = stdin; | 
|  |  | 
|  | while ((n = yylex()) != 0) | 
|  | printf("%d.n = %d [%s] %d %d\n", | 
|  | yylineNum, n, yystr, yypos, yylast); | 
|  | } | 
|  | #endif |