3c1a8ef8 |
/*
* $Id$
*
* cfg grammar
*/
%{
|
3e429f5c |
#include <stdlib.h>
|
63fa628f |
#include <stdio.h>
|
c07508e2 |
#include "route_struct.h"
|
3e429f5c |
#include "globals.h"
#include "route.h"
void yyerror(char* s);
|
c07508e2 |
|
3c1a8ef8 |
%}
%union {
int intval;
|
09e52ebb |
unsigned uval;
|
3c1a8ef8 |
char* strval;
|
c07508e2 |
struct expr* expr;
struct action* action;
|
09e52ebb |
struct net* net;
|
3e429f5c |
struct route_elem* route_el;
|
3c1a8ef8 |
}
/* terminals */
|
3e429f5c |
/* keywords */
|
3c1a8ef8 |
%token FORWARD
%token SEND
%token DROP
%token LOG
%token ERROR
%token ROUTE
|
09e52ebb |
%token EXEC
|
3c1a8ef8 |
%token METHOD
%token URI
%token SRCIP
%token DSTIP
/* config vars. */
%token DEBUG
%token FORK
%token LOGSTDERROR
%token LISTEN
%token DNS
%token REV_DNS
/* operators */
%nonassoc EQUAL
%nonassoc EQUAL_T
%nonassoc MATCH
%left OR
|
09e52ebb |
%left AND
%left NOT
|
3c1a8ef8 |
/* values */
|
c07508e2 |
%token <intval> NUMBER
%token <strval> ID
%token <strval> STRING
|
3c1a8ef8 |
/* other */
%token COMMA
%token SEMICOLON
%token RPAREN
%token LPAREN
%token LBRACE
%token RBRACE
%token LBRACK
%token RBRACK
%token SLASH
%token DOT
%token CR
/*non-terminals */
|
c07508e2 |
%type <expr> exp, condition, exp_elem
%type <action> action, actions, cmd
|
09e52ebb |
%type <uval> ipv4
%type <net> net4
%type <strval> host
|
3e429f5c |
%type <route_el> rules;
%type <route_el> rule;
|
3c1a8ef8 |
%%
cfg: statements
;
|
3e429f5c |
statements: statements statement {}
| statement {}
| statements error { yyerror(""); YYABORT;}
|
3c1a8ef8 |
;
statement: assign_stm CR
|
c07508e2 |
| route_stm CR
| CR /* null statement*/
|
3c1a8ef8 |
;
|
c07508e2 |
assign_stm: DEBUG EQUAL NUMBER
| DEBUG EQUAL error { yyerror("number expected"); }
| FORK EQUAL NUMBER
| FORK EQUAL error { yyerror("boolean value expected"); }
| LOGSTDERROR EQUAL NUMBER
| LOGSTDERROR EQUAL error { yyerror("boolean value expected"); }
| DNS EQUAL NUMBER
| DNS EQUAL error { yyerror("boolean value expected"); }
| REV_DNS EQUAL NUMBER
| REV_DNS EQUAL error { yyerror("boolean value expected"); }
| LISTEN EQUAL ipv4
| LISTEN EQUAL ID
| LISTEN EQUAL STRING
| LISTEN EQUAL error { yyerror("ip address or hostname"
"expected"); }
| error EQUAL { yyerror("unknown config variable"); }
|
3c1a8ef8 |
;
|
09e52ebb |
ipv4: NUMBER DOT NUMBER DOT NUMBER DOT NUMBER {
if (($1>255) || ($1<0) ||
($3>255) || ($3<0) ||
($5>255) || ($5<0) ||
($7>255) || ($7<0)){
yyerror("invalid ipv4"
"address");
$$=0;
}else{
|
3e429f5c |
$$=htonl( ($1<<24)|
($3<<16)| ($5<<8)|$7 );
|
09e52ebb |
}
}
|
3c1a8ef8 |
;
|
3e429f5c |
route_stm: ROUTE LBRACE rules RBRACE { push($3, &rlist[DEFAULT_RT]); }
| ROUTE LBRACK NUMBER RBRACK LBRACE rules RBRACE {
if (($3<RT_NO) && ($3>=0)){
push($6, &rlist[$3]);
}else{
yyerror("invalid routing"
"table number");
YYABORT; }
}
|
c07508e2 |
| ROUTE error { yyerror("invalid route statement"); }
|
3c1a8ef8 |
;
|
3e429f5c |
rules: rules rule { push($2, &$1); $$=$1;
printf(": rules->rules(%x) rule(%x)\n", $1,$2);}
|
63fa628f |
| rule {$$=$1; printf(": rules->rule (%x)\n",$1); }
|
3e429f5c |
| rules error { $$=0; yyerror("invalid rule"); }
|
3c1a8ef8 |
;
|
09e52ebb |
rule: condition actions CR {
printf("Got a new rule!\n");
printf("expr: "); print_expr($1);
printf("\n -> actions: ");
print_action($2); printf("\n");
|
3e429f5c |
$$=0;
if (add_rule($1, $2, &$$)<0) {
yyerror("error calling add_rule");
YYABORT;
}
printf(": rule -> condition actions CR\n");
}
| CR /* null rule */ { $$=0; printf(": rule-> CR!\n"); }
| condition error { $$=0; yyerror("bad actions in rule"); }
|
3c1a8ef8 |
;
|
09e52ebb |
condition: exp {$$=$1;}
|
3c1a8ef8 |
;
|
09e52ebb |
exp: exp AND exp { $$=mk_exp(AND_OP, $1, $3); }
| exp OR exp { $$=mk_exp(OR_OP, $1, $3); }
| NOT exp { $$=mk_exp(NOT_OP, $2, 0); }
| LPAREN exp RPAREN { $$=$2; }
| exp_elem { $$=$1; }
|
3c1a8ef8 |
;
|
09e52ebb |
exp_elem: METHOD EQUAL_T STRING {$$= mk_elem( EQUAL_OP, STRING_ST,
METHOD_O, $3);
}
| METHOD EQUAL_T ID {$$ = mk_elem( EQUAL_OP, STRING_ST,
METHOD_O, $3);
}
|
c07508e2 |
| METHOD EQUAL_T error { $$=0; yyerror("string expected"); }
|
09e52ebb |
| METHOD MATCH STRING {$$ = mk_elem( MATCH_OP, STRING_ST,
METHOD_O, $3);
}
| METHOD MATCH ID {$$ = mk_elem( MATCH_OP, STRING_ST,
METHOD_O, $3);
}
|
c07508e2 |
| METHOD MATCH error { $$=0; yyerror("string expected"); }
|
09e52ebb |
| METHOD error { $$=0; yyerror("invalid operator,"
"== or ~= expected");
}
| URI EQUAL_T STRING {$$ = mk_elem( EQUAL_OP, STRING_ST,
URI_O, $3);
}
| URI EQUAL_T ID {$$ = mk_elem( EQUAL_OP, STRING_ST,
URI_O, $3);
}
|
c07508e2 |
| URI EQUAL_T error { $$=0; yyerror("string expected"); }
|
09e52ebb |
| URI MATCH STRING { $$=mk_elem( MATCH_OP, STRING_ST,
URI_O, $3);
}
| URI MATCH ID { $$=mk_elem( MATCH_OP, STRING_ST,
URI_O, $3);
}
|
c07508e2 |
| URI MATCH error { $$=0; yyerror("string expected"); }
|
09e52ebb |
| URI error { $$=0; yyerror("invalid operator,"
" == or ~= expected");
}
| SRCIP EQUAL_T net4 { $$=mk_elem( EQUAL_OP, NET_ST,
SRCIP_O, $3);
}
| SRCIP EQUAL_T STRING { $$=mk_elem( EQUAL_OP, STRING_ST,
SRCIP_O, $3);
}
| SRCIP EQUAL_T host { $$=mk_elem( EQUAL_OP, STRING_ST,
SRCIP_O, $3);
}
| SRCIP EQUAL_T error { $$=0; yyerror( "ip address or hostname"
|
c07508e2 |
"expected" ); }
|
09e52ebb |
| SRCIP MATCH STRING { $$=mk_elem( MATCH_OP, STRING_ST,
SRCIP_O, $3);
}
| SRCIP MATCH ID { $$=mk_elem( MATCH_OP, STRING_ST,
SRCIP_O, $3);
}
| SRCIP MATCH error { $$=0; yyerror( "hostname expected"); }
| SRCIP error { $$=0;
yyerror("invalid operator, == or ~= expected");}
| DSTIP EQUAL_T net4 { $$=mk_elem( EQUAL_OP, NET_ST,
DSTIP_O, $3);
}
| DSTIP EQUAL_T STRING { $$=mk_elem( EQUAL_OP, STRING_ST,
DSTIP_O, $3);
}
| DSTIP EQUAL_T host { $$=mk_elem( EQUAL_OP, STRING_ST,
DSTIP_O, $3);
}
| DSTIP EQUAL_T error { $$=0; yyerror( "ip address or hostname"
"expected" ); }
| DSTIP MATCH STRING { $$=mk_elem( MATCH_OP, STRING_ST,
DSTIP_O, $3);
}
| DSTIP MATCH ID { $$=mk_elem( MATCH_OP, STRING_ST,
DSTIP_O, $3);
}
| DSTIP MATCH error { $$=0; yyerror ( "hostname expected" ); }
| DSTIP error { $$=0;
yyerror("invalid operator, == or ~= expected");}
|
3c1a8ef8 |
;
|
09e52ebb |
net4: ipv4 SLASH ipv4 { $$=mk_net($1, $3); }
|
a15c363f |
| ipv4 SLASH NUMBER { if (($3>32)|($3<0)){
|
09e52ebb |
yyerror("invalid bit number in netmask");
$$=0;
}else{
|
63fa628f |
$$=mk_net($1, ((1<<$3)-1));
|
09e52ebb |
}
}
| ipv4 { $$=mk_net($1, 0xffffffff); }
| ipv4 SLASH error { $$=0;
yyerror("netmask (eg:255.0.0.0 or 8) expected");}
|
3c1a8ef8 |
;
|
09e52ebb |
host: ID { $$=$1; }
| host DOT ID { $$=(char*)malloc(strlen($1)+1+strlen($3)+1);
if ($$==0){
fprintf(stderr, "memory allocation failure"
" while parsing host\n");
}else{
memcpy($$, $1, strlen($1));
$$[strlen($1)]='.';
memcpy($$+strlen($1)+1, $3, strlen($3));
$$[strlen($1)+1+strlen($3)]=0;
}
free($1); free($3);
};
| host DOT error { $$=0; free($1); yyerror("invalid hostname"); }
|
3c1a8ef8 |
;
|
09e52ebb |
actions: actions action {$$=append_action($1, $2); }
| action {$$=$1;}
| actions error { $$=0; yyerror("bad command"); }
|
c07508e2 |
;
|
09e52ebb |
action: cmd SEMICOLON {$$=$1;}
| SEMICOLON /* null action */ {$$=0;}
| cmd error { $$=0; yyerror("bad command: missing ';'?"); }
|
3c1a8ef8 |
;
|
09e52ebb |
cmd: FORWARD LPAREN host RPAREN { $$=mk_action( FORWARD_T,
STRING_ST,
NUMBER_ST,
$3,
0);
}
| FORWARD LPAREN STRING RPAREN { $$=mk_action( FORWARD_T,
STRING_ST,
NUMBER_ST,
$3,
0);
}
| FORWARD LPAREN ipv4 RPAREN { $$=mk_action( FORWARD_T,
IP_ST,
NUMBER_ST,
(void*)$3,
0);
}
| FORWARD LPAREN host COMMA NUMBER RPAREN { $$=mk_action(FORWARD_T,
STRING_ST,
NUMBER_ST,
$3,
(void*)$5);
}
| FORWARD LPAREN STRING COMMA NUMBER RPAREN {$$=mk_action(FORWARD_T,
STRING_ST,
NUMBER_ST,
$3,
(void*)$5);
}
| FORWARD LPAREN ipv4 COMMA NUMBER RPAREN { $$=mk_action(FORWARD_T,
IP_ST,
NUMBER_ST,
(void*)$3,
(void*)$5);
}
| FORWARD error { $$=0; yyerror("missing '(' or ')' ?"); }
| FORWARD LPAREN error RPAREN { $$=0; yyerror("bad forward"
"argument"); }
| SEND LPAREN host RPAREN { $$=mk_action( SEND_T,
STRING_ST,
NUMBER_ST,
$3,
0);
}
| SEND LPAREN STRING RPAREN { $$=mk_action( SEND_T,
STRING_ST,
NUMBER_ST,
$3,
0);
}
| SEND LPAREN ipv4 RPAREN { $$=mk_action( SEND_T,
IP_ST,
NUMBER_ST,
(void*)$3,
0);
}
| SEND LPAREN host COMMA NUMBER RPAREN { $$=mk_action( SEND_T,
STRING_ST,
NUMBER_ST,
$3,
(void*)$5);
}
| SEND LPAREN STRING COMMA NUMBER RPAREN {$$=mk_action( SEND_T,
STRING_ST,
NUMBER_ST,
$3,
(void*)$5);
}
| SEND LPAREN ipv4 COMMA NUMBER RPAREN { $$=mk_action( SEND_T,
IP_ST,
NUMBER_ST,
(void*)$3,
(void*)$5);
}
| SEND error { $$=0; yyerror("missing '(' or ')' ?"); }
| SEND LPAREN error RPAREN { $$=0; yyerror("bad send"
"argument"); }
| DROP LPAREN RPAREN {$$=mk_action(DROP_T,0, 0, 0, 0); }
| DROP {$$=mk_action(DROP_T,0, 0, 0, 0); }
| LOG LPAREN STRING RPAREN {$$=mk_action( LOG_T, NUMBER_ST,
STRING_ST,(void*)4,$3);
}
| LOG LPAREN NUMBER COMMA STRING RPAREN {$$=mk_action( LOG_T,
NUMBER_ST,
STRING_ST,
(void*)$3,
$5);
}
| LOG error { $$=0; yyerror("missing '(' or ')' ?"); }
| LOG LPAREN error RPAREN { $$=0; yyerror("bad log"
"argument"); }
| ERROR LPAREN STRING COMMA STRING RPAREN {$$=mk_action(ERROR_T,
STRING_ST,
STRING_ST,
$3,
$5);
}
| ERROR error { $$=0; yyerror("missing '(' or ')' ?"); }
| ERROR LPAREN error RPAREN { $$=0; yyerror("bad error"
"argument"); }
| ROUTE LPAREN NUMBER RPAREN { $$=mk_action(ROUTE_T, NUMBER_ST,
0, (void*)$3, 0);
}
| ROUTE error { $$=0; yyerror("missing '(' or ')' ?"); }
| ROUTE LPAREN error RPAREN { $$=0; yyerror("bad route"
|
c07508e2 |
"argument"); }
|
09e52ebb |
| EXEC LPAREN STRING RPAREN { $$=mk_action( EXEC_T, STRING_ST, 0,
$3, 0);
}
|
3c1a8ef8 |
;
%%
extern int line;
extern int column;
|
09e52ebb |
extern int startcolumn;
|
3e429f5c |
void yyerror(char* s)
|
3c1a8ef8 |
{
|
09e52ebb |
fprintf(stderr, "parse error (%d,%d-%d): %s\n", line, startcolumn,
column, s);
|
63fa628f |
cfg_errors++;
|
3c1a8ef8 |
}
|
a15c363f |
/*
|
3c1a8ef8 |
int main(int argc, char ** argv)
{
if (yyparse()!=0)
fprintf(stderr, "parsing error\n");
}
|
a15c363f |
*/
|