]>
Commit | Line | Data |
---|---|---|
a36ceb85 AH |
1 | /* |
2 | * m_xt.c xtables based targets | |
3d0b7439 | 3 | * utilities mostly ripped from iptables <duh, its the linux way> |
a36ceb85 AH |
4 | * |
5 | * This program is free software; you can distribute it and/or | |
6 | * modify it under the terms of the GNU General Public License | |
7 | * as published by the Free Software Foundation; either version | |
8 | * 2 of the License, or (at your option) any later version. | |
9 | * | |
10 | * Authors: J Hadi Salim (hadi@cyberus.ca) | |
11 | */ | |
12 | ||
a36ceb85 AH |
13 | #include <sys/socket.h> |
14 | #include <netinet/in.h> | |
15 | #include <arpa/inet.h> | |
16 | #include <net/if.h> | |
17 | #include <limits.h> | |
18 | #include <linux/netfilter.h> | |
19 | #include <linux/netfilter_ipv4/ip_tables.h> | |
20 | #include <xtables.h> | |
21 | #include "utils.h" | |
22 | #include "tc_util.h" | |
23 | #include <linux/tc_act/tc_ipt.h> | |
24 | #include <stdio.h> | |
25 | #include <dlfcn.h> | |
26 | #include <getopt.h> | |
27 | #include <errno.h> | |
28 | #include <string.h> | |
29 | #include <netdb.h> | |
30 | #include <stdlib.h> | |
31 | #include <ctype.h> | |
32 | #include <stdarg.h> | |
a36ceb85 AH |
33 | #include <unistd.h> |
34 | #include <fcntl.h> | |
35 | #include <sys/wait.h> | |
36 | #ifndef XT_LIB_DIR | |
37 | # define XT_LIB_DIR "/lib/xtables" | |
38 | #endif | |
39 | ||
cfa292de | 40 | #ifndef __ALIGN_KERNEL |
4b83a08c SH |
41 | #define __ALIGN_KERNEL(x, a) \ |
42 | __ALIGN_KERNEL_MASK(x, (typeof(x))(a) - 1) | |
43 | #define __ALIGN_KERNEL_MASK(x, mask) \ | |
44 | (((x) + (mask)) & ~(mask)) | |
cfa292de AD |
45 | #endif |
46 | ||
609ceb80 | 47 | #ifndef ALIGN |
32a121cb | 48 | #define ALIGN(x, a) __ALIGN_KERNEL((x), (a)) |
609ceb80 SH |
49 | #endif |
50 | ||
a36ceb85 AH |
51 | static const char *tname = "mangle"; |
52 | ||
53 | char *lib_dir; | |
54 | ||
4b83a08c | 55 | static const char * const ipthooks[] = { |
a36ceb85 AH |
56 | "NF_IP_PRE_ROUTING", |
57 | "NF_IP_LOCAL_IN", | |
58 | "NF_IP_FORWARD", | |
59 | "NF_IP_LOCAL_OUT", | |
60 | "NF_IP_POST_ROUTING", | |
61 | }; | |
62 | ||
63 | static struct option original_opts[] = { | |
64 | { | |
65 | .name = "jump", | |
66 | .has_arg = 1, | |
67 | .val = 'j' | |
68 | }, | |
69 | {0, 0, 0, 0} | |
70 | }; | |
71 | ||
72 | static struct xtables_globals tcipt_globals = { | |
73 | .option_offset = 0, | |
74 | .program_name = "tc-ipt", | |
75 | .program_version = "0.2", | |
76 | .orig_opts = original_opts, | |
77 | .opts = original_opts, | |
78 | .exit_err = NULL, | |
a05b9557 | 79 | #if XTABLES_VERSION_CODE >= 11 |
97a02cab PS |
80 | .compat_rev = xtables_compatible_revision, |
81 | #endif | |
a36ceb85 AH |
82 | }; |
83 | ||
84 | /* | |
85 | * we may need to check for version mismatch | |
86 | */ | |
d1f28cf1 | 87 | static int |
a36ceb85 AH |
88 | build_st(struct xtables_target *target, struct xt_entry_target *t) |
89 | { | |
90 | ||
91 | size_t size = | |
32a121cb | 92 | XT_ALIGN(sizeof(struct xt_entry_target)) + target->size; |
a36ceb85 | 93 | |
32a121cb | 94 | if (t == NULL) { |
a36ceb85 AH |
95 | target->t = xtables_calloc(1, size); |
96 | target->t->u.target_size = size; | |
56270e54 PS |
97 | strncpy(target->t->u.user.name, target->name, |
98 | sizeof(target->t->u.user.name) - 1); | |
be3c4d4f | 99 | target->t->u.user.revision = target->revision; |
a36ceb85 AH |
100 | |
101 | if (target->init != NULL) | |
102 | target->init(target->t); | |
103 | } else { | |
104 | target->t = t; | |
105 | } | |
106 | return 0; | |
107 | ||
108 | } | |
109 | ||
d1f28cf1 | 110 | static void set_lib_dir(void) |
a36ceb85 AH |
111 | { |
112 | ||
113 | lib_dir = getenv("XTABLES_LIBDIR"); | |
114 | if (!lib_dir) { | |
115 | lib_dir = getenv("IPTABLES_LIB_DIR"); | |
116 | if (lib_dir) | |
32a121cb | 117 | fprintf(stderr, "using deprecated IPTABLES_LIB_DIR\n"); |
a36ceb85 AH |
118 | } |
119 | if (lib_dir == NULL) | |
120 | lib_dir = XT_LIB_DIR; | |
121 | ||
122 | } | |
123 | ||
2ef40085 PS |
124 | static int get_xtables_target_opts(struct xtables_globals *globals, |
125 | struct xtables_target *m) | |
126 | { | |
127 | struct option *opts; | |
128 | ||
a05b9557 | 129 | #if XTABLES_VERSION_CODE >= 6 |
2ef40085 PS |
130 | opts = xtables_options_xfrm(globals->orig_opts, |
131 | globals->opts, | |
132 | m->x6_options, | |
133 | &m->option_offset); | |
134 | #else | |
135 | opts = xtables_merge_options(globals->opts, | |
136 | m->extra_opts, | |
137 | &m->option_offset); | |
138 | #endif | |
139 | if (!opts) | |
140 | return -1; | |
141 | globals->opts = opts; | |
142 | return 0; | |
143 | } | |
144 | ||
32a121cb | 145 | static int parse_ipt(struct action_util *a, int *argc_p, |
a36ceb85 AH |
146 | char ***argv_p, int tca_id, struct nlmsghdr *n) |
147 | { | |
148 | struct xtables_target *m = NULL; | |
f6fc1055 PS |
149 | #if XTABLES_VERSION_CODE >= 6 |
150 | struct ipt_entry fw = {}; | |
151 | #endif | |
a36ceb85 | 152 | struct rtattr *tail; |
852d5122 | 153 | |
a36ceb85 | 154 | int c; |
a36ceb85 | 155 | char **argv = *argv_p; |
f6ddd9c5 | 156 | int argc; |
b317557f | 157 | char k[FILTER_NAMESZ]; |
a36ceb85 AH |
158 | int size = 0; |
159 | int iok = 0, ok = 0; | |
160 | __u32 hook = 0, index = 0; | |
a36ceb85 | 161 | |
8eee75a8 PS |
162 | /* copy tcipt_globals because .opts will be modified by iptables */ |
163 | struct xtables_globals tmp_tcipt_globals = tcipt_globals; | |
4b83a08c | 164 | |
8eee75a8 | 165 | xtables_init_all(&tmp_tcipt_globals, NFPROTO_IPV4); |
a36ceb85 AH |
166 | set_lib_dir(); |
167 | ||
f6ddd9c5 PS |
168 | /* parse only up until the next action */ |
169 | for (argc = 0; argc < *argc_p; argc++) { | |
170 | if (!argv[argc] || !strcmp(argv[argc], "action")) | |
171 | break; | |
a36ceb85 AH |
172 | } |
173 | ||
174 | if (argc <= 2) { | |
4b83a08c SH |
175 | fprintf(stderr, |
176 | "too few arguments for xt, need at least '-j <target>'\n"); | |
a36ceb85 AH |
177 | return -1; |
178 | } | |
179 | ||
180 | while (1) { | |
8eee75a8 | 181 | c = getopt_long(argc, argv, "j:", tmp_tcipt_globals.opts, NULL); |
a36ceb85 AH |
182 | if (c == -1) |
183 | break; | |
184 | switch (c) { | |
185 | case 'j': | |
186 | m = xtables_find_target(optarg, XTF_TRY_LOAD); | |
f1a7c7d8 | 187 | if (!m) { |
4b83a08c SH |
188 | fprintf(stderr, |
189 | " failed to find target %s\n\n", | |
190 | optarg); | |
f1a7c7d8 PS |
191 | return -1; |
192 | } | |
a36ceb85 | 193 | |
f1a7c7d8 PS |
194 | if (build_st(m, NULL) < 0) { |
195 | printf(" %s error\n", m->name); | |
196 | return -1; | |
197 | } | |
2ef40085 | 198 | |
4b83a08c SH |
199 | if (get_xtables_target_opts(&tmp_tcipt_globals, |
200 | m) < 0) { | |
201 | fprintf(stderr, | |
202 | " failed to find additional options for target %s\n\n", | |
203 | optarg); | |
852d5122 | 204 | return -1; |
2ef40085 | 205 | } |
a36ceb85 AH |
206 | ok++; |
207 | break; | |
208 | ||
209 | default: | |
a05b9557 | 210 | #if XTABLES_VERSION_CODE >= 6 |
f1a7c7d8 | 211 | if (m != NULL && m->x6_parse != NULL) { |
f6fc1055 | 212 | xtables_option_tpcall(c, argv, 0, m, &fw); |
852d5122 | 213 | #else |
f1a7c7d8 PS |
214 | if (m != NULL && m->parse != NULL) { |
215 | m->parse(c - m->option_offset, argv, 0, | |
4b83a08c | 216 | &m->tflags, NULL, &m->t); |
852d5122 | 217 | #endif |
a36ceb85 | 218 | } else { |
4b83a08c SH |
219 | fprintf(stderr, |
220 | "failed to find target %s\n\n", optarg); | |
a36ceb85 AH |
221 | return -1; |
222 | ||
223 | } | |
224 | ok++; | |
225 | break; | |
a36ceb85 AH |
226 | } |
227 | } | |
228 | ||
28432f37 | 229 | if (argc > optind) { |
a36ceb85 AH |
230 | if (matches(argv[optind], "index") == 0) { |
231 | if (get_u32(&index, argv[optind + 1], 10)) { | |
232 | fprintf(stderr, "Illegal \"index\"\n"); | |
233 | xtables_free_opts(1); | |
234 | return -1; | |
235 | } | |
236 | iok++; | |
237 | ||
238 | optind += 2; | |
239 | } | |
240 | } | |
241 | ||
242 | if (!ok && !iok) { | |
32a121cb | 243 | fprintf(stderr, " ipt Parser BAD!! (%s)\n", *argv); |
a36ceb85 AH |
244 | return -1; |
245 | } | |
246 | ||
247 | /* check that we passed the correct parameters to the target */ | |
a05b9557 | 248 | #if XTABLES_VERSION_CODE >= 6 |
852d5122 JHS |
249 | if (m) |
250 | xtables_option_tfcall(m); | |
251 | #else | |
a36ceb85 AH |
252 | if (m && m->final_check) |
253 | m->final_check(m->tflags); | |
852d5122 | 254 | #endif |
a36ceb85 AH |
255 | |
256 | { | |
257 | struct tcmsg *t = NLMSG_DATA(n); | |
32a121cb | 258 | |
a36ceb85 AH |
259 | if (t->tcm_parent != TC_H_ROOT |
260 | && t->tcm_parent == TC_H_MAJ(TC_H_INGRESS)) { | |
261 | hook = NF_IP_PRE_ROUTING; | |
262 | } else { | |
263 | hook = NF_IP_POST_ROUTING; | |
264 | } | |
265 | } | |
266 | ||
267 | tail = NLMSG_TAIL(n); | |
268 | addattr_l(n, MAX_MSG, tca_id, NULL, 0); | |
269 | fprintf(stdout, "tablename: %s hook: %s\n ", tname, ipthooks[hook]); | |
270 | fprintf(stdout, "\ttarget: "); | |
271 | ||
44574522 PS |
272 | if (m) { |
273 | if (m->print) | |
274 | m->print(NULL, m->t, 0); | |
275 | else | |
276 | printf("%s ", m->name); | |
277 | } | |
a36ceb85 AH |
278 | fprintf(stdout, " index %d\n", index); |
279 | ||
56270e54 PS |
280 | if (strlen(tname) >= 16) { |
281 | size = 15; | |
a36ceb85 AH |
282 | k[15] = 0; |
283 | } else { | |
284 | size = 1 + strlen(tname); | |
285 | } | |
286 | strncpy(k, tname, size); | |
287 | ||
288 | addattr_l(n, MAX_MSG, TCA_IPT_TABLE, k, size); | |
289 | addattr_l(n, MAX_MSG, TCA_IPT_HOOK, &hook, 4); | |
290 | addattr_l(n, MAX_MSG, TCA_IPT_INDEX, &index, 4); | |
291 | if (m) | |
292 | addattr_l(n, MAX_MSG, TCA_IPT_TARG, m->t, m->t->u.target_size); | |
293 | tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; | |
294 | ||
a36ceb85 | 295 | argv += optind; |
28432f37 | 296 | *argc_p -= argc; |
a36ceb85 AH |
297 | *argv_p = argv; |
298 | ||
299 | optind = 0; | |
300 | xtables_free_opts(1); | |
a36ceb85 | 301 | |
4f3626f9 DM |
302 | if (m) { |
303 | /* Clear flags if target will be used again */ | |
304 | m->tflags = 0; | |
305 | m->used = 0; | |
306 | /* Free allocated memory */ | |
307 | if (m->t) | |
308 | free(m->t); | |
309 | } | |
a36ceb85 AH |
310 | |
311 | return 0; | |
312 | ||
313 | } | |
314 | ||
315 | static int | |
4b83a08c | 316 | print_ipt(struct action_util *au, FILE *f, struct rtattr *arg) |
a36ceb85 | 317 | { |
b45f9141 | 318 | struct xtables_target *m; |
a36ceb85 AH |
319 | struct rtattr *tb[TCA_IPT_MAX + 1]; |
320 | struct xt_entry_target *t = NULL; | |
321 | ||
322 | if (arg == NULL) | |
323 | return -1; | |
324 | ||
6e2e5ec2 AG |
325 | /* copy tcipt_globals because .opts will be modified by iptables */ |
326 | struct xtables_globals tmp_tcipt_globals = tcipt_globals; | |
327 | ||
328 | xtables_init_all(&tmp_tcipt_globals, NFPROTO_IPV4); | |
a36ceb85 AH |
329 | set_lib_dir(); |
330 | ||
331 | parse_rtattr_nested(tb, TCA_IPT_MAX, arg); | |
332 | ||
333 | if (tb[TCA_IPT_TABLE] == NULL) { | |
334 | fprintf(f, "[NULL ipt table name ] assuming mangle "); | |
335 | } else { | |
336 | fprintf(f, "tablename: %s ", | |
ff24746c | 337 | rta_getattr_str(tb[TCA_IPT_TABLE])); |
a36ceb85 AH |
338 | } |
339 | ||
340 | if (tb[TCA_IPT_HOOK] == NULL) { | |
341 | fprintf(f, "[NULL ipt hook name ]\n "); | |
342 | return -1; | |
343 | } else { | |
344 | __u32 hook; | |
32a121cb | 345 | |
ff24746c | 346 | hook = rta_getattr_u32(tb[TCA_IPT_HOOK]); |
32a121cb | 347 | fprintf(f, " hook: %s\n", ipthooks[hook]); |
a36ceb85 AH |
348 | } |
349 | ||
350 | if (tb[TCA_IPT_TARG] == NULL) { | |
32a121cb | 351 | fprintf(f, "\t[NULL ipt target parameters ]\n"); |
a36ceb85 | 352 | return -1; |
b45f9141 PS |
353 | } |
354 | ||
355 | t = RTA_DATA(tb[TCA_IPT_TARG]); | |
356 | m = xtables_find_target(t->u.user.name, XTF_TRY_LOAD); | |
357 | if (!m) { | |
358 | fprintf(stderr, " failed to find target %s\n\n", | |
359 | t->u.user.name); | |
360 | return -1; | |
361 | } | |
362 | if (build_st(m, t) < 0) { | |
363 | fprintf(stderr, " %s error\n", m->name); | |
364 | return -1; | |
365 | } | |
a36ceb85 | 366 | |
2ef40085 PS |
367 | if (get_xtables_target_opts(&tmp_tcipt_globals, m) < 0) { |
368 | fprintf(stderr, | |
4b83a08c | 369 | " failed to find additional options for target %s\n\n", |
2ef40085 | 370 | t->u.user.name); |
b45f9141 | 371 | return -1; |
2ef40085 | 372 | } |
b45f9141 PS |
373 | fprintf(f, "\ttarget "); |
374 | m->print(NULL, m->t, 0); | |
375 | if (tb[TCA_IPT_INDEX] == NULL) { | |
376 | fprintf(f, " [NULL ipt target index ]\n"); | |
377 | } else { | |
378 | __u32 index; | |
32a121cb | 379 | |
b45f9141 | 380 | index = rta_getattr_u32(tb[TCA_IPT_INDEX]); |
53075318 | 381 | fprintf(f, "\n\tindex %u", index); |
b45f9141 | 382 | } |
a36ceb85 | 383 | |
b45f9141 PS |
384 | if (tb[TCA_IPT_CNT]) { |
385 | struct tc_cnt *c = RTA_DATA(tb[TCA_IPT_CNT]); | |
32a121cb | 386 | |
b45f9141 PS |
387 | fprintf(f, " ref %d bind %d", c->refcnt, c->bindcnt); |
388 | } | |
389 | if (show_stats) { | |
390 | if (tb[TCA_IPT_TM]) { | |
391 | struct tcf_t *tm = RTA_DATA(tb[TCA_IPT_TM]); | |
32a121cb | 392 | |
b45f9141 | 393 | print_tm(f, tm); |
a36ceb85 | 394 | } |
a36ceb85 | 395 | } |
b45f9141 PS |
396 | fprintf(f, "\n"); |
397 | ||
a36ceb85 AH |
398 | xtables_free_opts(1); |
399 | ||
400 | return 0; | |
401 | } | |
402 | ||
8e91a80d | 403 | struct action_util xt_action_util = { |
32a121cb SH |
404 | .id = "xt", |
405 | .parse_aopt = parse_ipt, | |
406 | .print_aopt = print_ipt, | |
a36ceb85 | 407 | }; |