]> git.proxmox.com Git - mirror_iproute2.git/blob - tc/em_ipt.c
tc: add em_ipt ematch for calling xtables matches from tc matching context
[mirror_iproute2.git] / tc / em_ipt.c
1 /*
2 * em_ipt.c IPtables extenstions matching Ematch
3 *
4 * (C) 2018 Eyal Birger <eyal.birger@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11 #include <getopt.h>
12
13 #include <linux/tc_ematch/tc_em_ipt.h>
14 #include <linux/pkt_cls.h>
15 #include <xtables.h>
16 #include "m_ematch.h"
17
18 static void em_ipt_print_usage(FILE *fd)
19 {
20 fprintf(fd,
21 "Usage: ipt([-6] -m MATCH_NAME [MATCH_OPTS])\n"
22 "Example: 'ipt(-m policy --reqid 1 --pol ipsec --dir in)'\n");
23 }
24
25 static struct option original_opts[] = {
26 {
27 .name = "match",
28 .has_arg = 1,
29 .val = 'm'
30 },
31 {
32 .name = "ipv6",
33 .val = '6'
34 },
35 {}
36 };
37
38 static struct xtables_globals em_tc_ipt_globals = {
39 .option_offset = 0,
40 .program_name = "tc-em-ipt",
41 .program_version = "0.1",
42 .orig_opts = original_opts,
43 .opts = original_opts,
44 .compat_rev = xtables_compatible_revision,
45 };
46
47 static struct xt_entry_match *fake_xt_entry_match(int data_size, void *data)
48 {
49 struct xt_entry_match *m;
50
51 m = xtables_calloc(1, XT_ALIGN(sizeof(*m)) + data_size);
52 if (!m)
53 return NULL;
54
55 if (data)
56 memcpy(m->data, data, data_size);
57
58 m->u.user.match_size = data_size;
59 return m;
60 }
61
62 static void scrub_match(struct xtables_match *match)
63 {
64 match->mflags = 0;
65 free(match->m);
66 match->m = NULL;
67 }
68
69 /* IPv4 and IPv6 share the same hooking enumeration */
70 #define HOOK_PRE_ROUTING 0
71 #define HOOK_POST_ROUTING 4
72
73 static __u32 em_ipt_hook(struct nlmsghdr *n)
74 {
75 struct tcmsg *t = NLMSG_DATA(n);
76
77 if (t->tcm_parent != TC_H_ROOT &&
78 t->tcm_parent == TC_H_MAJ(TC_H_INGRESS))
79 return HOOK_PRE_ROUTING;
80
81 return HOOK_POST_ROUTING;
82 }
83
84 static int em_ipt_parse_eopt_argv(struct nlmsghdr *n,
85 struct tcf_ematch_hdr *hdr,
86 int argc, char **argv)
87 {
88 struct xtables_globals tmp_tcipt_globals = em_tc_ipt_globals;
89 struct xtables_match *match = NULL;
90 __u8 nfproto = NFPROTO_IPV4;
91
92 while (1) {
93 struct option *opts;
94 int c;
95
96 c = getopt_long(argc, argv, "6m:", tmp_tcipt_globals.opts,
97 NULL);
98 if (c == -1)
99 break;
100
101 switch (c) {
102 case 'm':
103 xtables_init_all(&tmp_tcipt_globals, nfproto);
104
105 match = xtables_find_match(optarg, XTF_TRY_LOAD, NULL);
106 if (!match || !match->x6_parse) {
107 fprintf(stderr, " failed to find match %s\n\n",
108 optarg);
109 return -1;
110 }
111
112 match->m = fake_xt_entry_match(match->size, NULL);
113 if (!match->m) {
114 printf(" %s error\n", match->name);
115 return -1;
116 }
117
118 if (match->init)
119 match->init(match->m);
120
121 opts = xtables_options_xfrm(tmp_tcipt_globals.orig_opts,
122 tmp_tcipt_globals.opts,
123 match->x6_options,
124 &match->option_offset);
125 if (!opts) {
126 scrub_match(match);
127 return -1;
128 }
129
130 tmp_tcipt_globals.opts = opts;
131 break;
132
133 case '6':
134 nfproto = NFPROTO_IPV6;
135 break;
136
137 default:
138 if (!match) {
139 fprintf(stderr, "failed to find match %s\n\n",
140 optarg);
141 return -1;
142
143 }
144 xtables_option_mpcall(c, argv, 0, match, NULL);
145 break;
146 }
147 }
148
149 if (!match) {
150 fprintf(stderr, " failed to parse parameters (%s)\n", *argv);
151 return -1;
152 }
153
154 /* check that we passed the correct parameters to the match */
155 xtables_option_mfcall(match);
156
157 addraw_l(n, MAX_MSG, hdr, sizeof(*hdr));
158 addattr32(n, MAX_MSG, TCA_EM_IPT_HOOK, em_ipt_hook(n));
159 addattrstrz(n, MAX_MSG, TCA_EM_IPT_MATCH_NAME, match->name);
160 addattr8(n, MAX_MSG, TCA_EM_IPT_MATCH_REVISION, match->revision);
161 addattr8(n, MAX_MSG, TCA_EM_IPT_NFPROTO, nfproto);
162 addattr_l(n, MAX_MSG, TCA_EM_IPT_MATCH_DATA, match->m->data,
163 match->size);
164
165 xtables_free_opts(1);
166
167 scrub_match(match);
168 return 0;
169 }
170
171 static int em_ipt_print_epot(FILE *fd, struct tcf_ematch_hdr *hdr, void *data,
172 int data_len)
173 {
174 struct rtattr *tb[TCA_EM_IPT_MAX + 1];
175 struct xtables_match *match;
176 const char *mname;
177 __u8 nfproto;
178
179 if (parse_rtattr(tb, TCA_EM_IPT_MAX, data, data_len) < 0)
180 return -1;
181
182 nfproto = rta_getattr_u8(tb[TCA_EM_IPT_NFPROTO]);
183
184 xtables_init_all(&em_tc_ipt_globals, nfproto);
185
186 mname = rta_getattr_str(tb[TCA_EM_IPT_MATCH_NAME]);
187 match = xtables_find_match(mname, XTF_TRY_LOAD, NULL);
188 if (!match)
189 return -1;
190
191 match->m = fake_xt_entry_match(RTA_PAYLOAD(tb[TCA_EM_IPT_MATCH_DATA]),
192 RTA_DATA(tb[TCA_EM_IPT_MATCH_DATA]));
193 if (!match->m)
194 return -1;
195
196 match->print(NULL, match->m, 0);
197
198 scrub_match(match);
199 return 0;
200 }
201
202 struct ematch_util ipt_ematch_util = {
203 .kind = "ipt",
204 .kind_num = TCF_EM_IPT,
205 .parse_eopt_argv = em_ipt_parse_eopt_argv,
206 .print_eopt = em_ipt_print_epot,
207 .print_usage = em_ipt_print_usage
208 };