Merge branch 'tc-ipt-ematch' into iproute2-next

Eyal Birger  says:

====================

This patchset extends tc to support the ipt ematch.

The first patch adds the ability for ematch cmdline parsers
to receive argc,argv parameters.
The second patch adds the em_ipt module.

====================

Signed-off-by: David Ahern <dsahern@gmail.com>
This commit is contained in:
David Ahern 2018-02-27 09:44:33 -08:00
commit 7c6e942e84
7 changed files with 279 additions and 1 deletions

View File

@ -5,3 +5,4 @@
4 meta
7 canid
8 ipset
9 ipt

View File

@ -0,0 +1,20 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef __LINUX_TC_EM_IPT_H
#define __LINUX_TC_EM_IPT_H
#include <linux/types.h>
#include <linux/pkt_cls.h>
enum {
TCA_EM_IPT_UNSPEC,
TCA_EM_IPT_HOOK,
TCA_EM_IPT_MATCH_NAME,
TCA_EM_IPT_MATCH_REVISION,
TCA_EM_IPT_NFPROTO,
TCA_EM_IPT_MATCH_DATA,
__TCA_EM_IPT_MAX
};
#define TCA_EM_IPT_MAX (__TCA_EM_IPT_MAX - 1)
#endif

View File

@ -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.

View File

@ -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 $@ $<

208
tc/em_ipt.c Normal file
View File

@ -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
};

View File

@ -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;
}

View File

@ -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;