%{
#include <stdio.h>
+#include <stdlib.h>
#include <malloc.h>
#include <string.h>
#include "ssfilter.h"
static struct ssfilter * alloc_node(int type, void *pred)
{
- struct ssfilter *n = malloc(sizeof(*n));
+ struct ssfilter *n;
+
+ if (!ssfilter_is_supported(type)) {
+ fprintf(stderr, "It looks like such filter is not supported! Too old kernel?\n");
+ exit(-1);
+ }
+
+ n = malloc(sizeof(*n));
if (n == NULL)
abort();
n->type = type;
static int yy_argc;
static FILE *yy_fp;
static ssfilter_t *yy_ret;
+static int tok_type = -1;
static int yylex(void);
%}
-%token HOSTCOND DCOND SCOND DPORT SPORT LEQ GEQ NEQ AUTOBOUND
+%token HOSTCOND DCOND SCOND DPORT SPORT LEQ GEQ NEQ AUTOBOUND DEVCOND DEVNAME MARKMASK FWMARK CGROUPCOND CGROUPPATH
%left '|'
%left '&'
%nonassoc '!'
%%
-applet: null expr
+applet: exprlist
{
- *yy_ret = $2;
- $$ = $2;
+ *yy_ret = $1;
+ $$ = $1;
}
| null
;
+
null: /* NOTHING */ { $$ = NULL; }
;
-expr: DCOND HOSTCOND
+
+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, $2);
+ $$ = alloc_node(SSF_DCOND, $3);
}
- | SCOND HOSTCOND
- {
- $$ = alloc_node(SSF_SCOND, $2);
+ | SCOND eq HOSTCOND
+ {
+ $$ = alloc_node(SSF_SCOND, $3);
}
| DPORT GEQ HOSTCOND
{
{
$$ = alloc_node(SSF_NOT, alloc_node(SSF_D_GE, $3));
}
- | DPORT '=' HOSTCOND
+ | DPORT eq HOSTCOND
{
$$ = alloc_node(SSF_DCOND, $3);
}
{
$$ = alloc_node(SSF_NOT, alloc_node(SSF_S_GE, $3));
}
- | SPORT '=' HOSTCOND
+ | SPORT eq HOSTCOND
{
$$ = alloc_node(SSF_SCOND, $3);
}
{
$$ = alloc_node(SSF_NOT, alloc_node(SSF_SCOND, $3));
}
-
- | AUTOBOUND
+ | DEVNAME eq DEVCOND
{
- $$ = alloc_node(SSF_S_AUTO, NULL);
+ $$ = alloc_node(SSF_DEVCOND, $3);
}
- | expr '|' expr
+ | DEVNAME NEQ DEVCOND
{
- $$ = alloc_node(SSF_OR, $1);
- $$->post = $3;
+ $$ = alloc_node(SSF_NOT, alloc_node(SSF_DEVCOND, $3));
}
- | expr expr
+ | FWMARK eq MARKMASK
{
- $$ = alloc_node(SSF_AND, $1);
- $$->post = $2;
+ $$ = alloc_node(SSF_MARKMASK, $3);
}
- | expr '&' expr
-
+ | FWMARK NEQ MARKMASK
{
- $$ = alloc_node(SSF_AND, $1);
- $$->post = $3;
+ $$ = alloc_node(SSF_NOT, alloc_node(SSF_MARKMASK, $3));
}
- | '!' expr
+ | CGROUPPATH eq CGROUPCOND
{
- $$ = alloc_node(SSF_NOT, $2);
+ $$ = alloc_node(SSF_CGROUPCOND, $3);
}
- | '(' expr ')'
+ | CGROUPPATH NEQ CGROUPCOND
{
- $$ = $2;
+ $$ = alloc_node(SSF_NOT, alloc_node(SSF_CGROUPCOND, $3));
+ }
+ | AUTOBOUND
+ {
+ $$ = alloc_node(SSF_S_AUTO, NULL);
}
;
%%
argc++;
} else if (yy_fp) {
while (tokptr == NULL) {
- if (fgets(argbuf, sizeof(argbuf)-1, yy_fp) == NULL)
+ size_t len;
+
+ if (fgets(argbuf, sizeof(argbuf), yy_fp) == NULL)
return 0;
- argbuf[sizeof(argbuf)-1] = 0;
- if (strlen(argbuf) == sizeof(argbuf) - 1) {
- fprintf(stderr, "Too long line in filter");
+
+ 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[strlen(argbuf)-1] == '\n')
- argbuf[strlen(argbuf)-1] = 0;
+ if (argbuf[len - 1] == '\n')
+ argbuf[len-1] = 0;
if (argbuf[0] == '#' || argbuf[0] == '0')
continue;
tokptr = argbuf;
return '(';
if (strcmp(curtok, ")") == 0)
return ')';
- if (strcmp(curtok, "dst") == 0)
+ if (strcmp(curtok, "dst") == 0) {
+ tok_type = DCOND;
return DCOND;
- if (strcmp(curtok, "src") == 0)
+ }
+ if (strcmp(curtok, "src") == 0) {
+ tok_type = SCOND;
return SCOND;
- if (strcmp(curtok, "dport") == 0)
+ }
+ if (strcmp(curtok, "dport") == 0) {
+ tok_type = DPORT;
return DPORT;
- if (strcmp(curtok, "sport") == 0)
+ }
+ 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, "cgroup") == 0) {
+ tok_type = CGROUPPATH;
+ return CGROUPPATH;
+ }
if (strcmp(curtok, ">=") == 0 ||
strcmp(curtok, "ge") == 0 ||
strcmp(curtok, "geq") == 0)
if (strcmp(curtok, "<") == 0 ||
strcmp(curtok, "lt") == 0)
return '<';
- if (strcmp(curtok, "autobound") == 0)
+ if (strcmp(curtok, "autobound") == 0) {
+ tok_type = AUTOBOUND;
return AUTOBOUND;
- yylval = (void*)parse_hostcond(curtok);
+ }
+ 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;
+ }
+ if (tok_type == CGROUPPATH) {
+ yylval = (void*)parse_cgroupcond(curtok);
+ if (yylval == NULL) {
+ fprintf(stderr, "Cannot parse cgroup %s.\n", curtok);
+ exit(1);
+ }
+ return CGROUPCOND;
+ }
+ yylval = (void*)parse_hostcond(curtok, tok_type == SPORT || tok_type == DPORT);
if (yylval == NULL) {
fprintf(stderr, "Cannot parse dst/src address.\n");
exit(1);