|
Packit |
d3f73b |
/*
|
|
Packit |
d3f73b |
* m_ematch.c Extended Matches
|
|
Packit |
d3f73b |
*
|
|
Packit |
d3f73b |
* This program is free software; you can distribute it and/or
|
|
Packit |
d3f73b |
* modify it under the terms of the GNU General Public License
|
|
Packit |
d3f73b |
* as published by the Free Software Foundation; either version
|
|
Packit |
d3f73b |
* 2 of the License, or (at your option) any later version.
|
|
Packit |
d3f73b |
*
|
|
Packit |
d3f73b |
* Authors: Thomas Graf <tgraf@suug.ch>
|
|
Packit |
d3f73b |
*/
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
#include <stdio.h>
|
|
Packit |
d3f73b |
#include <stdlib.h>
|
|
Packit |
d3f73b |
#include <unistd.h>
|
|
Packit |
d3f73b |
#include <fcntl.h>
|
|
Packit |
d3f73b |
#include <sys/socket.h>
|
|
Packit |
d3f73b |
#include <netinet/in.h>
|
|
Packit |
d3f73b |
#include <arpa/inet.h>
|
|
Packit |
d3f73b |
#include <string.h>
|
|
Packit |
d3f73b |
#include <dlfcn.h>
|
|
Packit |
d3f73b |
#include <stdarg.h>
|
|
Packit |
d3f73b |
#include <errno.h>
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
#include "utils.h"
|
|
Packit |
d3f73b |
#include "tc_util.h"
|
|
Packit |
d3f73b |
#include "m_ematch.h"
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
#define EMATCH_MAP "/etc/iproute2/ematch_map"
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
static struct ematch_util *ematch_list;
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
/* export to bison parser */
|
|
Packit |
d3f73b |
int ematch_argc;
|
|
Packit |
d3f73b |
char **ematch_argv;
|
|
Packit |
d3f73b |
char *ematch_err;
|
|
Packit |
d3f73b |
struct ematch *ematch_root;
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
static int begin_argc;
|
|
Packit |
d3f73b |
static char **begin_argv;
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
static void bstr_print(FILE *fd, const struct bstr *b, int ascii);
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
static inline void map_warning(int num, char *kind)
|
|
Packit |
d3f73b |
{
|
|
Packit |
d3f73b |
fprintf(stderr,
|
|
Packit |
d3f73b |
"Error: Unable to find ematch \"%s\" in %s\n" \
|
|
Packit |
d3f73b |
"Please assign a unique ID to the ematch kind the suggested " \
|
|
Packit |
d3f73b |
"entry is:\n" \
|
|
Packit |
d3f73b |
"\t%d\t%s\n",
|
|
Packit |
d3f73b |
kind, EMATCH_MAP, num, kind);
|
|
Packit |
d3f73b |
}
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
static int lookup_map(__u16 num, char *dst, int len, const char *file)
|
|
Packit |
d3f73b |
{
|
|
Packit |
d3f73b |
int err = -EINVAL;
|
|
Packit |
d3f73b |
char buf[512];
|
|
Packit |
d3f73b |
FILE *fd = fopen(file, "r");
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
if (fd == NULL)
|
|
Packit |
d3f73b |
return -errno;
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
while (fgets(buf, sizeof(buf), fd)) {
|
|
Packit |
d3f73b |
char namebuf[512], *p = buf;
|
|
Packit |
d3f73b |
int id;
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
while (*p == ' ' || *p == '\t')
|
|
Packit |
d3f73b |
p++;
|
|
Packit |
d3f73b |
if (*p == '#' || *p == '\n' || *p == 0)
|
|
Packit |
d3f73b |
continue;
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
if (sscanf(p, "%d %s", &id, namebuf) != 2) {
|
|
Packit |
d3f73b |
fprintf(stderr, "ematch map %s corrupted at %s\n",
|
|
Packit |
d3f73b |
file, p);
|
|
Packit |
d3f73b |
goto out;
|
|
Packit |
d3f73b |
}
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
if (id == num) {
|
|
Packit |
d3f73b |
if (dst)
|
|
Packit |
d3f73b |
strncpy(dst, namebuf, len - 1);
|
|
Packit |
d3f73b |
err = 0;
|
|
Packit |
d3f73b |
goto out;
|
|
Packit |
d3f73b |
}
|
|
Packit |
d3f73b |
}
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
err = -ENOENT;
|
|
Packit |
d3f73b |
out:
|
|
Packit |
d3f73b |
fclose(fd);
|
|
Packit |
d3f73b |
return err;
|
|
Packit |
d3f73b |
}
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
static int lookup_map_id(char *kind, int *dst, const char *file)
|
|
Packit |
d3f73b |
{
|
|
Packit |
d3f73b |
int err = -EINVAL;
|
|
Packit |
d3f73b |
char buf[512];
|
|
Packit |
d3f73b |
FILE *fd = fopen(file, "r");
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
if (fd == NULL)
|
|
Packit |
d3f73b |
return -errno;
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
while (fgets(buf, sizeof(buf), fd)) {
|
|
Packit |
d3f73b |
char namebuf[512], *p = buf;
|
|
Packit |
d3f73b |
int id;
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
while (*p == ' ' || *p == '\t')
|
|
Packit |
d3f73b |
p++;
|
|
Packit |
d3f73b |
if (*p == '#' || *p == '\n' || *p == 0)
|
|
Packit |
d3f73b |
continue;
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
if (sscanf(p, "%d %s", &id, namebuf) != 2) {
|
|
Packit |
d3f73b |
fprintf(stderr, "ematch map %s corrupted at %s\n",
|
|
Packit |
d3f73b |
file, p);
|
|
Packit |
d3f73b |
goto out;
|
|
Packit |
d3f73b |
}
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
if (!strcasecmp(namebuf, kind)) {
|
|
Packit |
d3f73b |
if (dst)
|
|
Packit |
d3f73b |
*dst = id;
|
|
Packit |
d3f73b |
err = 0;
|
|
Packit |
d3f73b |
goto out;
|
|
Packit |
d3f73b |
}
|
|
Packit |
d3f73b |
}
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
err = -ENOENT;
|
|
Packit |
d3f73b |
*dst = 0;
|
|
Packit |
d3f73b |
out:
|
|
Packit |
d3f73b |
fclose(fd);
|
|
Packit |
d3f73b |
return err;
|
|
Packit |
d3f73b |
}
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
static struct ematch_util *get_ematch_kind(char *kind)
|
|
Packit |
d3f73b |
{
|
|
Packit |
d3f73b |
static void *body;
|
|
Packit |
d3f73b |
void *dlh;
|
|
Packit |
d3f73b |
char buf[256];
|
|
Packit |
d3f73b |
struct ematch_util *e;
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
for (e = ematch_list; e; e = e->next) {
|
|
Packit |
d3f73b |
if (strcmp(e->kind, kind) == 0)
|
|
Packit |
d3f73b |
return e;
|
|
Packit |
d3f73b |
}
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
snprintf(buf, sizeof(buf), "em_%s.so", kind);
|
|
Packit |
d3f73b |
dlh = dlopen(buf, RTLD_LAZY);
|
|
Packit |
d3f73b |
if (dlh == NULL) {
|
|
Packit |
d3f73b |
dlh = body;
|
|
Packit |
d3f73b |
if (dlh == NULL) {
|
|
Packit |
d3f73b |
dlh = body = dlopen(NULL, RTLD_LAZY);
|
|
Packit |
d3f73b |
if (dlh == NULL)
|
|
Packit |
d3f73b |
return NULL;
|
|
Packit |
d3f73b |
}
|
|
Packit |
d3f73b |
}
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
snprintf(buf, sizeof(buf), "%s_ematch_util", kind);
|
|
Packit |
d3f73b |
e = dlsym(dlh, buf);
|
|
Packit |
d3f73b |
if (e == NULL)
|
|
Packit |
d3f73b |
return NULL;
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
e->next = ematch_list;
|
|
Packit |
d3f73b |
ematch_list = e;
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
return e;
|
|
Packit |
d3f73b |
}
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
static struct ematch_util *get_ematch_kind_num(__u16 kind)
|
|
Packit |
d3f73b |
{
|
|
Packit |
d3f73b |
char name[513];
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
if (lookup_map(kind, name, sizeof(name), EMATCH_MAP) < 0)
|
|
Packit |
d3f73b |
return NULL;
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
return get_ematch_kind(name);
|
|
Packit |
d3f73b |
}
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
static int em_parse_call(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr,
|
|
Packit |
d3f73b |
struct ematch_util *e, struct ematch *t)
|
|
Packit |
d3f73b |
{
|
|
Packit |
d3f73b |
if (e->parse_eopt_argv) {
|
|
Packit |
d3f73b |
int argc = 0, i = 0, ret;
|
|
Packit |
d3f73b |
struct bstr *args;
|
|
Packit |
d3f73b |
char **argv;
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
for (args = t->args; args; args = bstr_next(args))
|
|
Packit |
d3f73b |
argc++;
|
|
Packit |
d3f73b |
argv = calloc(argc, sizeof(char *));
|
|
Packit |
d3f73b |
if (!argv)
|
|
Packit |
d3f73b |
return -1;
|
|
Packit |
d3f73b |
for (args = t->args; args; args = bstr_next(args))
|
|
Packit |
d3f73b |
argv[i++] = args->data;
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
ret = e->parse_eopt_argv(n, hdr, argc, argv);
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
free(argv);
|
|
Packit |
d3f73b |
return ret;
|
|
Packit |
d3f73b |
}
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
return e->parse_eopt(n, hdr, t->args->next);
|
|
Packit |
d3f73b |
}
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
static int parse_tree(struct nlmsghdr *n, struct ematch *tree)
|
|
Packit |
d3f73b |
{
|
|
Packit |
d3f73b |
int index = 1;
|
|
Packit |
d3f73b |
struct ematch *t;
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
for (t = tree; t; t = t->next) {
|
|
Packit |
d3f73b |
struct rtattr *tail;
|
|
Packit |
d3f73b |
struct tcf_ematch_hdr hdr = { .flags = t->relation };
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
if (t->inverted)
|
|
Packit |
d3f73b |
hdr.flags |= TCF_EM_INVERT;
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
tail = addattr_nest(n, MAX_MSG, index++);
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
if (t->child) {
|
|
Packit |
d3f73b |
__u32 r = t->child_ref;
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
addraw_l(n, MAX_MSG, &hdr, sizeof(hdr));
|
|
Packit |
d3f73b |
addraw_l(n, MAX_MSG, &r, sizeof(r));
|
|
Packit |
d3f73b |
} else {
|
|
Packit |
d3f73b |
int num = 0, err;
|
|
Packit |
d3f73b |
char buf[64];
|
|
Packit |
d3f73b |
struct ematch_util *e;
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
if (t->args == NULL)
|
|
Packit |
d3f73b |
return -1;
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
strncpy(buf, (char *) t->args->data, sizeof(buf)-1);
|
|
Packit |
d3f73b |
e = get_ematch_kind(buf);
|
|
Packit |
d3f73b |
if (e == NULL) {
|
|
Packit |
d3f73b |
fprintf(stderr, "Unknown ematch \"%s\"\n",
|
|
Packit |
d3f73b |
buf);
|
|
Packit |
d3f73b |
return -1;
|
|
Packit |
d3f73b |
}
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
err = lookup_map_id(buf, &num, EMATCH_MAP);
|
|
Packit |
d3f73b |
if (err < 0) {
|
|
Packit |
d3f73b |
if (err == -ENOENT)
|
|
Packit |
d3f73b |
map_warning(e->kind_num, buf);
|
|
Packit |
d3f73b |
return err;
|
|
Packit |
d3f73b |
}
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
hdr.kind = num;
|
|
Packit |
d3f73b |
if (em_parse_call(n, &hdr, e, t) < 0)
|
|
Packit |
d3f73b |
return -1;
|
|
Packit |
d3f73b |
}
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
addattr_nest_end(n, tail);
|
|
Packit |
d3f73b |
}
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
return 0;
|
|
Packit |
d3f73b |
}
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
static int flatten_tree(struct ematch *head, struct ematch *tree)
|
|
Packit |
d3f73b |
{
|
|
Packit |
d3f73b |
int i, count = 0;
|
|
Packit |
d3f73b |
struct ematch *t;
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
for (;;) {
|
|
Packit |
d3f73b |
count++;
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
if (tree->child) {
|
|
Packit |
d3f73b |
for (t = head; t->next; t = t->next);
|
|
Packit |
d3f73b |
t->next = tree->child;
|
|
Packit |
d3f73b |
count += flatten_tree(head, tree->child);
|
|
Packit |
d3f73b |
}
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
if (tree->relation == 0)
|
|
Packit |
d3f73b |
break;
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
tree = tree->next;
|
|
Packit |
d3f73b |
}
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
for (i = 0, t = head; t; t = t->next, i++)
|
|
Packit |
d3f73b |
t->index = i;
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
for (t = head; t; t = t->next)
|
|
Packit |
d3f73b |
if (t->child)
|
|
Packit |
d3f73b |
t->child_ref = t->child->index;
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
return count;
|
|
Packit |
d3f73b |
}
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
__attribute__((format(printf, 5, 6)))
|
|
Packit |
d3f73b |
int em_parse_error(int err, struct bstr *args, struct bstr *carg,
|
|
Packit |
d3f73b |
struct ematch_util *e, char *fmt, ...)
|
|
Packit |
d3f73b |
{
|
|
Packit |
d3f73b |
va_list a;
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
va_start(a, fmt);
|
|
Packit |
d3f73b |
vfprintf(stderr, fmt, a);
|
|
Packit |
d3f73b |
va_end(a);
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
if (ematch_err)
|
|
Packit |
d3f73b |
fprintf(stderr, ": %s\n... ", ematch_err);
|
|
Packit |
d3f73b |
else
|
|
Packit |
d3f73b |
fprintf(stderr, "\n... ");
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
while (ematch_argc < begin_argc) {
|
|
Packit |
d3f73b |
if (ematch_argc == (begin_argc - 1))
|
|
Packit |
d3f73b |
fprintf(stderr, ">>%s<< ", *begin_argv);
|
|
Packit |
d3f73b |
else
|
|
Packit |
d3f73b |
fprintf(stderr, "%s ", *begin_argv);
|
|
Packit |
d3f73b |
begin_argv++;
|
|
Packit |
d3f73b |
begin_argc--;
|
|
Packit |
d3f73b |
}
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
fprintf(stderr, "...\n");
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
if (args) {
|
|
Packit |
d3f73b |
fprintf(stderr, "... %s(", e->kind);
|
|
Packit |
d3f73b |
while (args) {
|
|
Packit |
d3f73b |
fprintf(stderr, "%s", args == carg ? ">>" : "");
|
|
Packit |
d3f73b |
bstr_print(stderr, args, 1);
|
|
Packit |
d3f73b |
fprintf(stderr, "%s%s", args == carg ? "<<" : "",
|
|
Packit |
d3f73b |
args->next ? " " : "");
|
|
Packit |
d3f73b |
args = args->next;
|
|
Packit |
d3f73b |
}
|
|
Packit |
d3f73b |
fprintf(stderr, ")...\n");
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
}
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
if (e == NULL) {
|
|
Packit |
d3f73b |
fprintf(stderr,
|
|
Packit |
d3f73b |
"Usage: EXPR\n" \
|
|
Packit |
d3f73b |
"where: EXPR := TERM [ { and | or } EXPR ]\n" \
|
|
Packit |
d3f73b |
" TERM := [ not ] { MATCH | '(' EXPR ')' }\n" \
|
|
Packit |
d3f73b |
" MATCH := module '(' ARGS ')'\n" \
|
|
Packit |
d3f73b |
" ARGS := ARG1 ARG2 ...\n" \
|
|
Packit |
d3f73b |
"\n" \
|
|
Packit |
d3f73b |
"Example: a(x y) and not (b(x) or c(x y z))\n");
|
|
Packit |
d3f73b |
} else
|
|
Packit |
d3f73b |
e->print_usage(stderr);
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
return -err;
|
|
Packit |
d3f73b |
}
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
static inline void free_ematch_err(void)
|
|
Packit |
d3f73b |
{
|
|
Packit |
d3f73b |
if (ematch_err) {
|
|
Packit |
d3f73b |
free(ematch_err);
|
|
Packit |
d3f73b |
ematch_err = NULL;
|
|
Packit |
d3f73b |
}
|
|
Packit |
d3f73b |
}
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
extern int ematch_parse(void);
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
int parse_ematch(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n)
|
|
Packit |
d3f73b |
{
|
|
Packit |
d3f73b |
begin_argc = ematch_argc = *argc_p;
|
|
Packit |
d3f73b |
begin_argv = ematch_argv = *argv_p;
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
if (ematch_parse()) {
|
|
Packit |
d3f73b |
int err = em_parse_error(EINVAL, NULL, NULL, NULL,
|
|
Packit |
d3f73b |
"Parse error");
|
|
Packit |
d3f73b |
free_ematch_err();
|
|
Packit |
d3f73b |
return err;
|
|
Packit |
d3f73b |
}
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
free_ematch_err();
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
/* undo look ahead by parser */
|
|
Packit |
d3f73b |
ematch_argc++;
|
|
Packit |
d3f73b |
ematch_argv--;
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
if (ematch_root) {
|
|
Packit |
d3f73b |
struct rtattr *tail, *tail_list;
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
struct tcf_ematch_tree_hdr hdr = {
|
|
Packit |
d3f73b |
.nmatches = flatten_tree(ematch_root, ematch_root),
|
|
Packit |
d3f73b |
.progid = TCF_EM_PROG_TC
|
|
Packit |
d3f73b |
};
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
tail = addattr_nest(n, MAX_MSG, tca_id);
|
|
Packit |
d3f73b |
addattr_l(n, MAX_MSG, TCA_EMATCH_TREE_HDR, &hdr, sizeof(hdr));
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
tail_list = addattr_nest(n, MAX_MSG, TCA_EMATCH_TREE_LIST);
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
if (parse_tree(n, ematch_root) < 0)
|
|
Packit |
d3f73b |
return -1;
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
addattr_nest_end(n, tail_list);
|
|
Packit |
d3f73b |
addattr_nest_end(n, tail);
|
|
Packit |
d3f73b |
}
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
*argc_p = ematch_argc;
|
|
Packit |
d3f73b |
*argv_p = ematch_argv;
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
return 0;
|
|
Packit |
d3f73b |
}
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
static int print_ematch_seq(FILE *fd, struct rtattr **tb, int start,
|
|
Packit |
d3f73b |
int prefix)
|
|
Packit |
d3f73b |
{
|
|
Packit |
d3f73b |
int n, i = start;
|
|
Packit |
d3f73b |
struct tcf_ematch_hdr *hdr;
|
|
Packit |
d3f73b |
int dlen;
|
|
Packit |
d3f73b |
void *data;
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
for (;;) {
|
|
Packit |
d3f73b |
if (tb[i] == NULL)
|
|
Packit |
d3f73b |
return -1;
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
dlen = RTA_PAYLOAD(tb[i]) - sizeof(*hdr);
|
|
Packit |
d3f73b |
data = (void *) RTA_DATA(tb[i]) + sizeof(*hdr);
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
if (dlen < 0)
|
|
Packit |
d3f73b |
return -1;
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
hdr = RTA_DATA(tb[i]);
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
if (hdr->flags & TCF_EM_INVERT)
|
|
Packit |
d3f73b |
fprintf(fd, "NOT ");
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
if (hdr->kind == 0) {
|
|
Packit |
d3f73b |
__u32 ref;
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
if (dlen < sizeof(__u32))
|
|
Packit |
d3f73b |
return -1;
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
ref = *(__u32 *) data;
|
|
Packit |
d3f73b |
fprintf(fd, "(\n");
|
|
Packit |
d3f73b |
for (n = 0; n <= prefix; n++)
|
|
Packit |
d3f73b |
fprintf(fd, " ");
|
|
Packit |
d3f73b |
if (print_ematch_seq(fd, tb, ref + 1, prefix + 1) < 0)
|
|
Packit |
d3f73b |
return -1;
|
|
Packit |
d3f73b |
for (n = 0; n < prefix; n++)
|
|
Packit |
d3f73b |
fprintf(fd, " ");
|
|
Packit |
d3f73b |
fprintf(fd, ") ");
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
} else {
|
|
Packit |
d3f73b |
struct ematch_util *e;
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
e = get_ematch_kind_num(hdr->kind);
|
|
Packit |
d3f73b |
if (e == NULL)
|
|
Packit |
d3f73b |
fprintf(fd, "[unknown ematch %d]\n",
|
|
Packit |
d3f73b |
hdr->kind);
|
|
Packit |
d3f73b |
else {
|
|
Packit |
d3f73b |
fprintf(fd, "%s(", e->kind);
|
|
Packit |
d3f73b |
if (e->print_eopt(fd, hdr, data, dlen) < 0)
|
|
Packit |
d3f73b |
return -1;
|
|
Packit |
d3f73b |
fprintf(fd, ")\n");
|
|
Packit |
d3f73b |
}
|
|
Packit |
d3f73b |
if (hdr->flags & TCF_EM_REL_MASK)
|
|
Packit |
d3f73b |
for (n = 0; n < prefix; n++)
|
|
Packit |
d3f73b |
fprintf(fd, " ");
|
|
Packit |
d3f73b |
}
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
switch (hdr->flags & TCF_EM_REL_MASK) {
|
|
Packit |
d3f73b |
case TCF_EM_REL_AND:
|
|
Packit |
d3f73b |
fprintf(fd, "AND ");
|
|
Packit |
d3f73b |
break;
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
case TCF_EM_REL_OR:
|
|
Packit |
d3f73b |
fprintf(fd, "OR ");
|
|
Packit |
d3f73b |
break;
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
default:
|
|
Packit |
d3f73b |
return 0;
|
|
Packit |
d3f73b |
}
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
i++;
|
|
Packit |
d3f73b |
}
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
return 0;
|
|
Packit |
d3f73b |
}
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
static int print_ematch_list(FILE *fd, struct tcf_ematch_tree_hdr *hdr,
|
|
Packit |
d3f73b |
struct rtattr *rta)
|
|
Packit |
d3f73b |
{
|
|
Packit |
d3f73b |
int err = -1;
|
|
Packit |
d3f73b |
struct rtattr **tb;
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
tb = malloc((hdr->nmatches + 1) * sizeof(struct rtattr *));
|
|
Packit |
d3f73b |
if (tb == NULL)
|
|
Packit |
d3f73b |
return -1;
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
if (hdr->nmatches > 0) {
|
|
Packit |
d3f73b |
if (parse_rtattr_nested(tb, hdr->nmatches, rta) < 0)
|
|
Packit |
d3f73b |
goto errout;
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
fprintf(fd, "\n ");
|
|
Packit |
d3f73b |
if (print_ematch_seq(fd, tb, 1, 1) < 0)
|
|
Packit |
d3f73b |
goto errout;
|
|
Packit |
d3f73b |
}
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
err = 0;
|
|
Packit |
d3f73b |
errout:
|
|
Packit |
d3f73b |
free(tb);
|
|
Packit |
d3f73b |
return err;
|
|
Packit |
d3f73b |
}
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
int print_ematch(FILE *fd, const struct rtattr *rta)
|
|
Packit |
d3f73b |
{
|
|
Packit |
d3f73b |
struct rtattr *tb[TCA_EMATCH_TREE_MAX+1];
|
|
Packit |
d3f73b |
struct tcf_ematch_tree_hdr *hdr;
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
if (parse_rtattr_nested(tb, TCA_EMATCH_TREE_MAX, rta) < 0)
|
|
Packit |
d3f73b |
return -1;
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
if (tb[TCA_EMATCH_TREE_HDR] == NULL) {
|
|
Packit |
d3f73b |
fprintf(stderr, "Missing ematch tree header\n");
|
|
Packit |
d3f73b |
return -1;
|
|
Packit |
d3f73b |
}
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
if (tb[TCA_EMATCH_TREE_LIST] == NULL) {
|
|
Packit |
d3f73b |
fprintf(stderr, "Missing ematch tree list\n");
|
|
Packit |
d3f73b |
return -1;
|
|
Packit |
d3f73b |
}
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
if (RTA_PAYLOAD(tb[TCA_EMATCH_TREE_HDR]) < sizeof(*hdr)) {
|
|
Packit |
d3f73b |
fprintf(stderr, "Ematch tree header size mismatch\n");
|
|
Packit |
d3f73b |
return -1;
|
|
Packit |
d3f73b |
}
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
hdr = RTA_DATA(tb[TCA_EMATCH_TREE_HDR]);
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
return print_ematch_list(fd, hdr, tb[TCA_EMATCH_TREE_LIST]);
|
|
Packit |
d3f73b |
}
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
struct bstr *bstr_alloc(const char *text)
|
|
Packit |
d3f73b |
{
|
|
Packit |
d3f73b |
struct bstr *b = calloc(1, sizeof(*b));
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
if (b == NULL)
|
|
Packit |
d3f73b |
return NULL;
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
b->data = strdup(text);
|
|
Packit |
d3f73b |
if (b->data == NULL) {
|
|
Packit |
d3f73b |
free(b);
|
|
Packit |
d3f73b |
return NULL;
|
|
Packit |
d3f73b |
}
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
b->len = strlen(text);
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
return b;
|
|
Packit |
d3f73b |
}
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
unsigned long bstrtoul(const struct bstr *b)
|
|
Packit |
d3f73b |
{
|
|
Packit |
d3f73b |
char *inv = NULL;
|
|
Packit |
d3f73b |
unsigned long l;
|
|
Packit |
d3f73b |
char buf[b->len+1];
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
memcpy(buf, b->data, b->len);
|
|
Packit |
d3f73b |
buf[b->len] = '\0';
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
l = strtoul(buf, &inv, 0);
|
|
Packit |
d3f73b |
if (l == ULONG_MAX || inv == buf)
|
|
Packit |
d3f73b |
return ULONG_MAX;
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
return l;
|
|
Packit |
d3f73b |
}
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
static void bstr_print(FILE *fd, const struct bstr *b, int ascii)
|
|
Packit |
d3f73b |
{
|
|
Packit |
d3f73b |
int i;
|
|
Packit |
d3f73b |
char *s = b->data;
|
|
Packit |
d3f73b |
|
|
Packit |
d3f73b |
if (ascii)
|
|
Packit |
d3f73b |
for (i = 0; i < b->len; i++)
|
|
Packit |
d3f73b |
fprintf(fd, "%c", isprint(s[i]) ? s[i] : '.');
|
|
Packit |
d3f73b |
else {
|
|
Packit |
d3f73b |
for (i = 0; i < b->len; i++)
|
|
Packit |
d3f73b |
fprintf(fd, "%02x", s[i]);
|
|
Packit |
d3f73b |
fprintf(fd, "\"");
|
|
Packit |
d3f73b |
for (i = 0; i < b->len; i++)
|
|
Packit |
d3f73b |
fprintf(fd, "%c", isprint(s[i]) ? s[i] : '.');
|
|
Packit |
d3f73b |
fprintf(fd, "\"");
|
|
Packit |
d3f73b |
}
|
|
Packit |
d3f73b |
}
|