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