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