1*de1e4e89SAndroid Build Coastguard Worker /*
2*de1e4e89SAndroid Build Coastguard Worker * m_ematch.c Extended Matches
3*de1e4e89SAndroid Build Coastguard Worker *
4*de1e4e89SAndroid Build Coastguard Worker * This program is free software; you can distribute it and/or
5*de1e4e89SAndroid Build Coastguard Worker * modify it under the terms of the GNU General Public License
6*de1e4e89SAndroid Build Coastguard Worker * as published by the Free Software Foundation; either version
7*de1e4e89SAndroid Build Coastguard Worker * 2 of the License, or (at your option) any later version.
8*de1e4e89SAndroid Build Coastguard Worker *
9*de1e4e89SAndroid Build Coastguard Worker * Authors: Thomas Graf <[email protected]>
10*de1e4e89SAndroid Build Coastguard Worker */
11*de1e4e89SAndroid Build Coastguard Worker
12*de1e4e89SAndroid Build Coastguard Worker #include <stdio.h>
13*de1e4e89SAndroid Build Coastguard Worker #include <stdlib.h>
14*de1e4e89SAndroid Build Coastguard Worker #include <unistd.h>
15*de1e4e89SAndroid Build Coastguard Worker #include <syslog.h>
16*de1e4e89SAndroid Build Coastguard Worker #include <fcntl.h>
17*de1e4e89SAndroid Build Coastguard Worker #include <sys/socket.h>
18*de1e4e89SAndroid Build Coastguard Worker #include <netinet/in.h>
19*de1e4e89SAndroid Build Coastguard Worker #include <arpa/inet.h>
20*de1e4e89SAndroid Build Coastguard Worker #include <string.h>
21*de1e4e89SAndroid Build Coastguard Worker #include <dlfcn.h>
22*de1e4e89SAndroid Build Coastguard Worker #include <stdarg.h>
23*de1e4e89SAndroid Build Coastguard Worker #include <errno.h>
24*de1e4e89SAndroid Build Coastguard Worker
25*de1e4e89SAndroid Build Coastguard Worker #include "utils.h"
26*de1e4e89SAndroid Build Coastguard Worker #include "tc_util.h"
27*de1e4e89SAndroid Build Coastguard Worker #include "m_ematch.h"
28*de1e4e89SAndroid Build Coastguard Worker
29*de1e4e89SAndroid Build Coastguard Worker #define EMATCH_MAP "/etc/iproute2/ematch_map"
30*de1e4e89SAndroid Build Coastguard Worker
31*de1e4e89SAndroid Build Coastguard Worker static struct ematch_util *ematch_list;
32*de1e4e89SAndroid Build Coastguard Worker
33*de1e4e89SAndroid Build Coastguard Worker /* export to bison parser */
34*de1e4e89SAndroid Build Coastguard Worker int ematch_argc;
35*de1e4e89SAndroid Build Coastguard Worker char **ematch_argv;
36*de1e4e89SAndroid Build Coastguard Worker char *ematch_err;
37*de1e4e89SAndroid Build Coastguard Worker struct ematch *ematch_root;
38*de1e4e89SAndroid Build Coastguard Worker
39*de1e4e89SAndroid Build Coastguard Worker static int begin_argc;
40*de1e4e89SAndroid Build Coastguard Worker static char **begin_argv;
41*de1e4e89SAndroid Build Coastguard Worker
map_warning(int num,char * kind)42*de1e4e89SAndroid Build Coastguard Worker static inline void map_warning(int num, char *kind)
43*de1e4e89SAndroid Build Coastguard Worker {
44*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr,
45*de1e4e89SAndroid Build Coastguard Worker "Error: Unable to find ematch \"%s\" in %s\n" \
46*de1e4e89SAndroid Build Coastguard Worker "Please assign a unique ID to the ematch kind the suggested " \
47*de1e4e89SAndroid Build Coastguard Worker "entry is:\n" \
48*de1e4e89SAndroid Build Coastguard Worker "\t%d\t%s\n",
49*de1e4e89SAndroid Build Coastguard Worker kind, EMATCH_MAP, num, kind);
50*de1e4e89SAndroid Build Coastguard Worker }
51*de1e4e89SAndroid Build Coastguard Worker
lookup_map(__u16 num,char * dst,int len,const char * file)52*de1e4e89SAndroid Build Coastguard Worker static int lookup_map(__u16 num, char *dst, int len, const char *file)
53*de1e4e89SAndroid Build Coastguard Worker {
54*de1e4e89SAndroid Build Coastguard Worker int err = -EINVAL;
55*de1e4e89SAndroid Build Coastguard Worker char buf[512];
56*de1e4e89SAndroid Build Coastguard Worker FILE *fd = fopen(file, "r");
57*de1e4e89SAndroid Build Coastguard Worker
58*de1e4e89SAndroid Build Coastguard Worker if (fd == NULL)
59*de1e4e89SAndroid Build Coastguard Worker return -errno;
60*de1e4e89SAndroid Build Coastguard Worker
61*de1e4e89SAndroid Build Coastguard Worker while (fgets(buf, sizeof(buf), fd)) {
62*de1e4e89SAndroid Build Coastguard Worker char namebuf[512], *p = buf;
63*de1e4e89SAndroid Build Coastguard Worker int id;
64*de1e4e89SAndroid Build Coastguard Worker
65*de1e4e89SAndroid Build Coastguard Worker while (*p == ' ' || *p == '\t')
66*de1e4e89SAndroid Build Coastguard Worker p++;
67*de1e4e89SAndroid Build Coastguard Worker if (*p == '#' || *p == '\n' || *p == 0)
68*de1e4e89SAndroid Build Coastguard Worker continue;
69*de1e4e89SAndroid Build Coastguard Worker
70*de1e4e89SAndroid Build Coastguard Worker if (sscanf(p, "%d %s", &id, namebuf) != 2) {
71*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "ematch map %s corrupted at %s\n",
72*de1e4e89SAndroid Build Coastguard Worker file, p);
73*de1e4e89SAndroid Build Coastguard Worker goto out;
74*de1e4e89SAndroid Build Coastguard Worker }
75*de1e4e89SAndroid Build Coastguard Worker
76*de1e4e89SAndroid Build Coastguard Worker if (id == num) {
77*de1e4e89SAndroid Build Coastguard Worker if (dst)
78*de1e4e89SAndroid Build Coastguard Worker strncpy(dst, namebuf, len - 1);
79*de1e4e89SAndroid Build Coastguard Worker err = 0;
80*de1e4e89SAndroid Build Coastguard Worker goto out;
81*de1e4e89SAndroid Build Coastguard Worker }
82*de1e4e89SAndroid Build Coastguard Worker }
83*de1e4e89SAndroid Build Coastguard Worker
84*de1e4e89SAndroid Build Coastguard Worker err = -ENOENT;
85*de1e4e89SAndroid Build Coastguard Worker out:
86*de1e4e89SAndroid Build Coastguard Worker fclose(fd);
87*de1e4e89SAndroid Build Coastguard Worker return err;
88*de1e4e89SAndroid Build Coastguard Worker }
89*de1e4e89SAndroid Build Coastguard Worker
lookup_map_id(char * kind,int * dst,const char * file)90*de1e4e89SAndroid Build Coastguard Worker static int lookup_map_id(char *kind, int *dst, const char *file)
91*de1e4e89SAndroid Build Coastguard Worker {
92*de1e4e89SAndroid Build Coastguard Worker int err = -EINVAL;
93*de1e4e89SAndroid Build Coastguard Worker char buf[512];
94*de1e4e89SAndroid Build Coastguard Worker FILE *fd = fopen(file, "r");
95*de1e4e89SAndroid Build Coastguard Worker
96*de1e4e89SAndroid Build Coastguard Worker if (fd == NULL)
97*de1e4e89SAndroid Build Coastguard Worker return -errno;
98*de1e4e89SAndroid Build Coastguard Worker
99*de1e4e89SAndroid Build Coastguard Worker while (fgets(buf, sizeof(buf), fd)) {
100*de1e4e89SAndroid Build Coastguard Worker char namebuf[512], *p = buf;
101*de1e4e89SAndroid Build Coastguard Worker int id;
102*de1e4e89SAndroid Build Coastguard Worker
103*de1e4e89SAndroid Build Coastguard Worker while (*p == ' ' || *p == '\t')
104*de1e4e89SAndroid Build Coastguard Worker p++;
105*de1e4e89SAndroid Build Coastguard Worker if (*p == '#' || *p == '\n' || *p == 0)
106*de1e4e89SAndroid Build Coastguard Worker continue;
107*de1e4e89SAndroid Build Coastguard Worker
108*de1e4e89SAndroid Build Coastguard Worker if (sscanf(p, "%d %s", &id, namebuf) != 2) {
109*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "ematch map %s corrupted at %s\n",
110*de1e4e89SAndroid Build Coastguard Worker file, p);
111*de1e4e89SAndroid Build Coastguard Worker goto out;
112*de1e4e89SAndroid Build Coastguard Worker }
113*de1e4e89SAndroid Build Coastguard Worker
114*de1e4e89SAndroid Build Coastguard Worker if (!strcasecmp(namebuf, kind)) {
115*de1e4e89SAndroid Build Coastguard Worker if (dst)
116*de1e4e89SAndroid Build Coastguard Worker *dst = id;
117*de1e4e89SAndroid Build Coastguard Worker err = 0;
118*de1e4e89SAndroid Build Coastguard Worker goto out;
119*de1e4e89SAndroid Build Coastguard Worker }
120*de1e4e89SAndroid Build Coastguard Worker }
121*de1e4e89SAndroid Build Coastguard Worker
122*de1e4e89SAndroid Build Coastguard Worker err = -ENOENT;
123*de1e4e89SAndroid Build Coastguard Worker *dst = 0;
124*de1e4e89SAndroid Build Coastguard Worker out:
125*de1e4e89SAndroid Build Coastguard Worker fclose(fd);
126*de1e4e89SAndroid Build Coastguard Worker return err;
127*de1e4e89SAndroid Build Coastguard Worker }
128*de1e4e89SAndroid Build Coastguard Worker
get_ematch_kind(char * kind)129*de1e4e89SAndroid Build Coastguard Worker static struct ematch_util *get_ematch_kind(char *kind)
130*de1e4e89SAndroid Build Coastguard Worker {
131*de1e4e89SAndroid Build Coastguard Worker static void *body;
132*de1e4e89SAndroid Build Coastguard Worker void *dlh;
133*de1e4e89SAndroid Build Coastguard Worker char buf[256];
134*de1e4e89SAndroid Build Coastguard Worker struct ematch_util *e;
135*de1e4e89SAndroid Build Coastguard Worker
136*de1e4e89SAndroid Build Coastguard Worker for (e = ematch_list; e; e = e->next) {
137*de1e4e89SAndroid Build Coastguard Worker if (strcmp(e->kind, kind) == 0)
138*de1e4e89SAndroid Build Coastguard Worker return e;
139*de1e4e89SAndroid Build Coastguard Worker }
140*de1e4e89SAndroid Build Coastguard Worker
141*de1e4e89SAndroid Build Coastguard Worker snprintf(buf, sizeof(buf), "em_%s.so", kind);
142*de1e4e89SAndroid Build Coastguard Worker dlh = dlopen(buf, RTLD_LAZY);
143*de1e4e89SAndroid Build Coastguard Worker if (dlh == NULL) {
144*de1e4e89SAndroid Build Coastguard Worker dlh = body;
145*de1e4e89SAndroid Build Coastguard Worker if (dlh == NULL) {
146*de1e4e89SAndroid Build Coastguard Worker dlh = body = dlopen(NULL, RTLD_LAZY);
147*de1e4e89SAndroid Build Coastguard Worker if (dlh == NULL)
148*de1e4e89SAndroid Build Coastguard Worker return NULL;
149*de1e4e89SAndroid Build Coastguard Worker }
150*de1e4e89SAndroid Build Coastguard Worker }
151*de1e4e89SAndroid Build Coastguard Worker
152*de1e4e89SAndroid Build Coastguard Worker snprintf(buf, sizeof(buf), "%s_ematch_util", kind);
153*de1e4e89SAndroid Build Coastguard Worker e = dlsym(dlh, buf);
154*de1e4e89SAndroid Build Coastguard Worker if (e == NULL)
155*de1e4e89SAndroid Build Coastguard Worker return NULL;
156*de1e4e89SAndroid Build Coastguard Worker
157*de1e4e89SAndroid Build Coastguard Worker e->next = ematch_list;
158*de1e4e89SAndroid Build Coastguard Worker ematch_list = e;
159*de1e4e89SAndroid Build Coastguard Worker
160*de1e4e89SAndroid Build Coastguard Worker return e;
161*de1e4e89SAndroid Build Coastguard Worker }
162*de1e4e89SAndroid Build Coastguard Worker
get_ematch_kind_num(__u16 kind)163*de1e4e89SAndroid Build Coastguard Worker static struct ematch_util *get_ematch_kind_num(__u16 kind)
164*de1e4e89SAndroid Build Coastguard Worker {
165*de1e4e89SAndroid Build Coastguard Worker char name[32];
166*de1e4e89SAndroid Build Coastguard Worker
167*de1e4e89SAndroid Build Coastguard Worker if (lookup_map(kind, name, sizeof(name), EMATCH_MAP) < 0)
168*de1e4e89SAndroid Build Coastguard Worker return NULL;
169*de1e4e89SAndroid Build Coastguard Worker
170*de1e4e89SAndroid Build Coastguard Worker return get_ematch_kind(name);
171*de1e4e89SAndroid Build Coastguard Worker }
172*de1e4e89SAndroid Build Coastguard Worker
parse_tree(struct nlmsghdr * n,struct ematch * tree)173*de1e4e89SAndroid Build Coastguard Worker static int parse_tree(struct nlmsghdr *n, struct ematch *tree)
174*de1e4e89SAndroid Build Coastguard Worker {
175*de1e4e89SAndroid Build Coastguard Worker int index = 1;
176*de1e4e89SAndroid Build Coastguard Worker struct ematch *t;
177*de1e4e89SAndroid Build Coastguard Worker
178*de1e4e89SAndroid Build Coastguard Worker for (t = tree; t; t = t->next) {
179*de1e4e89SAndroid Build Coastguard Worker struct rtattr *tail = NLMSG_TAIL(n);
180*de1e4e89SAndroid Build Coastguard Worker struct tcf_ematch_hdr hdr = { .flags = t->relation };
181*de1e4e89SAndroid Build Coastguard Worker
182*de1e4e89SAndroid Build Coastguard Worker if (t->inverted)
183*de1e4e89SAndroid Build Coastguard Worker hdr.flags |= TCF_EM_INVERT;
184*de1e4e89SAndroid Build Coastguard Worker
185*de1e4e89SAndroid Build Coastguard Worker addattr_l(n, MAX_MSG, index++, NULL, 0);
186*de1e4e89SAndroid Build Coastguard Worker
187*de1e4e89SAndroid Build Coastguard Worker if (t->child) {
188*de1e4e89SAndroid Build Coastguard Worker __u32 r = t->child_ref;
189*de1e4e89SAndroid Build Coastguard Worker
190*de1e4e89SAndroid Build Coastguard Worker addraw_l(n, MAX_MSG, &hdr, sizeof(hdr));
191*de1e4e89SAndroid Build Coastguard Worker addraw_l(n, MAX_MSG, &r, sizeof(r));
192*de1e4e89SAndroid Build Coastguard Worker } else {
193*de1e4e89SAndroid Build Coastguard Worker int num = 0, err;
194*de1e4e89SAndroid Build Coastguard Worker char buf[64];
195*de1e4e89SAndroid Build Coastguard Worker struct ematch_util *e;
196*de1e4e89SAndroid Build Coastguard Worker
197*de1e4e89SAndroid Build Coastguard Worker if (t->args == NULL)
198*de1e4e89SAndroid Build Coastguard Worker return -1;
199*de1e4e89SAndroid Build Coastguard Worker
200*de1e4e89SAndroid Build Coastguard Worker strncpy(buf, (char *) t->args->data, sizeof(buf)-1);
201*de1e4e89SAndroid Build Coastguard Worker e = get_ematch_kind(buf);
202*de1e4e89SAndroid Build Coastguard Worker if (e == NULL) {
203*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Unknown ematch \"%s\"\n",
204*de1e4e89SAndroid Build Coastguard Worker buf);
205*de1e4e89SAndroid Build Coastguard Worker return -1;
206*de1e4e89SAndroid Build Coastguard Worker }
207*de1e4e89SAndroid Build Coastguard Worker
208*de1e4e89SAndroid Build Coastguard Worker err = lookup_map_id(buf, &num, EMATCH_MAP);
209*de1e4e89SAndroid Build Coastguard Worker if (err < 0) {
210*de1e4e89SAndroid Build Coastguard Worker if (err == -ENOENT)
211*de1e4e89SAndroid Build Coastguard Worker map_warning(e->kind_num, buf);
212*de1e4e89SAndroid Build Coastguard Worker return err;
213*de1e4e89SAndroid Build Coastguard Worker }
214*de1e4e89SAndroid Build Coastguard Worker
215*de1e4e89SAndroid Build Coastguard Worker hdr.kind = num;
216*de1e4e89SAndroid Build Coastguard Worker if (e->parse_eopt(n, &hdr, t->args->next) < 0)
217*de1e4e89SAndroid Build Coastguard Worker return -1;
218*de1e4e89SAndroid Build Coastguard Worker }
219*de1e4e89SAndroid Build Coastguard Worker
220*de1e4e89SAndroid Build Coastguard Worker tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
221*de1e4e89SAndroid Build Coastguard Worker }
222*de1e4e89SAndroid Build Coastguard Worker
223*de1e4e89SAndroid Build Coastguard Worker return 0;
224*de1e4e89SAndroid Build Coastguard Worker }
225*de1e4e89SAndroid Build Coastguard Worker
flatten_tree(struct ematch * head,struct ematch * tree)226*de1e4e89SAndroid Build Coastguard Worker static int flatten_tree(struct ematch *head, struct ematch *tree)
227*de1e4e89SAndroid Build Coastguard Worker {
228*de1e4e89SAndroid Build Coastguard Worker int i, count = 0;
229*de1e4e89SAndroid Build Coastguard Worker struct ematch *t;
230*de1e4e89SAndroid Build Coastguard Worker
231*de1e4e89SAndroid Build Coastguard Worker for (;;) {
232*de1e4e89SAndroid Build Coastguard Worker count++;
233*de1e4e89SAndroid Build Coastguard Worker
234*de1e4e89SAndroid Build Coastguard Worker if (tree->child) {
235*de1e4e89SAndroid Build Coastguard Worker for (t = head; t->next; t = t->next);
236*de1e4e89SAndroid Build Coastguard Worker t->next = tree->child;
237*de1e4e89SAndroid Build Coastguard Worker count += flatten_tree(head, tree->child);
238*de1e4e89SAndroid Build Coastguard Worker }
239*de1e4e89SAndroid Build Coastguard Worker
240*de1e4e89SAndroid Build Coastguard Worker if (tree->relation == 0)
241*de1e4e89SAndroid Build Coastguard Worker break;
242*de1e4e89SAndroid Build Coastguard Worker
243*de1e4e89SAndroid Build Coastguard Worker tree = tree->next;
244*de1e4e89SAndroid Build Coastguard Worker }
245*de1e4e89SAndroid Build Coastguard Worker
246*de1e4e89SAndroid Build Coastguard Worker for (i = 0, t = head; t; t = t->next, i++)
247*de1e4e89SAndroid Build Coastguard Worker t->index = i;
248*de1e4e89SAndroid Build Coastguard Worker
249*de1e4e89SAndroid Build Coastguard Worker for (t = head; t; t = t->next)
250*de1e4e89SAndroid Build Coastguard Worker if (t->child)
251*de1e4e89SAndroid Build Coastguard Worker t->child_ref = t->child->index;
252*de1e4e89SAndroid Build Coastguard Worker
253*de1e4e89SAndroid Build Coastguard Worker return count;
254*de1e4e89SAndroid Build Coastguard Worker }
255*de1e4e89SAndroid Build Coastguard Worker
em_parse_error(int err,struct bstr * args,struct bstr * carg,struct ematch_util * e,char * fmt,...)256*de1e4e89SAndroid Build Coastguard Worker int em_parse_error(int err, struct bstr *args, struct bstr *carg,
257*de1e4e89SAndroid Build Coastguard Worker struct ematch_util *e, char *fmt, ...)
258*de1e4e89SAndroid Build Coastguard Worker {
259*de1e4e89SAndroid Build Coastguard Worker va_list a;
260*de1e4e89SAndroid Build Coastguard Worker
261*de1e4e89SAndroid Build Coastguard Worker va_start(a, fmt);
262*de1e4e89SAndroid Build Coastguard Worker vfprintf(stderr, fmt, a);
263*de1e4e89SAndroid Build Coastguard Worker va_end(a);
264*de1e4e89SAndroid Build Coastguard Worker
265*de1e4e89SAndroid Build Coastguard Worker if (ematch_err)
266*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, ": %s\n... ", ematch_err);
267*de1e4e89SAndroid Build Coastguard Worker else
268*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "\n... ");
269*de1e4e89SAndroid Build Coastguard Worker
270*de1e4e89SAndroid Build Coastguard Worker while (ematch_argc < begin_argc) {
271*de1e4e89SAndroid Build Coastguard Worker if (ematch_argc == (begin_argc - 1))
272*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, ">>%s<< ", *begin_argv);
273*de1e4e89SAndroid Build Coastguard Worker else
274*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "%s ", *begin_argv);
275*de1e4e89SAndroid Build Coastguard Worker begin_argv++;
276*de1e4e89SAndroid Build Coastguard Worker begin_argc--;
277*de1e4e89SAndroid Build Coastguard Worker }
278*de1e4e89SAndroid Build Coastguard Worker
279*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "...\n");
280*de1e4e89SAndroid Build Coastguard Worker
281*de1e4e89SAndroid Build Coastguard Worker if (args) {
282*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "... %s(", e->kind);
283*de1e4e89SAndroid Build Coastguard Worker while (args) {
284*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "%s", args == carg ? ">>" : "");
285*de1e4e89SAndroid Build Coastguard Worker bstr_print(stderr, args, 1);
286*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "%s%s", args == carg ? "<<" : "",
287*de1e4e89SAndroid Build Coastguard Worker args->next ? " " : "");
288*de1e4e89SAndroid Build Coastguard Worker args = args->next;
289*de1e4e89SAndroid Build Coastguard Worker }
290*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, ")...\n");
291*de1e4e89SAndroid Build Coastguard Worker
292*de1e4e89SAndroid Build Coastguard Worker }
293*de1e4e89SAndroid Build Coastguard Worker
294*de1e4e89SAndroid Build Coastguard Worker if (e == NULL) {
295*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr,
296*de1e4e89SAndroid Build Coastguard Worker "Usage: EXPR\n" \
297*de1e4e89SAndroid Build Coastguard Worker "where: EXPR := TERM [ { and | or } EXPR ]\n" \
298*de1e4e89SAndroid Build Coastguard Worker " TERM := [ not ] { MATCH | '(' EXPR ')' }\n" \
299*de1e4e89SAndroid Build Coastguard Worker " MATCH := module '(' ARGS ')'\n" \
300*de1e4e89SAndroid Build Coastguard Worker " ARGS := ARG1 ARG2 ...\n" \
301*de1e4e89SAndroid Build Coastguard Worker "\n" \
302*de1e4e89SAndroid Build Coastguard Worker "Example: a(x y) and not (b(x) or c(x y z))\n");
303*de1e4e89SAndroid Build Coastguard Worker } else
304*de1e4e89SAndroid Build Coastguard Worker e->print_usage(stderr);
305*de1e4e89SAndroid Build Coastguard Worker
306*de1e4e89SAndroid Build Coastguard Worker return -err;
307*de1e4e89SAndroid Build Coastguard Worker }
308*de1e4e89SAndroid Build Coastguard Worker
free_ematch_err(void)309*de1e4e89SAndroid Build Coastguard Worker static inline void free_ematch_err(void)
310*de1e4e89SAndroid Build Coastguard Worker {
311*de1e4e89SAndroid Build Coastguard Worker if (ematch_err) {
312*de1e4e89SAndroid Build Coastguard Worker free(ematch_err);
313*de1e4e89SAndroid Build Coastguard Worker ematch_err = NULL;
314*de1e4e89SAndroid Build Coastguard Worker }
315*de1e4e89SAndroid Build Coastguard Worker }
316*de1e4e89SAndroid Build Coastguard Worker
317*de1e4e89SAndroid Build Coastguard Worker extern int ematch_parse(void);
318*de1e4e89SAndroid Build Coastguard Worker
parse_ematch(int * argc_p,char *** argv_p,int tca_id,struct nlmsghdr * n)319*de1e4e89SAndroid Build Coastguard Worker int parse_ematch(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n)
320*de1e4e89SAndroid Build Coastguard Worker {
321*de1e4e89SAndroid Build Coastguard Worker begin_argc = ematch_argc = *argc_p;
322*de1e4e89SAndroid Build Coastguard Worker begin_argv = ematch_argv = *argv_p;
323*de1e4e89SAndroid Build Coastguard Worker
324*de1e4e89SAndroid Build Coastguard Worker if (ematch_parse()) {
325*de1e4e89SAndroid Build Coastguard Worker int err = em_parse_error(EINVAL, NULL, NULL, NULL,
326*de1e4e89SAndroid Build Coastguard Worker "Parse error");
327*de1e4e89SAndroid Build Coastguard Worker free_ematch_err();
328*de1e4e89SAndroid Build Coastguard Worker return err;
329*de1e4e89SAndroid Build Coastguard Worker }
330*de1e4e89SAndroid Build Coastguard Worker
331*de1e4e89SAndroid Build Coastguard Worker free_ematch_err();
332*de1e4e89SAndroid Build Coastguard Worker
333*de1e4e89SAndroid Build Coastguard Worker /* undo look ahead by parser */
334*de1e4e89SAndroid Build Coastguard Worker ematch_argc++;
335*de1e4e89SAndroid Build Coastguard Worker ematch_argv--;
336*de1e4e89SAndroid Build Coastguard Worker
337*de1e4e89SAndroid Build Coastguard Worker if (ematch_root) {
338*de1e4e89SAndroid Build Coastguard Worker struct rtattr *tail, *tail_list;
339*de1e4e89SAndroid Build Coastguard Worker
340*de1e4e89SAndroid Build Coastguard Worker struct tcf_ematch_tree_hdr hdr = {
341*de1e4e89SAndroid Build Coastguard Worker .nmatches = flatten_tree(ematch_root, ematch_root),
342*de1e4e89SAndroid Build Coastguard Worker .progid = TCF_EM_PROG_TC
343*de1e4e89SAndroid Build Coastguard Worker };
344*de1e4e89SAndroid Build Coastguard Worker
345*de1e4e89SAndroid Build Coastguard Worker tail = NLMSG_TAIL(n);
346*de1e4e89SAndroid Build Coastguard Worker addattr_l(n, MAX_MSG, tca_id, NULL, 0);
347*de1e4e89SAndroid Build Coastguard Worker addattr_l(n, MAX_MSG, TCA_EMATCH_TREE_HDR, &hdr, sizeof(hdr));
348*de1e4e89SAndroid Build Coastguard Worker
349*de1e4e89SAndroid Build Coastguard Worker tail_list = NLMSG_TAIL(n);
350*de1e4e89SAndroid Build Coastguard Worker addattr_l(n, MAX_MSG, TCA_EMATCH_TREE_LIST, NULL, 0);
351*de1e4e89SAndroid Build Coastguard Worker
352*de1e4e89SAndroid Build Coastguard Worker if (parse_tree(n, ematch_root) < 0)
353*de1e4e89SAndroid Build Coastguard Worker return -1;
354*de1e4e89SAndroid Build Coastguard Worker
355*de1e4e89SAndroid Build Coastguard Worker tail_list->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail_list;
356*de1e4e89SAndroid Build Coastguard Worker tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
357*de1e4e89SAndroid Build Coastguard Worker }
358*de1e4e89SAndroid Build Coastguard Worker
359*de1e4e89SAndroid Build Coastguard Worker *argc_p = ematch_argc;
360*de1e4e89SAndroid Build Coastguard Worker *argv_p = ematch_argv;
361*de1e4e89SAndroid Build Coastguard Worker
362*de1e4e89SAndroid Build Coastguard Worker return 0;
363*de1e4e89SAndroid Build Coastguard Worker }
364*de1e4e89SAndroid Build Coastguard Worker
print_ematch_seq(FILE * fd,struct rtattr ** tb,int start,int prefix)365*de1e4e89SAndroid Build Coastguard Worker static int print_ematch_seq(FILE *fd, struct rtattr **tb, int start,
366*de1e4e89SAndroid Build Coastguard Worker int prefix)
367*de1e4e89SAndroid Build Coastguard Worker {
368*de1e4e89SAndroid Build Coastguard Worker int n, i = start;
369*de1e4e89SAndroid Build Coastguard Worker struct tcf_ematch_hdr *hdr;
370*de1e4e89SAndroid Build Coastguard Worker int dlen;
371*de1e4e89SAndroid Build Coastguard Worker void *data;
372*de1e4e89SAndroid Build Coastguard Worker
373*de1e4e89SAndroid Build Coastguard Worker for (;;) {
374*de1e4e89SAndroid Build Coastguard Worker if (tb[i] == NULL)
375*de1e4e89SAndroid Build Coastguard Worker return -1;
376*de1e4e89SAndroid Build Coastguard Worker
377*de1e4e89SAndroid Build Coastguard Worker dlen = RTA_PAYLOAD(tb[i]) - sizeof(*hdr);
378*de1e4e89SAndroid Build Coastguard Worker data = (void *) RTA_DATA(tb[i]) + sizeof(*hdr);
379*de1e4e89SAndroid Build Coastguard Worker
380*de1e4e89SAndroid Build Coastguard Worker if (dlen < 0)
381*de1e4e89SAndroid Build Coastguard Worker return -1;
382*de1e4e89SAndroid Build Coastguard Worker
383*de1e4e89SAndroid Build Coastguard Worker hdr = RTA_DATA(tb[i]);
384*de1e4e89SAndroid Build Coastguard Worker
385*de1e4e89SAndroid Build Coastguard Worker if (hdr->flags & TCF_EM_INVERT)
386*de1e4e89SAndroid Build Coastguard Worker fprintf(fd, "NOT ");
387*de1e4e89SAndroid Build Coastguard Worker
388*de1e4e89SAndroid Build Coastguard Worker if (hdr->kind == 0) {
389*de1e4e89SAndroid Build Coastguard Worker __u32 ref;
390*de1e4e89SAndroid Build Coastguard Worker
391*de1e4e89SAndroid Build Coastguard Worker if (dlen < sizeof(__u32))
392*de1e4e89SAndroid Build Coastguard Worker return -1;
393*de1e4e89SAndroid Build Coastguard Worker
394*de1e4e89SAndroid Build Coastguard Worker ref = *(__u32 *) data;
395*de1e4e89SAndroid Build Coastguard Worker fprintf(fd, "(\n");
396*de1e4e89SAndroid Build Coastguard Worker for (n = 0; n <= prefix; n++)
397*de1e4e89SAndroid Build Coastguard Worker fprintf(fd, " ");
398*de1e4e89SAndroid Build Coastguard Worker if (print_ematch_seq(fd, tb, ref + 1, prefix + 1) < 0)
399*de1e4e89SAndroid Build Coastguard Worker return -1;
400*de1e4e89SAndroid Build Coastguard Worker for (n = 0; n < prefix; n++)
401*de1e4e89SAndroid Build Coastguard Worker fprintf(fd, " ");
402*de1e4e89SAndroid Build Coastguard Worker fprintf(fd, ") ");
403*de1e4e89SAndroid Build Coastguard Worker
404*de1e4e89SAndroid Build Coastguard Worker } else {
405*de1e4e89SAndroid Build Coastguard Worker struct ematch_util *e;
406*de1e4e89SAndroid Build Coastguard Worker
407*de1e4e89SAndroid Build Coastguard Worker e = get_ematch_kind_num(hdr->kind);
408*de1e4e89SAndroid Build Coastguard Worker if (e == NULL)
409*de1e4e89SAndroid Build Coastguard Worker fprintf(fd, "[unknown ematch %d]\n",
410*de1e4e89SAndroid Build Coastguard Worker hdr->kind);
411*de1e4e89SAndroid Build Coastguard Worker else {
412*de1e4e89SAndroid Build Coastguard Worker fprintf(fd, "%s(", e->kind);
413*de1e4e89SAndroid Build Coastguard Worker if (e->print_eopt(fd, hdr, data, dlen) < 0)
414*de1e4e89SAndroid Build Coastguard Worker return -1;
415*de1e4e89SAndroid Build Coastguard Worker fprintf(fd, ")\n");
416*de1e4e89SAndroid Build Coastguard Worker }
417*de1e4e89SAndroid Build Coastguard Worker if (hdr->flags & TCF_EM_REL_MASK)
418*de1e4e89SAndroid Build Coastguard Worker for (n = 0; n < prefix; n++)
419*de1e4e89SAndroid Build Coastguard Worker fprintf(fd, " ");
420*de1e4e89SAndroid Build Coastguard Worker }
421*de1e4e89SAndroid Build Coastguard Worker
422*de1e4e89SAndroid Build Coastguard Worker switch (hdr->flags & TCF_EM_REL_MASK) {
423*de1e4e89SAndroid Build Coastguard Worker case TCF_EM_REL_AND:
424*de1e4e89SAndroid Build Coastguard Worker fprintf(fd, "AND ");
425*de1e4e89SAndroid Build Coastguard Worker break;
426*de1e4e89SAndroid Build Coastguard Worker
427*de1e4e89SAndroid Build Coastguard Worker case TCF_EM_REL_OR:
428*de1e4e89SAndroid Build Coastguard Worker fprintf(fd, "OR ");
429*de1e4e89SAndroid Build Coastguard Worker break;
430*de1e4e89SAndroid Build Coastguard Worker
431*de1e4e89SAndroid Build Coastguard Worker default:
432*de1e4e89SAndroid Build Coastguard Worker return 0;
433*de1e4e89SAndroid Build Coastguard Worker }
434*de1e4e89SAndroid Build Coastguard Worker
435*de1e4e89SAndroid Build Coastguard Worker i++;
436*de1e4e89SAndroid Build Coastguard Worker }
437*de1e4e89SAndroid Build Coastguard Worker
438*de1e4e89SAndroid Build Coastguard Worker return 0;
439*de1e4e89SAndroid Build Coastguard Worker }
440*de1e4e89SAndroid Build Coastguard Worker
print_ematch_list(FILE * fd,struct tcf_ematch_tree_hdr * hdr,struct rtattr * rta)441*de1e4e89SAndroid Build Coastguard Worker static int print_ematch_list(FILE *fd, struct tcf_ematch_tree_hdr *hdr,
442*de1e4e89SAndroid Build Coastguard Worker struct rtattr *rta)
443*de1e4e89SAndroid Build Coastguard Worker {
444*de1e4e89SAndroid Build Coastguard Worker int err = -1;
445*de1e4e89SAndroid Build Coastguard Worker struct rtattr **tb;
446*de1e4e89SAndroid Build Coastguard Worker
447*de1e4e89SAndroid Build Coastguard Worker tb = malloc((hdr->nmatches + 1) * sizeof(struct rtattr *));
448*de1e4e89SAndroid Build Coastguard Worker if (tb == NULL)
449*de1e4e89SAndroid Build Coastguard Worker return -1;
450*de1e4e89SAndroid Build Coastguard Worker
451*de1e4e89SAndroid Build Coastguard Worker if (hdr->nmatches > 0) {
452*de1e4e89SAndroid Build Coastguard Worker if (parse_rtattr_nested(tb, hdr->nmatches, rta) < 0)
453*de1e4e89SAndroid Build Coastguard Worker goto errout;
454*de1e4e89SAndroid Build Coastguard Worker
455*de1e4e89SAndroid Build Coastguard Worker fprintf(fd, "\n ");
456*de1e4e89SAndroid Build Coastguard Worker if (print_ematch_seq(fd, tb, 1, 1) < 0)
457*de1e4e89SAndroid Build Coastguard Worker goto errout;
458*de1e4e89SAndroid Build Coastguard Worker }
459*de1e4e89SAndroid Build Coastguard Worker
460*de1e4e89SAndroid Build Coastguard Worker err = 0;
461*de1e4e89SAndroid Build Coastguard Worker errout:
462*de1e4e89SAndroid Build Coastguard Worker free(tb);
463*de1e4e89SAndroid Build Coastguard Worker return err;
464*de1e4e89SAndroid Build Coastguard Worker }
465*de1e4e89SAndroid Build Coastguard Worker
print_ematch(FILE * fd,const struct rtattr * rta)466*de1e4e89SAndroid Build Coastguard Worker int print_ematch(FILE *fd, const struct rtattr *rta)
467*de1e4e89SAndroid Build Coastguard Worker {
468*de1e4e89SAndroid Build Coastguard Worker struct rtattr *tb[TCA_EMATCH_TREE_MAX+1];
469*de1e4e89SAndroid Build Coastguard Worker struct tcf_ematch_tree_hdr *hdr;
470*de1e4e89SAndroid Build Coastguard Worker
471*de1e4e89SAndroid Build Coastguard Worker if (parse_rtattr_nested(tb, TCA_EMATCH_TREE_MAX, rta) < 0)
472*de1e4e89SAndroid Build Coastguard Worker return -1;
473*de1e4e89SAndroid Build Coastguard Worker
474*de1e4e89SAndroid Build Coastguard Worker if (tb[TCA_EMATCH_TREE_HDR] == NULL) {
475*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Missing ematch tree header\n");
476*de1e4e89SAndroid Build Coastguard Worker return -1;
477*de1e4e89SAndroid Build Coastguard Worker }
478*de1e4e89SAndroid Build Coastguard Worker
479*de1e4e89SAndroid Build Coastguard Worker if (tb[TCA_EMATCH_TREE_LIST] == NULL) {
480*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Missing ematch tree list\n");
481*de1e4e89SAndroid Build Coastguard Worker return -1;
482*de1e4e89SAndroid Build Coastguard Worker }
483*de1e4e89SAndroid Build Coastguard Worker
484*de1e4e89SAndroid Build Coastguard Worker if (RTA_PAYLOAD(tb[TCA_EMATCH_TREE_HDR]) < sizeof(*hdr)) {
485*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Ematch tree header size mismatch\n");
486*de1e4e89SAndroid Build Coastguard Worker return -1;
487*de1e4e89SAndroid Build Coastguard Worker }
488*de1e4e89SAndroid Build Coastguard Worker
489*de1e4e89SAndroid Build Coastguard Worker hdr = RTA_DATA(tb[TCA_EMATCH_TREE_HDR]);
490*de1e4e89SAndroid Build Coastguard Worker
491*de1e4e89SAndroid Build Coastguard Worker return print_ematch_list(fd, hdr, tb[TCA_EMATCH_TREE_LIST]);
492*de1e4e89SAndroid Build Coastguard Worker }
493*de1e4e89SAndroid Build Coastguard Worker
bstr_alloc(const char * text)494*de1e4e89SAndroid Build Coastguard Worker struct bstr *bstr_alloc(const char *text)
495*de1e4e89SAndroid Build Coastguard Worker {
496*de1e4e89SAndroid Build Coastguard Worker struct bstr *b = calloc(1, sizeof(*b));
497*de1e4e89SAndroid Build Coastguard Worker
498*de1e4e89SAndroid Build Coastguard Worker if (b == NULL)
499*de1e4e89SAndroid Build Coastguard Worker return NULL;
500*de1e4e89SAndroid Build Coastguard Worker
501*de1e4e89SAndroid Build Coastguard Worker b->data = strdup(text);
502*de1e4e89SAndroid Build Coastguard Worker if (b->data == NULL) {
503*de1e4e89SAndroid Build Coastguard Worker free(b);
504*de1e4e89SAndroid Build Coastguard Worker return NULL;
505*de1e4e89SAndroid Build Coastguard Worker }
506*de1e4e89SAndroid Build Coastguard Worker
507*de1e4e89SAndroid Build Coastguard Worker b->len = strlen(text);
508*de1e4e89SAndroid Build Coastguard Worker
509*de1e4e89SAndroid Build Coastguard Worker return b;
510*de1e4e89SAndroid Build Coastguard Worker }
511*de1e4e89SAndroid Build Coastguard Worker
bstrtoul(const struct bstr * b)512*de1e4e89SAndroid Build Coastguard Worker unsigned long bstrtoul(const struct bstr *b)
513*de1e4e89SAndroid Build Coastguard Worker {
514*de1e4e89SAndroid Build Coastguard Worker char *inv = NULL;
515*de1e4e89SAndroid Build Coastguard Worker unsigned long l;
516*de1e4e89SAndroid Build Coastguard Worker char buf[b->len+1];
517*de1e4e89SAndroid Build Coastguard Worker
518*de1e4e89SAndroid Build Coastguard Worker memcpy(buf, b->data, b->len);
519*de1e4e89SAndroid Build Coastguard Worker buf[b->len] = '\0';
520*de1e4e89SAndroid Build Coastguard Worker
521*de1e4e89SAndroid Build Coastguard Worker l = strtoul(buf, &inv, 0);
522*de1e4e89SAndroid Build Coastguard Worker if (l == ULONG_MAX || inv == buf)
523*de1e4e89SAndroid Build Coastguard Worker return ULONG_MAX;
524*de1e4e89SAndroid Build Coastguard Worker
525*de1e4e89SAndroid Build Coastguard Worker return l;
526*de1e4e89SAndroid Build Coastguard Worker }
527*de1e4e89SAndroid Build Coastguard Worker
bstr_print(FILE * fd,const struct bstr * b,int ascii)528*de1e4e89SAndroid Build Coastguard Worker void bstr_print(FILE *fd, const struct bstr *b, int ascii)
529*de1e4e89SAndroid Build Coastguard Worker {
530*de1e4e89SAndroid Build Coastguard Worker int i;
531*de1e4e89SAndroid Build Coastguard Worker char *s = b->data;
532*de1e4e89SAndroid Build Coastguard Worker
533*de1e4e89SAndroid Build Coastguard Worker if (ascii)
534*de1e4e89SAndroid Build Coastguard Worker for (i = 0; i < b->len; i++)
535*de1e4e89SAndroid Build Coastguard Worker fprintf(fd, "%c", isprint(s[i]) ? s[i] : '.');
536*de1e4e89SAndroid Build Coastguard Worker else {
537*de1e4e89SAndroid Build Coastguard Worker for (i = 0; i < b->len; i++)
538*de1e4e89SAndroid Build Coastguard Worker fprintf(fd, "%02x", s[i]);
539*de1e4e89SAndroid Build Coastguard Worker fprintf(fd, "\"");
540*de1e4e89SAndroid Build Coastguard Worker for (i = 0; i < b->len; i++)
541*de1e4e89SAndroid Build Coastguard Worker fprintf(fd, "%c", isprint(s[i]) ? s[i] : '.');
542*de1e4e89SAndroid Build Coastguard Worker fprintf(fd, "\"");
543*de1e4e89SAndroid Build Coastguard Worker }
544*de1e4e89SAndroid Build Coastguard Worker }
545*de1e4e89SAndroid Build Coastguard Worker
print_ematch_tree(const struct ematch * tree)546*de1e4e89SAndroid Build Coastguard Worker void print_ematch_tree(const struct ematch *tree)
547*de1e4e89SAndroid Build Coastguard Worker {
548*de1e4e89SAndroid Build Coastguard Worker const struct ematch *t;
549*de1e4e89SAndroid Build Coastguard Worker
550*de1e4e89SAndroid Build Coastguard Worker for (t = tree; t; t = t->next) {
551*de1e4e89SAndroid Build Coastguard Worker if (t->inverted)
552*de1e4e89SAndroid Build Coastguard Worker printf("NOT ");
553*de1e4e89SAndroid Build Coastguard Worker
554*de1e4e89SAndroid Build Coastguard Worker if (t->child) {
555*de1e4e89SAndroid Build Coastguard Worker printf("(");
556*de1e4e89SAndroid Build Coastguard Worker print_ematch_tree(t->child);
557*de1e4e89SAndroid Build Coastguard Worker printf(")");
558*de1e4e89SAndroid Build Coastguard Worker } else {
559*de1e4e89SAndroid Build Coastguard Worker struct bstr *b;
560*de1e4e89SAndroid Build Coastguard Worker
561*de1e4e89SAndroid Build Coastguard Worker for (b = t->args; b; b = b->next)
562*de1e4e89SAndroid Build Coastguard Worker printf("%s%s", b->data, b->next ? " " : "");
563*de1e4e89SAndroid Build Coastguard Worker }
564*de1e4e89SAndroid Build Coastguard Worker
565*de1e4e89SAndroid Build Coastguard Worker if (t->relation == TCF_EM_REL_AND)
566*de1e4e89SAndroid Build Coastguard Worker printf(" AND ");
567*de1e4e89SAndroid Build Coastguard Worker else if (t->relation == TCF_EM_REL_OR)
568*de1e4e89SAndroid Build Coastguard Worker printf(" OR ");
569*de1e4e89SAndroid Build Coastguard Worker }
570*de1e4e89SAndroid Build Coastguard Worker }
571