blob: 2e9d9626a30ae70fde510749d03c19fee3cfcedf [file] [log] [blame]
%{
#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 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
%left '|'
%left '&'
%nonassoc '!'
%%
applet: null expr
{
*yy_ret = $2;
$$ = $2;
}
| null
;
null: /* NOTHING */ { $$ = NULL; }
;
expr: DCOND HOSTCOND
{
$$ = alloc_node(SSF_DCOND, $2);
}
| SCOND HOSTCOND
{
$$ = alloc_node(SSF_SCOND, $2);
}
| 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 '=' 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 '=' HOSTCOND
{
$$ = alloc_node(SSF_SCOND, $3);
}
| SPORT NEQ HOSTCOND
{
$$ = alloc_node(SSF_NOT, alloc_node(SSF_SCOND, $3));
}
| AUTOBOUND
{
$$ = alloc_node(SSF_S_AUTO, NULL);
}
| expr '|' expr
{
$$ = alloc_node(SSF_OR, $1);
$$->post = $3;
}
| expr expr
{
$$ = alloc_node(SSF_AND, $1);
$$->post = $2;
}
| expr '&' expr
{
$$ = alloc_node(SSF_AND, $1);
$$->post = $3;
}
| '!' expr
{
$$ = alloc_node(SSF_NOT, $2);
}
| '(' expr ')'
{
$$ = $2;
}
;
%%
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) {
if (fgets(argbuf, sizeof(argbuf)-1, yy_fp) == NULL)
return 0;
argbuf[sizeof(argbuf)-1] = 0;
if (strlen(argbuf) == sizeof(argbuf) - 1) {
fprintf(stderr, "Too long line in filter");
exit(-1);
}
if (argbuf[strlen(argbuf)-1] == '\n')
argbuf[strlen(argbuf)-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)
return DCOND;
if (strcmp(curtok, "src") == 0)
return SCOND;
if (strcmp(curtok, "dport") == 0)
return DPORT;
if (strcmp(curtok, "sport") == 0)
return SPORT;
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)
return AUTOBOUND;
yylval = (void*)parse_hostcond(curtok);
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;
}