%}
-%token HOSTCOND DCOND SCOND DPORT SPORT LEQ GEQ NEQ AUTOBOUND
+%token HOSTCOND DCOND SCOND DPORT SPORT LEQ GEQ NEQ AUTOBOUND DEVCOND DEVNAME MARKMASK FWMARK
%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
+ | SCOND eq HOSTCOND
{
- $$ = alloc_node(SSF_SCOND, $2);
+ $$ = 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
- {
- $$ = alloc_node(SSF_S_AUTO, NULL);
- }
- | expr '|' expr
+ | DEVNAME eq DEVCOND
{
- $$ = alloc_node(SSF_OR, $1);
- $$->post = $3;
+ $$ = alloc_node(SSF_DEVCOND, $3);
}
- | expr expr
+ | DEVNAME NEQ DEVCOND
{
- $$ = alloc_node(SSF_AND, $1);
- $$->post = $2;
+ $$ = alloc_node(SSF_NOT, alloc_node(SSF_DEVCOND, $3));
}
- | expr '&' expr
-
+ | FWMARK eq MARKMASK
{
- $$ = alloc_node(SSF_AND, $1);
- $$->post = $3;
+ $$ = alloc_node(SSF_MARKMASK, $3);
}
- | '!' expr
+ | FWMARK NEQ MARKMASK
{
- $$ = alloc_node(SSF_NOT, $2);
+ $$ = alloc_node(SSF_NOT, alloc_node(SSF_MARKMASK, $3));
}
- | '(' expr ')'
+ | AUTOBOUND
{
- $$ = $2;
+ $$ = 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 (argbuf[strlen(argbuf)-1] == '\n')
- argbuf[strlen(argbuf)-1] = 0;
+
+ 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;
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)
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");