mirror of
https://git.proxmox.com/git/mirror_iproute2
synced 2025-08-15 04:35:14 +00:00
tc: add em_ipt ematch for calling xtables matches from tc matching context
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> Signed-off-by: David Ahern <dsahern@gmail.com>
This commit is contained in:
parent
526862038e
commit
dd29621578
@ -5,3 +5,4 @@
|
||||
4 meta
|
||||
7 canid
|
||||
8 ipset
|
||||
9 ipt
|
||||
|
@ -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.
|
||||
|
@ -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
208
tc/em_ipt.c
Normal 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
|
||||
};
|
Loading…
Reference in New Issue
Block a user