]>
Commit | Line | Data |
---|---|---|
dd296215 | 1 | /* |
69df9bf9 | 2 | * em_ipt.c IPtables extensions matching Ematch |
dd296215 EB |
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, | |
17504be8 | 44 | #if (XTABLES_VERSION_CODE >= 11) |
dd296215 | 45 | .compat_rev = xtables_compatible_revision, |
17504be8 | 46 | #endif |
dd296215 EB |
47 | }; |
48 | ||
49 | static struct xt_entry_match *fake_xt_entry_match(int data_size, void *data) | |
50 | { | |
51 | struct xt_entry_match *m; | |
52 | ||
53 | m = xtables_calloc(1, XT_ALIGN(sizeof(*m)) + data_size); | |
54 | if (!m) | |
55 | return NULL; | |
56 | ||
57 | if (data) | |
58 | memcpy(m->data, data, data_size); | |
59 | ||
60 | m->u.user.match_size = data_size; | |
61 | return m; | |
62 | } | |
63 | ||
64 | static void scrub_match(struct xtables_match *match) | |
65 | { | |
66 | match->mflags = 0; | |
67 | free(match->m); | |
68 | match->m = NULL; | |
69 | } | |
70 | ||
71 | /* IPv4 and IPv6 share the same hooking enumeration */ | |
72 | #define HOOK_PRE_ROUTING 0 | |
73 | #define HOOK_POST_ROUTING 4 | |
74 | ||
75 | static __u32 em_ipt_hook(struct nlmsghdr *n) | |
76 | { | |
77 | struct tcmsg *t = NLMSG_DATA(n); | |
78 | ||
79 | if (t->tcm_parent != TC_H_ROOT && | |
80 | t->tcm_parent == TC_H_MAJ(TC_H_INGRESS)) | |
81 | return HOOK_PRE_ROUTING; | |
82 | ||
83 | return HOOK_POST_ROUTING; | |
84 | } | |
85 | ||
86 | static int em_ipt_parse_eopt_argv(struct nlmsghdr *n, | |
87 | struct tcf_ematch_hdr *hdr, | |
88 | int argc, char **argv) | |
89 | { | |
90 | struct xtables_globals tmp_tcipt_globals = em_tc_ipt_globals; | |
91 | struct xtables_match *match = NULL; | |
92 | __u8 nfproto = NFPROTO_IPV4; | |
93 | ||
94 | while (1) { | |
95 | struct option *opts; | |
96 | int c; | |
97 | ||
98 | c = getopt_long(argc, argv, "6m:", tmp_tcipt_globals.opts, | |
99 | NULL); | |
100 | if (c == -1) | |
101 | break; | |
102 | ||
103 | switch (c) { | |
104 | case 'm': | |
105 | xtables_init_all(&tmp_tcipt_globals, nfproto); | |
106 | ||
107 | match = xtables_find_match(optarg, XTF_TRY_LOAD, NULL); | |
108 | if (!match || !match->x6_parse) { | |
109 | fprintf(stderr, " failed to find match %s\n\n", | |
110 | optarg); | |
111 | return -1; | |
112 | } | |
113 | ||
114 | match->m = fake_xt_entry_match(match->size, NULL); | |
115 | if (!match->m) { | |
116 | printf(" %s error\n", match->name); | |
117 | return -1; | |
118 | } | |
119 | ||
120 | if (match->init) | |
121 | match->init(match->m); | |
122 | ||
123 | opts = xtables_options_xfrm(tmp_tcipt_globals.orig_opts, | |
124 | tmp_tcipt_globals.opts, | |
125 | match->x6_options, | |
126 | &match->option_offset); | |
127 | if (!opts) { | |
128 | scrub_match(match); | |
129 | return -1; | |
130 | } | |
131 | ||
132 | tmp_tcipt_globals.opts = opts; | |
133 | break; | |
134 | ||
135 | case '6': | |
136 | nfproto = NFPROTO_IPV6; | |
137 | break; | |
138 | ||
139 | default: | |
140 | if (!match) { | |
141 | fprintf(stderr, "failed to find match %s\n\n", | |
142 | optarg); | |
143 | return -1; | |
144 | ||
145 | } | |
146 | xtables_option_mpcall(c, argv, 0, match, NULL); | |
147 | break; | |
148 | } | |
149 | } | |
150 | ||
151 | if (!match) { | |
152 | fprintf(stderr, " failed to parse parameters (%s)\n", *argv); | |
153 | return -1; | |
154 | } | |
155 | ||
156 | /* check that we passed the correct parameters to the match */ | |
157 | xtables_option_mfcall(match); | |
158 | ||
159 | addraw_l(n, MAX_MSG, hdr, sizeof(*hdr)); | |
160 | addattr32(n, MAX_MSG, TCA_EM_IPT_HOOK, em_ipt_hook(n)); | |
161 | addattrstrz(n, MAX_MSG, TCA_EM_IPT_MATCH_NAME, match->name); | |
162 | addattr8(n, MAX_MSG, TCA_EM_IPT_MATCH_REVISION, match->revision); | |
163 | addattr8(n, MAX_MSG, TCA_EM_IPT_NFPROTO, nfproto); | |
164 | addattr_l(n, MAX_MSG, TCA_EM_IPT_MATCH_DATA, match->m->data, | |
165 | match->size); | |
166 | ||
167 | xtables_free_opts(1); | |
168 | ||
169 | scrub_match(match); | |
170 | return 0; | |
171 | } | |
172 | ||
173 | static int em_ipt_print_epot(FILE *fd, struct tcf_ematch_hdr *hdr, void *data, | |
174 | int data_len) | |
175 | { | |
176 | struct rtattr *tb[TCA_EM_IPT_MAX + 1]; | |
177 | struct xtables_match *match; | |
178 | const char *mname; | |
179 | __u8 nfproto; | |
180 | ||
181 | if (parse_rtattr(tb, TCA_EM_IPT_MAX, data, data_len) < 0) | |
182 | return -1; | |
183 | ||
184 | nfproto = rta_getattr_u8(tb[TCA_EM_IPT_NFPROTO]); | |
185 | ||
186 | xtables_init_all(&em_tc_ipt_globals, nfproto); | |
187 | ||
188 | mname = rta_getattr_str(tb[TCA_EM_IPT_MATCH_NAME]); | |
189 | match = xtables_find_match(mname, XTF_TRY_LOAD, NULL); | |
190 | if (!match) | |
191 | return -1; | |
192 | ||
193 | match->m = fake_xt_entry_match(RTA_PAYLOAD(tb[TCA_EM_IPT_MATCH_DATA]), | |
194 | RTA_DATA(tb[TCA_EM_IPT_MATCH_DATA])); | |
195 | if (!match->m) | |
196 | return -1; | |
197 | ||
198 | match->print(NULL, match->m, 0); | |
199 | ||
200 | scrub_match(match); | |
201 | return 0; | |
202 | } | |
203 | ||
204 | struct ematch_util ipt_ematch_util = { | |
205 | .kind = "ipt", | |
206 | .kind_num = TCF_EM_IPT, | |
207 | .parse_eopt_argv = em_ipt_parse_eopt_argv, | |
208 | .print_eopt = em_ipt_print_epot, | |
209 | .print_usage = em_ipt_print_usage | |
210 | }; |