Home | History | Annotate | Download | only in misc
      1 %{
      2 
      3 #include <stdio.h>
      4 #include <stdlib.h>
      5 #include <malloc.h>
      6 #include <string.h>
      7 /* NOTE: Android yacc build rules transform ssfilter.y into ssfilter.h, and
      8  * #include "ssfilter.h" gets this file instead of the ssfilter.h in the
      9  * source tree. This does not work. #include <ssfilter.h> instead. */
     10 #include <ssfilter.h>
     11 
     12 typedef struct ssfilter * ssfilter_t;
     13 
     14 #define YYSTYPE ssfilter_t
     15 
     16 static struct ssfilter * alloc_node(int type, void *pred)
     17 {
     18 	struct ssfilter *n = malloc(sizeof(*n));
     19 	if (n == NULL)
     20 		abort();
     21 	n->type = type;
     22 	n->pred = pred;
     23 	n->post = NULL;
     24 	return n;
     25 }
     26 
     27 static char		**yy_argv;
     28 static int		yy_argc;
     29 static FILE		*yy_fp;
     30 static ssfilter_t	*yy_ret;
     31 static int tok_type = -1;
     32 
     33 static int yylex(void);
     34 
     35 static void yyerror(char *s)
     36 {
     37 	fprintf(stderr, "ss: bison bellows (while parsing filter): \"%s!\"", s);
     38 }
     39 
     40 %}
     41 
     42 %token HOSTCOND DCOND SCOND DPORT SPORT LEQ GEQ NEQ AUTOBOUND MARKMASK FWMARK
     43 %left '|'
     44 %left '&'
     45 %nonassoc '!'
     46 
     47 %%
     48 applet: null expr
     49         {
     50                 *yy_ret = $2;
     51                 $$ = $2;
     52         }
     53         | null
     54         ;
     55 null:   /* NOTHING */ { $$ = NULL; }
     56         ;
     57 expr:	DCOND HOSTCOND
     58         {
     59 		$$ = alloc_node(SSF_DCOND, $2);
     60         }
     61         | SCOND HOSTCOND
     62         {
     63 		$$ = alloc_node(SSF_SCOND, $2);
     64         }
     65         | DPORT GEQ HOSTCOND
     66         {
     67                 $$ = alloc_node(SSF_D_GE, $3);
     68         }
     69         | DPORT LEQ HOSTCOND
     70         {
     71                 $$ = alloc_node(SSF_D_LE, $3);
     72         }
     73         | DPORT '>' HOSTCOND
     74         {
     75                 $$ = alloc_node(SSF_NOT, alloc_node(SSF_D_LE, $3));
     76         }
     77         | DPORT '<' HOSTCOND
     78         {
     79                 $$ = alloc_node(SSF_NOT, alloc_node(SSF_D_GE, $3));
     80         }
     81         | DPORT '=' HOSTCOND
     82         {
     83 		$$ = alloc_node(SSF_DCOND, $3);
     84         }
     85         | DPORT NEQ HOSTCOND
     86         {
     87 		$$ = alloc_node(SSF_NOT, alloc_node(SSF_DCOND, $3));
     88         }
     89 
     90         | SPORT GEQ HOSTCOND
     91         {
     92                 $$ = alloc_node(SSF_S_GE, $3);
     93         }
     94         | SPORT LEQ HOSTCOND
     95         {
     96                 $$ = alloc_node(SSF_S_LE, $3);
     97         }
     98         | SPORT '>' HOSTCOND
     99         {
    100                 $$ = alloc_node(SSF_NOT, alloc_node(SSF_S_LE, $3));
    101         }
    102         | SPORT '<' HOSTCOND
    103         {
    104                 $$ = alloc_node(SSF_NOT, alloc_node(SSF_S_GE, $3));
    105         }
    106         | SPORT '=' HOSTCOND
    107         {
    108 		$$ = alloc_node(SSF_SCOND, $3);
    109         }
    110         | SPORT NEQ HOSTCOND
    111         {
    112 		$$ = alloc_node(SSF_NOT, alloc_node(SSF_SCOND, $3));
    113         }
    114         | FWMARK '=' MARKMASK
    115         {
    116                 $$ = alloc_node(SSF_MARKMASK, $3);
    117         }
    118         | FWMARK NEQ MARKMASK
    119         {
    120                 $$ = alloc_node(SSF_NOT, alloc_node(SSF_MARKMASK, $3));
    121         }
    122         | AUTOBOUND
    123         {
    124                 $$ = alloc_node(SSF_S_AUTO, NULL);
    125         }
    126         | expr '|' expr
    127         {
    128                 $$ = alloc_node(SSF_OR, $1);
    129 	        $$->post = $3;
    130         }
    131         | expr expr
    132         {
    133                 $$ = alloc_node(SSF_AND, $1);
    134 	        $$->post = $2;
    135         }
    136         | expr '&' expr
    137 
    138         {
    139                 $$ = alloc_node(SSF_AND, $1);
    140 	        $$->post = $3;
    141         }
    142         | '!' expr
    143         {
    144                 $$ = alloc_node(SSF_NOT, $2);
    145         }
    146         | '(' expr ')'
    147         {
    148                 $$ = $2;
    149         }
    150 ;
    151 %%
    152 
    153 static char *get_token_from_line(char **ptr)
    154 {
    155 	char *tok, *cp = *ptr;
    156 
    157 	while (*cp == ' ' || *cp == '\t') cp++;
    158 
    159 	if (*cp == 0) {
    160 		*ptr = cp;
    161 		return NULL;
    162 	}
    163 
    164 	tok = cp;
    165 
    166 	while (*cp != 0 && *cp != ' ' && *cp != '\t') {
    167 		/* Backslash escapes everything. */
    168 		if (*cp == '\\') {
    169 			char *tp;
    170 			for (tp = cp; tp != tok; tp--)
    171 				*tp = *(tp-1);
    172 			cp++;
    173 			tok++;
    174 			if (*cp == 0)
    175 				break;
    176 		}
    177 		cp++;
    178 	}
    179 	if (*cp)
    180 		*cp++ = 0;
    181 	*ptr = cp;
    182 	return tok;
    183 }
    184 
    185 int yylex(void)
    186 {
    187 	static char argbuf[1024];
    188 	static char *tokptr = argbuf;
    189 	static int argc;
    190 	char *curtok;
    191 
    192 	do {
    193 		while (*tokptr == 0) {
    194 			tokptr = NULL;
    195 			if (argc < yy_argc) {
    196 				tokptr = yy_argv[argc];
    197 				argc++;
    198 			} else if (yy_fp) {
    199 				while (tokptr == NULL) {
    200 					if (fgets(argbuf, sizeof(argbuf)-1, yy_fp) == NULL)
    201 						return 0;
    202 					argbuf[sizeof(argbuf)-1] = 0;
    203 					if (strlen(argbuf) == sizeof(argbuf) - 1) {
    204 						fprintf(stderr, "Too long line in filter");
    205 						exit(-1);
    206 					}
    207 					if (argbuf[strlen(argbuf)-1] == '\n')
    208 						argbuf[strlen(argbuf)-1] = 0;
    209 					if (argbuf[0] == '#' || argbuf[0] == '0')
    210 						continue;
    211 					tokptr = argbuf;
    212 				}
    213 			} else {
    214 				return 0;
    215 			}
    216 		}
    217 	} while ((curtok = get_token_from_line(&tokptr)) == NULL);
    218 
    219 	if (strcmp(curtok, "!") == 0 ||
    220 	    strcmp(curtok, "not") == 0)
    221 		return '!';
    222 	if (strcmp(curtok, "&") == 0 ||
    223 	    strcmp(curtok, "&&") == 0 ||
    224 	    strcmp(curtok, "and") == 0)
    225 		return '&';
    226 	if (strcmp(curtok, "|") == 0 ||
    227 	    strcmp(curtok, "||") == 0 ||
    228 	    strcmp(curtok, "or") == 0)
    229 		return '|';
    230 	if (strcmp(curtok, "(") == 0)
    231 		return '(';
    232 	if (strcmp(curtok, ")") == 0)
    233 		return ')';
    234 	if (strcmp(curtok, "dst") == 0) {
    235 		tok_type = DCOND;
    236 		return DCOND;
    237 	}
    238 	if (strcmp(curtok, "src") == 0) {
    239                 tok_type = SCOND;
    240 		return SCOND;
    241         }
    242 	if (strcmp(curtok, "dport") == 0) {
    243 		tok_type = DPORT;
    244 		return DPORT;
    245 	}
    246 	if (strcmp(curtok, "sport") == 0) {
    247 		tok_type = SPORT;
    248 		return SPORT;
    249 	}
    250 	if (strcmp(curtok, "fwmark") == 0) {
    251 		tok_type = FWMARK;
    252 		return FWMARK;
    253 	}
    254 	if (strcmp(curtok, ">=") == 0 ||
    255 	    strcmp(curtok, "ge") == 0 ||
    256 	    strcmp(curtok, "geq") == 0)
    257 		return GEQ;
    258 	if (strcmp(curtok, "<=") == 0 ||
    259 	    strcmp(curtok, "le") == 0 ||
    260 	    strcmp(curtok, "leq") == 0)
    261 		return LEQ;
    262 	if (strcmp(curtok, "!=") == 0 ||
    263 	    strcmp(curtok, "ne") == 0 ||
    264 	    strcmp(curtok, "neq") == 0)
    265 		return NEQ;
    266 	if (strcmp(curtok, "=") == 0 ||
    267 	    strcmp(curtok, "==") == 0 ||
    268 	    strcmp(curtok, "eq") == 0)
    269 		return '=';
    270 	if (strcmp(curtok, ">") == 0 ||
    271 	    strcmp(curtok, "gt") == 0)
    272 		return '>';
    273 	if (strcmp(curtok, "<") == 0 ||
    274 	    strcmp(curtok, "lt") == 0)
    275 		return '<';
    276 	if (strcmp(curtok, "autobound") == 0) {
    277 		tok_type = AUTOBOUND;
    278 		return AUTOBOUND;
    279 	}
    280 	if (tok_type == FWMARK) {
    281 		yylval = (void*)parse_markmask(curtok);
    282 		if (yylval == NULL) {
    283 			fprintf(stderr, "Cannot parse mark %s.\n", curtok);
    284 			exit(1);
    285 		}
    286 		return MARKMASK;
    287 	}
    288 	yylval = (void*)parse_hostcond(curtok, tok_type == SPORT || tok_type == DPORT);
    289 	if (yylval == NULL) {
    290 		fprintf(stderr, "Cannot parse dst/src address.\n");
    291 		exit(1);
    292 	}
    293 	return HOSTCOND;
    294 }
    295 
    296 int ssfilter_parse(struct ssfilter **f, int argc, char **argv, FILE *fp)
    297 {
    298 	yy_argc = argc;
    299 	yy_argv = argv;
    300 	yy_fp   = fp;
    301 	yy_ret  = f;
    302 
    303 	if (yyparse()) {
    304 		fprintf(stderr, " Sorry.\n");
    305 		return -1;
    306 	}
    307 	return 0;
    308 }
    309