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
alloc_node(int type,void * pred)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
yyerror(char * s)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 DEVCOND DEVNAME 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 | 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
161 static 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
yylex(void)193 int 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
ssfilter_parse(struct ssfilter ** f,int argc,char ** argv,FILE * fp)316 int 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