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