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 12typedef struct ssfilter * ssfilter_t; 13 14#define YYSTYPE ssfilter_t 15 16static 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 27static char **yy_argv; 28static int yy_argc; 29static FILE *yy_fp; 30static ssfilter_t *yy_ret; 31static int tok_type = -1; 32 33static int yylex(void); 34 35static 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 DEVCOND DEVNAME MARKMASK FWMARK 43%left '|' 44%left '&' 45%nonassoc '!' 46 47%% 48applet: null expr 49 { 50 *yy_ret = $2; 51 $$ = $2; 52 } 53 | null 54 ; 55null: /* NOTHING */ { $$ = NULL; } 56 ; 57expr: 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 | DEVNAME '=' DEVCOND 115 { 116 $$ = alloc_node(SSF_DEVCOND, $3); 117 } 118 | DEVNAME NEQ DEVCOND 119 { 120 $$ = alloc_node(SSF_NOT, alloc_node(SSF_DEVCOND, $3)); 121 } 122 | FWMARK '=' MARKMASK 123 { 124 $$ = alloc_node(SSF_MARKMASK, $3); 125 } 126 | FWMARK NEQ MARKMASK 127 { 128 $$ = alloc_node(SSF_NOT, alloc_node(SSF_MARKMASK, $3)); 129 } 130 | AUTOBOUND 131 { 132 $$ = alloc_node(SSF_S_AUTO, NULL); 133 } 134 | expr '|' expr 135 { 136 $$ = alloc_node(SSF_OR, $1); 137 $$->post = $3; 138 } 139 | expr expr 140 { 141 $$ = alloc_node(SSF_AND, $1); 142 $$->post = $2; 143 } 144 | expr '&' expr 145 146 { 147 $$ = alloc_node(SSF_AND, $1); 148 $$->post = $3; 149 } 150 | '!' expr 151 { 152 $$ = alloc_node(SSF_NOT, $2); 153 } 154 | '(' expr ')' 155 { 156 $$ = $2; 157 } 158; 159%% 160 161static char *get_token_from_line(char **ptr) 162{ 163 char *tok, *cp = *ptr; 164 165 while (*cp == ' ' || *cp == '\t') cp++; 166 167 if (*cp == 0) { 168 *ptr = cp; 169 return NULL; 170 } 171 172 tok = cp; 173 174 while (*cp != 0 && *cp != ' ' && *cp != '\t') { 175 /* Backslash escapes everything. */ 176 if (*cp == '\\') { 177 char *tp; 178 for (tp = cp; tp != tok; tp--) 179 *tp = *(tp-1); 180 cp++; 181 tok++; 182 if (*cp == 0) 183 break; 184 } 185 cp++; 186 } 187 if (*cp) 188 *cp++ = 0; 189 *ptr = cp; 190 return tok; 191} 192 193int yylex(void) 194{ 195 static char argbuf[1024]; 196 static char *tokptr = argbuf; 197 static int argc; 198 char *curtok; 199 200 do { 201 while (*tokptr == 0) { 202 tokptr = NULL; 203 if (argc < yy_argc) { 204 tokptr = yy_argv[argc]; 205 argc++; 206 } else if (yy_fp) { 207 while (tokptr == NULL) { 208 if (fgets(argbuf, sizeof(argbuf)-1, yy_fp) == NULL) 209 return 0; 210 argbuf[sizeof(argbuf)-1] = 0; 211 if (strlen(argbuf) == sizeof(argbuf) - 1) { 212 fprintf(stderr, "Too long line in filter"); 213 exit(-1); 214 } 215 if (argbuf[strlen(argbuf)-1] == '\n') 216 argbuf[strlen(argbuf)-1] = 0; 217 if (argbuf[0] == '#' || argbuf[0] == '0') 218 continue; 219 tokptr = argbuf; 220 } 221 } else { 222 return 0; 223 } 224 } 225 } while ((curtok = get_token_from_line(&tokptr)) == NULL); 226 227 if (strcmp(curtok, "!") == 0 || 228 strcmp(curtok, "not") == 0) 229 return '!'; 230 if (strcmp(curtok, "&") == 0 || 231 strcmp(curtok, "&&") == 0 || 232 strcmp(curtok, "and") == 0) 233 return '&'; 234 if (strcmp(curtok, "|") == 0 || 235 strcmp(curtok, "||") == 0 || 236 strcmp(curtok, "or") == 0) 237 return '|'; 238 if (strcmp(curtok, "(") == 0) 239 return '('; 240 if (strcmp(curtok, ")") == 0) 241 return ')'; 242 if (strcmp(curtok, "dst") == 0) { 243 tok_type = DCOND; 244 return DCOND; 245 } 246 if (strcmp(curtok, "src") == 0) { 247 tok_type = SCOND; 248 return SCOND; 249 } 250 if (strcmp(curtok, "dport") == 0) { 251 tok_type = DPORT; 252 return DPORT; 253 } 254 if (strcmp(curtok, "sport") == 0) { 255 tok_type = SPORT; 256 return SPORT; 257 } 258 if (strcmp(curtok, "dev") == 0) { 259 tok_type = DEVNAME; 260 return DEVNAME; 261 } 262 if (strcmp(curtok, "fwmark") == 0) { 263 tok_type = FWMARK; 264 return FWMARK; 265 } 266 if (strcmp(curtok, ">=") == 0 || 267 strcmp(curtok, "ge") == 0 || 268 strcmp(curtok, "geq") == 0) 269 return GEQ; 270 if (strcmp(curtok, "<=") == 0 || 271 strcmp(curtok, "le") == 0 || 272 strcmp(curtok, "leq") == 0) 273 return LEQ; 274 if (strcmp(curtok, "!=") == 0 || 275 strcmp(curtok, "ne") == 0 || 276 strcmp(curtok, "neq") == 0) 277 return NEQ; 278 if (strcmp(curtok, "=") == 0 || 279 strcmp(curtok, "==") == 0 || 280 strcmp(curtok, "eq") == 0) 281 return '='; 282 if (strcmp(curtok, ">") == 0 || 283 strcmp(curtok, "gt") == 0) 284 return '>'; 285 if (strcmp(curtok, "<") == 0 || 286 strcmp(curtok, "lt") == 0) 287 return '<'; 288 if (strcmp(curtok, "autobound") == 0) { 289 tok_type = AUTOBOUND; 290 return AUTOBOUND; 291 } 292 if (tok_type == DEVNAME) { 293 yylval = (void*)parse_devcond(curtok); 294 if (yylval == NULL) { 295 fprintf(stderr, "Cannot parse device.\n"); 296 exit(1); 297 } 298 return DEVCOND; 299 } 300 if (tok_type == FWMARK) { 301 yylval = (void*)parse_markmask(curtok); 302 if (yylval == NULL) { 303 fprintf(stderr, "Cannot parse mark %s.\n", curtok); 304 exit(1); 305 } 306 return MARKMASK; 307 } 308 yylval = (void*)parse_hostcond(curtok, tok_type == SPORT || tok_type == DPORT); 309 if (yylval == NULL) { 310 fprintf(stderr, "Cannot parse dst/src address.\n"); 311 exit(1); 312 } 313 return HOSTCOND; 314} 315 316int ssfilter_parse(struct ssfilter **f, int argc, char **argv, FILE *fp) 317{ 318 yy_argc = argc; 319 yy_argv = argv; 320 yy_fp = fp; 321 yy_ret = f; 322 323 if (yyparse()) { 324 fprintf(stderr, " Sorry.\n"); 325 return -1; 326 } 327 return 0; 328} 329