* [PATCH iproute2-next 1/2] tc: ematch: add parse_eopt_argv() method for providing ematches with argv parameters
2018-02-23 11:12 [PATCH iproute2-next 0/2] tc: add ipt ematch Eyal Birger
@ 2018-02-23 11:12 ` Eyal Birger
2018-02-23 11:12 ` [PATCH iproute2-next 2/2] tc: add em_ipt ematch for calling xtables matches from tc matching context Eyal Birger
2018-02-27 17:45 ` [PATCH iproute2-next 0/2] tc: add ipt ematch David Ahern
2 siblings, 0 replies; 4+ messages in thread
From: Eyal Birger @ 2018-02-23 11:12 UTC (permalink / raw)
To: netdev; +Cc: dsahern, shmulik, Eyal Birger
ematche uses YACC to parse ematch arguments and places them in struct bstr
linked lists.
It is useful to be able to receive parameters as argc,argv in order to use
getopt (and alike) argument parsers.
Signed-off-by: Eyal Birger <eyal.birger@gmail.com>
---
tc/m_ematch.c | 27 ++++++++++++++++++++++++++-
tc/m_ematch.h | 2 ++
2 files changed, 28 insertions(+), 1 deletion(-)
diff --git a/tc/m_ematch.c b/tc/m_ematch.c
index 7dbc2e7..61f8fb3 100644
--- a/tc/m_ematch.c
+++ b/tc/m_ematch.c
@@ -169,6 +169,31 @@ static struct ematch_util *get_ematch_kind_num(__u16 kind)
return get_ematch_kind(name);
}
+static int em_parse_call(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr,
+ struct ematch_util *e, struct ematch *t)
+{
+ if (e->parse_eopt_argv) {
+ int argc = 0, i = 0, ret;
+ struct bstr *args;
+ char **argv;
+
+ for (args = t->args; args; args = bstr_next(args))
+ argc++;
+ argv = calloc(argc, sizeof(char *));
+ if (!argv)
+ return -1;
+ for (args = t->args; args; args = bstr_next(args))
+ argv[i++] = args->data;
+
+ ret = e->parse_eopt_argv(n, hdr, argc, argv);
+
+ free(argv);
+ return ret;
+ }
+
+ return e->parse_eopt(n, hdr, t->args->next);
+}
+
static int parse_tree(struct nlmsghdr *n, struct ematch *tree)
{
int index = 1;
@@ -212,7 +237,7 @@ static int parse_tree(struct nlmsghdr *n, struct ematch *tree)
}
hdr.kind = num;
- if (e->parse_eopt(n, &hdr, t->args->next) < 0)
+ if (em_parse_call(n, &hdr, e, t) < 0)
return -1;
}
diff --git a/tc/m_ematch.h b/tc/m_ematch.h
index fa6e214..f634f19 100644
--- a/tc/m_ematch.h
+++ b/tc/m_ematch.h
@@ -88,6 +88,8 @@ struct ematch_util
int kind_num;
int (*parse_eopt)(struct nlmsghdr *,struct tcf_ematch_hdr *,
struct bstr *);
+ int (*parse_eopt_argv)(struct nlmsghdr *, struct tcf_ematch_hdr *,
+ int, char **);
int (*print_eopt)(FILE *, struct tcf_ematch_hdr *, void *, int);
void (*print_usage)(FILE *);
struct ematch_util *next;
--
2.7.4
^ permalink raw reply related [flat|nested] 4+ messages in thread* [PATCH iproute2-next 2/2] tc: add em_ipt ematch for calling xtables matches from tc matching context
2018-02-23 11:12 [PATCH iproute2-next 0/2] tc: add ipt ematch Eyal Birger
2018-02-23 11:12 ` [PATCH iproute2-next 1/2] tc: ematch: add parse_eopt_argv() method for providing ematches with argv parameters Eyal Birger
@ 2018-02-23 11:12 ` Eyal Birger
2018-02-27 17:45 ` [PATCH iproute2-next 0/2] tc: add ipt ematch David Ahern
2 siblings, 0 replies; 4+ messages in thread
From: Eyal Birger @ 2018-02-23 11:12 UTC (permalink / raw)
To: netdev; +Cc: dsahern, shmulik, Eyal Birger
The commit calls a new tc ematch for using netfilter xtable matches.
This allows early classification as well as mirroning/redirecting traffic
based on logic implemented in netfilter extensions.
Current supported use case is classification based on the incoming IPSec
state used during decpsulation using the 'policy' iptables extension
(xt_policy).
The matcher uses libxtables for parsing the input parameters.
Example use for matching an IPSec state with reqid 1:
tc qdisc add dev eth0 ingress
tc filter add dev eth0 protocol ip parent ffff: \
basic match 'ipt(-m policy --dir in --pol ipsec --reqid 1)' \
action drop
This is the user-space counter part of kernel commit ccc007e4a746
("net: sched: add em_ipt ematch for calling xtables matches")
Signed-off-by: Eyal Birger <eyal.birger@gmail.com>
---
etc/iproute2/ematch_map | 1 +
man/man8/tc-ematch.8 | 15 ++++
tc/Makefile | 7 ++
tc/em_ipt.c | 208 ++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 231 insertions(+)
create mode 100644 tc/em_ipt.c
diff --git a/etc/iproute2/ematch_map b/etc/iproute2/ematch_map
index 1823983..4d6bb2f 100644
--- a/etc/iproute2/ematch_map
+++ b/etc/iproute2/ematch_map
@@ -5,3 +5,4 @@
4 meta
7 canid
8 ipset
+9 ipt
diff --git a/man/man8/tc-ematch.8 b/man/man8/tc-ematch.8
index b9bf70c..042f840 100644
--- a/man/man8/tc-ematch.8
+++ b/man/man8/tc-ematch.8
@@ -98,6 +98,17 @@ When using the ipset ematch with the "ip_set_hash:net,iface" set type,
the interface can be queried using "src,dst (source ip address, outgoing interface) or
"src,src" (source ip address, incoming interface) syntax.
+.SS ipt
+test packet against xtables matches
+
+.IR ipt "( " [-6] " "-m " " MATCH_NAME " " FLAGS " )
+
+.IR MATCH_NAME " := " string
+
+.IR FLAGS " := { " FLAG " [, " FLAGS "] }
+
+The flag options are the same as those used by the xtable match used.
+
.SH CAVEATS
The ematch syntax uses '(' and ')' to group expressions. All braces need to be
@@ -127,6 +138,10 @@ Check if packet source ip and the interface the packet arrived on is member of "
# 'ipset(interactive src,src)'
+Check if packet matches an IPSec state with reqid 1:
+
+# 'ipt(-m policy --dir in --pol ipsec --reqid 1)'
+
.SH "AUTHOR"
The extended match infrastructure was added by Thomas Graf.
diff --git a/tc/Makefile b/tc/Makefile
index 3716dd6..dfd0026 100644
--- a/tc/Makefile
+++ b/tc/Makefile
@@ -80,6 +80,7 @@ endif
ifneq ($(TC_CONFIG_NO_XT),y)
ifeq ($(TC_CONFIG_XT),y)
TCSO += m_xt.so
+ TCMODULES += em_ipt.o
ifeq ($(TC_CONFIG_IPSET),y)
TCMODULES += em_ipset.o
endif
@@ -163,6 +164,12 @@ m_xt_old.so: m_xt_old.c
em_ipset.o: CFLAGS += $$($(PKG_CONFIG) xtables --cflags)
+em_ipt.o: CFLAGS += $$($(PKG_CONFIG) xtables --cflags)
+
+ifeq ($(TC_CONFIG_XT),y)
+ LDFLAGS += $$($(PKG_CONFIG) xtables --libs)
+endif
+
%.yacc.c: %.y
$(QUIET_YACC)$(YACC) $(YACCFLAGS) -o $@ $<
diff --git a/tc/em_ipt.c b/tc/em_ipt.c
new file mode 100644
index 0000000..9d2b2f9
--- /dev/null
+++ b/tc/em_ipt.c
@@ -0,0 +1,208 @@
+/*
+ * em_ipt.c IPtables extenstions matching Ematch
+ *
+ * (C) 2018 Eyal Birger <eyal.birger@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <getopt.h>
+
+#include <linux/tc_ematch/tc_em_ipt.h>
+#include <linux/pkt_cls.h>
+#include <xtables.h>
+#include "m_ematch.h"
+
+static void em_ipt_print_usage(FILE *fd)
+{
+ fprintf(fd,
+ "Usage: ipt([-6] -m MATCH_NAME [MATCH_OPTS])\n"
+ "Example: 'ipt(-m policy --reqid 1 --pol ipsec --dir in)'\n");
+}
+
+static struct option original_opts[] = {
+ {
+ .name = "match",
+ .has_arg = 1,
+ .val = 'm'
+ },
+ {
+ .name = "ipv6",
+ .val = '6'
+ },
+ {}
+};
+
+static struct xtables_globals em_tc_ipt_globals = {
+ .option_offset = 0,
+ .program_name = "tc-em-ipt",
+ .program_version = "0.1",
+ .orig_opts = original_opts,
+ .opts = original_opts,
+ .compat_rev = xtables_compatible_revision,
+};
+
+static struct xt_entry_match *fake_xt_entry_match(int data_size, void *data)
+{
+ struct xt_entry_match *m;
+
+ m = xtables_calloc(1, XT_ALIGN(sizeof(*m)) + data_size);
+ if (!m)
+ return NULL;
+
+ if (data)
+ memcpy(m->data, data, data_size);
+
+ m->u.user.match_size = data_size;
+ return m;
+}
+
+static void scrub_match(struct xtables_match *match)
+{
+ match->mflags = 0;
+ free(match->m);
+ match->m = NULL;
+}
+
+/* IPv4 and IPv6 share the same hooking enumeration */
+#define HOOK_PRE_ROUTING 0
+#define HOOK_POST_ROUTING 4
+
+static __u32 em_ipt_hook(struct nlmsghdr *n)
+{
+ struct tcmsg *t = NLMSG_DATA(n);
+
+ if (t->tcm_parent != TC_H_ROOT &&
+ t->tcm_parent == TC_H_MAJ(TC_H_INGRESS))
+ return HOOK_PRE_ROUTING;
+
+ return HOOK_POST_ROUTING;
+}
+
+static int em_ipt_parse_eopt_argv(struct nlmsghdr *n,
+ struct tcf_ematch_hdr *hdr,
+ int argc, char **argv)
+{
+ struct xtables_globals tmp_tcipt_globals = em_tc_ipt_globals;
+ struct xtables_match *match = NULL;
+ __u8 nfproto = NFPROTO_IPV4;
+
+ while (1) {
+ struct option *opts;
+ int c;
+
+ c = getopt_long(argc, argv, "6m:", tmp_tcipt_globals.opts,
+ NULL);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'm':
+ xtables_init_all(&tmp_tcipt_globals, nfproto);
+
+ match = xtables_find_match(optarg, XTF_TRY_LOAD, NULL);
+ if (!match || !match->x6_parse) {
+ fprintf(stderr, " failed to find match %s\n\n",
+ optarg);
+ return -1;
+ }
+
+ match->m = fake_xt_entry_match(match->size, NULL);
+ if (!match->m) {
+ printf(" %s error\n", match->name);
+ return -1;
+ }
+
+ if (match->init)
+ match->init(match->m);
+
+ opts = xtables_options_xfrm(tmp_tcipt_globals.orig_opts,
+ tmp_tcipt_globals.opts,
+ match->x6_options,
+ &match->option_offset);
+ if (!opts) {
+ scrub_match(match);
+ return -1;
+ }
+
+ tmp_tcipt_globals.opts = opts;
+ break;
+
+ case '6':
+ nfproto = NFPROTO_IPV6;
+ break;
+
+ default:
+ if (!match) {
+ fprintf(stderr, "failed to find match %s\n\n",
+ optarg);
+ return -1;
+
+ }
+ xtables_option_mpcall(c, argv, 0, match, NULL);
+ break;
+ }
+ }
+
+ if (!match) {
+ fprintf(stderr, " failed to parse parameters (%s)\n", *argv);
+ return -1;
+ }
+
+ /* check that we passed the correct parameters to the match */
+ xtables_option_mfcall(match);
+
+ addraw_l(n, MAX_MSG, hdr, sizeof(*hdr));
+ addattr32(n, MAX_MSG, TCA_EM_IPT_HOOK, em_ipt_hook(n));
+ addattrstrz(n, MAX_MSG, TCA_EM_IPT_MATCH_NAME, match->name);
+ addattr8(n, MAX_MSG, TCA_EM_IPT_MATCH_REVISION, match->revision);
+ addattr8(n, MAX_MSG, TCA_EM_IPT_NFPROTO, nfproto);
+ addattr_l(n, MAX_MSG, TCA_EM_IPT_MATCH_DATA, match->m->data,
+ match->size);
+
+ xtables_free_opts(1);
+
+ scrub_match(match);
+ return 0;
+}
+
+static int em_ipt_print_epot(FILE *fd, struct tcf_ematch_hdr *hdr, void *data,
+ int data_len)
+{
+ struct rtattr *tb[TCA_EM_IPT_MAX + 1];
+ struct xtables_match *match;
+ const char *mname;
+ __u8 nfproto;
+
+ if (parse_rtattr(tb, TCA_EM_IPT_MAX, data, data_len) < 0)
+ return -1;
+
+ nfproto = rta_getattr_u8(tb[TCA_EM_IPT_NFPROTO]);
+
+ xtables_init_all(&em_tc_ipt_globals, nfproto);
+
+ mname = rta_getattr_str(tb[TCA_EM_IPT_MATCH_NAME]);
+ match = xtables_find_match(mname, XTF_TRY_LOAD, NULL);
+ if (!match)
+ return -1;
+
+ match->m = fake_xt_entry_match(RTA_PAYLOAD(tb[TCA_EM_IPT_MATCH_DATA]),
+ RTA_DATA(tb[TCA_EM_IPT_MATCH_DATA]));
+ if (!match->m)
+ return -1;
+
+ match->print(NULL, match->m, 0);
+
+ scrub_match(match);
+ return 0;
+}
+
+struct ematch_util ipt_ematch_util = {
+ .kind = "ipt",
+ .kind_num = TCF_EM_IPT,
+ .parse_eopt_argv = em_ipt_parse_eopt_argv,
+ .print_eopt = em_ipt_print_epot,
+ .print_usage = em_ipt_print_usage
+};
--
2.7.4
^ permalink raw reply related [flat|nested] 4+ messages in thread