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