| %{ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <malloc.h> |
| #include <string.h> |
| #include "ssfilter.h" |
| |
| typedef struct ssfilter * ssfilter_t; |
| |
| #define YYSTYPE ssfilter_t |
| |
| static struct ssfilter * alloc_node(int type, void *pred) |
| { |
| struct ssfilter *n = malloc(sizeof(*n)); |
| if (n == NULL) |
| abort(); |
| n->type = type; |
| n->pred = pred; |
| n->post = NULL; |
| return n; |
| } |
| |
| static char **yy_argv; |
| static int yy_argc; |
| static FILE *yy_fp; |
| static ssfilter_t *yy_ret; |
| static int tok_type = -1; |
| |
| static int yylex(void); |
| |
| static void yyerror(char *s) |
| { |
| fprintf(stderr, "ss: bison bellows (while parsing filter): \"%s!\"", s); |
| } |
| |
| %} |
| |
| %token HOSTCOND DCOND SCOND DPORT SPORT LEQ GEQ NEQ AUTOBOUND DEVCOND DEVNAME MARKMASK FWMARK |
| %left '|' |
| %left '&' |
| %nonassoc '!' |
| |
| %% |
| applet: exprlist |
| { |
| *yy_ret = $1; |
| $$ = $1; |
| } |
| | null |
| ; |
| |
| null: /* NOTHING */ { $$ = NULL; } |
| ; |
| |
| exprlist: expr |
| | exprlist '|' expr |
| { |
| $$ = alloc_node(SSF_OR, $1); |
| $$->post = $3; |
| } |
| | exprlist '&' expr |
| { |
| $$ = alloc_node(SSF_AND, $1); |
| $$->post = $3; |
| } |
| | exprlist expr |
| { |
| $$ = alloc_node(SSF_AND, $1); |
| $$->post = $2; |
| } |
| ; |
| |
| eq: '=' |
| | /* nothing */ |
| ; |
| |
| expr: '(' exprlist ')' |
| { |
| $$ = $2; |
| } |
| | '!' expr |
| { |
| $$ = alloc_node(SSF_NOT, $2); |
| } |
| | DCOND eq HOSTCOND |
| { |
| $$ = alloc_node(SSF_DCOND, $3); |
| } |
| | SCOND eq HOSTCOND |
| { |
| $$ = alloc_node(SSF_SCOND, $3); |
| } |
| | DPORT GEQ HOSTCOND |
| { |
| $$ = alloc_node(SSF_D_GE, $3); |
| } |
| | DPORT LEQ HOSTCOND |
| { |
| $$ = alloc_node(SSF_D_LE, $3); |
| } |
| | DPORT '>' HOSTCOND |
| { |
| $$ = alloc_node(SSF_NOT, alloc_node(SSF_D_LE, $3)); |
| } |
| | DPORT '<' HOSTCOND |
| { |
| $$ = alloc_node(SSF_NOT, alloc_node(SSF_D_GE, $3)); |
| } |
| | DPORT eq HOSTCOND |
| { |
| $$ = alloc_node(SSF_DCOND, $3); |
| } |
| | DPORT NEQ HOSTCOND |
| { |
| $$ = alloc_node(SSF_NOT, alloc_node(SSF_DCOND, $3)); |
| } |
| |
| | SPORT GEQ HOSTCOND |
| { |
| $$ = alloc_node(SSF_S_GE, $3); |
| } |
| | SPORT LEQ HOSTCOND |
| { |
| $$ = alloc_node(SSF_S_LE, $3); |
| } |
| | SPORT '>' HOSTCOND |
| { |
| $$ = alloc_node(SSF_NOT, alloc_node(SSF_S_LE, $3)); |
| } |
| | SPORT '<' HOSTCOND |
| { |
| $$ = alloc_node(SSF_NOT, alloc_node(SSF_S_GE, $3)); |
| } |
| | SPORT eq HOSTCOND |
| { |
| $$ = alloc_node(SSF_SCOND, $3); |
| } |
| | SPORT NEQ HOSTCOND |
| { |
| $$ = alloc_node(SSF_NOT, alloc_node(SSF_SCOND, $3)); |
| } |
| | DEVNAME eq DEVCOND |
| { |
| $$ = alloc_node(SSF_DEVCOND, $3); |
| } |
| | DEVNAME NEQ DEVCOND |
| { |
| $$ = alloc_node(SSF_NOT, alloc_node(SSF_DEVCOND, $3)); |
| } |
| | FWMARK eq MARKMASK |
| { |
| $$ = alloc_node(SSF_MARKMASK, $3); |
| } |
| | FWMARK NEQ MARKMASK |
| { |
| $$ = alloc_node(SSF_NOT, alloc_node(SSF_MARKMASK, $3)); |
| } |
| | AUTOBOUND |
| { |
| $$ = alloc_node(SSF_S_AUTO, NULL); |
| } |
| ; |
| %% |
| |
| static char *get_token_from_line(char **ptr) |
| { |
| char *tok, *cp = *ptr; |
| |
| while (*cp == ' ' || *cp == '\t') cp++; |
| |
| if (*cp == 0) { |
| *ptr = cp; |
| return NULL; |
| } |
| |
| tok = cp; |
| |
| while (*cp != 0 && *cp != ' ' && *cp != '\t') { |
| /* Backslash escapes everything. */ |
| if (*cp == '\\') { |
| char *tp; |
| for (tp = cp; tp != tok; tp--) |
| *tp = *(tp-1); |
| cp++; |
| tok++; |
| if (*cp == 0) |
| break; |
| } |
| cp++; |
| } |
| if (*cp) |
| *cp++ = 0; |
| *ptr = cp; |
| return tok; |
| } |
| |
| int yylex(void) |
| { |
| static char argbuf[1024]; |
| static char *tokptr = argbuf; |
| static int argc; |
| char *curtok; |
| |
| do { |
| while (*tokptr == 0) { |
| tokptr = NULL; |
| if (argc < yy_argc) { |
| tokptr = yy_argv[argc]; |
| argc++; |
| } else if (yy_fp) { |
| while (tokptr == NULL) { |
| size_t len; |
| |
| if (fgets(argbuf, sizeof(argbuf), yy_fp) == NULL) |
| return 0; |
| |
| len = strnlen(argbuf, sizeof(argbuf)); |
| if (len == 0) { |
| fprintf(stderr, "Invalid line\n"); |
| exit(-1); |
| } |
| |
| if (len >= sizeof(argbuf) - 1) { |
| fprintf(stderr, "Too long line in filter\n"); |
| exit(-1); |
| } |
| if (argbuf[len - 1] == '\n') |
| argbuf[len-1] = 0; |
| if (argbuf[0] == '#' || argbuf[0] == '0') |
| continue; |
| tokptr = argbuf; |
| } |
| } else { |
| return 0; |
| } |
| } |
| } while ((curtok = get_token_from_line(&tokptr)) == NULL); |
| |
| if (strcmp(curtok, "!") == 0 || |
| strcmp(curtok, "not") == 0) |
| return '!'; |
| if (strcmp(curtok, "&") == 0 || |
| strcmp(curtok, "&&") == 0 || |
| strcmp(curtok, "and") == 0) |
| return '&'; |
| if (strcmp(curtok, "|") == 0 || |
| strcmp(curtok, "||") == 0 || |
| strcmp(curtok, "or") == 0) |
| return '|'; |
| if (strcmp(curtok, "(") == 0) |
| return '('; |
| if (strcmp(curtok, ")") == 0) |
| return ')'; |
| if (strcmp(curtok, "dst") == 0) { |
| tok_type = DCOND; |
| return DCOND; |
| } |
| if (strcmp(curtok, "src") == 0) { |
| tok_type = SCOND; |
| return SCOND; |
| } |
| if (strcmp(curtok, "dport") == 0) { |
| tok_type = DPORT; |
| return DPORT; |
| } |
| if (strcmp(curtok, "sport") == 0) { |
| tok_type = SPORT; |
| return SPORT; |
| } |
| if (strcmp(curtok, "dev") == 0) { |
| tok_type = DEVNAME; |
| return DEVNAME; |
| } |
| if (strcmp(curtok, "fwmark") == 0) { |
| tok_type = FWMARK; |
| return FWMARK; |
| } |
| if (strcmp(curtok, ">=") == 0 || |
| strcmp(curtok, "ge") == 0 || |
| strcmp(curtok, "geq") == 0) |
| return GEQ; |
| if (strcmp(curtok, "<=") == 0 || |
| strcmp(curtok, "le") == 0 || |
| strcmp(curtok, "leq") == 0) |
| return LEQ; |
| if (strcmp(curtok, "!=") == 0 || |
| strcmp(curtok, "ne") == 0 || |
| strcmp(curtok, "neq") == 0) |
| return NEQ; |
| if (strcmp(curtok, "=") == 0 || |
| strcmp(curtok, "==") == 0 || |
| strcmp(curtok, "eq") == 0) |
| return '='; |
| if (strcmp(curtok, ">") == 0 || |
| strcmp(curtok, "gt") == 0) |
| return '>'; |
| if (strcmp(curtok, "<") == 0 || |
| strcmp(curtok, "lt") == 0) |
| return '<'; |
| if (strcmp(curtok, "autobound") == 0) { |
| tok_type = AUTOBOUND; |
| return AUTOBOUND; |
| } |
| if (tok_type == DEVNAME) { |
| yylval = (void*)parse_devcond(curtok); |
| if (yylval == NULL) { |
| fprintf(stderr, "Cannot parse device.\n"); |
| exit(1); |
| } |
| return DEVCOND; |
| } |
| if (tok_type == FWMARK) { |
| yylval = (void*)parse_markmask(curtok); |
| if (yylval == NULL) { |
| fprintf(stderr, "Cannot parse mark %s.\n", curtok); |
| exit(1); |
| } |
| return MARKMASK; |
| } |
| yylval = (void*)parse_hostcond(curtok, tok_type == SPORT || tok_type == DPORT); |
| if (yylval == NULL) { |
| fprintf(stderr, "Cannot parse dst/src address.\n"); |
| exit(1); |
| } |
| return HOSTCOND; |
| } |
| |
| int ssfilter_parse(struct ssfilter **f, int argc, char **argv, FILE *fp) |
| { |
| yy_argc = argc; |
| yy_argv = argv; |
| yy_fp = fp; |
| yy_ret = f; |
| |
| if (yyparse()) { |
| fprintf(stderr, " Sorry.\n"); |
| return -1; |
| } |
| return 0; |
| } |