]> rtime.felk.cvut.cz Git - lisovros/iproute2_canprio.git/blob - tc/m_xt.c
Allow default DP of zero in gred
[lisovros/iproute2_canprio.git] / tc / m_xt.c
1 /*
2  * m_xt.c       xtables based targets
3  *              utilities mostly ripped from iptables <duh, its the linux way>
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
13 /*XXX: in the future (xtables 1.4.3?) get rid of everything tagged
14  * as TC_CONFIG_XT_H */
15
16 #include <syslog.h>
17 #include <sys/socket.h>
18 #include <netinet/in.h>
19 #include <arpa/inet.h>
20 #include <net/if.h>
21 #include <linux/netfilter.h>
22 #include <linux/netfilter_ipv4/ip_tables.h>
23 #include <xtables.h>
24 #include "utils.h"
25 #include "tc_util.h"
26 #include <linux/tc_act/tc_ipt.h>
27 #include <stdio.h>
28 #include <dlfcn.h>
29 #include <getopt.h>
30 #include <errno.h>
31 #include <string.h>
32 #include <netdb.h>
33 #include <stdlib.h>
34 #include <ctype.h>
35 #include <stdarg.h>
36 #include <limits.h>
37 #include <unistd.h>
38 #include <fcntl.h>
39 #include <sys/wait.h>
40 #ifdef TC_CONFIG_XT_H
41 #include "xt-internal.h"
42 #endif
43
44 static const char *pname = "tc-ipt";
45 static const char *tname = "mangle";
46 static const char *pversion = "0.2";
47
48 static const char *ipthooks[] = {
49         "NF_IP_PRE_ROUTING",
50         "NF_IP_LOCAL_IN",
51         "NF_IP_FORWARD",
52         "NF_IP_LOCAL_OUT",
53         "NF_IP_POST_ROUTING",
54 };
55
56 static struct option original_opts[] = {
57         {"jump", 1, 0, 'j'},
58         {0, 0, 0, 0}
59 };
60
61 static struct option *opts = original_opts;
62 static unsigned int global_option_offset = 0;
63 char *lib_dir;
64 const char *program_version = XTABLES_VERSION;
65 const char *program_name = "tc-ipt";
66 struct afinfo afinfo = {
67         .family         = AF_INET,
68         .libprefix      = "libxt_",
69         .ipproto        = IPPROTO_IP,
70         .kmod           = "ip_tables",
71         .so_rev_target  = IPT_SO_GET_REVISION_TARGET,
72 };
73
74
75 #define OPTION_OFFSET 256
76
77 /*XXX: TC_CONFIG_XT_H */
78 static void free_opts(struct option *local_opts)
79 {
80         if (local_opts != original_opts) {
81                 free(local_opts);
82                 opts = original_opts;
83                 global_option_offset = 0;
84         }
85 }
86
87 /*XXX: TC_CONFIG_XT_H */
88 static struct option *
89 merge_options(struct option *oldopts, const struct option *newopts,
90               unsigned int *option_offset)
91 {
92         struct option *merge;
93         unsigned int num_old, num_new, i;
94
95         for (num_old = 0; oldopts[num_old].name; num_old++) ;
96         for (num_new = 0; newopts[num_new].name; num_new++) ;
97
98         *option_offset = global_option_offset + OPTION_OFFSET;
99
100         merge = malloc(sizeof (struct option) * (num_new + num_old + 1));
101         memcpy(merge, oldopts, num_old * sizeof (struct option));
102         for (i = 0; i < num_new; i++) {
103                 merge[num_old + i] = newopts[i];
104                 merge[num_old + i].val += *option_offset;
105         }
106         memset(merge + num_old + num_new, 0, sizeof (struct option));
107
108         return merge;
109 }
110
111
112 /*XXX: TC_CONFIG_XT_H */
113 #ifndef TRUE
114 #define TRUE 1
115 #endif
116 #ifndef FALSE
117 #define FALSE 0
118 #endif
119
120 /*XXX: TC_CONFIG_XT_H */
121 int
122 check_inverse(const char option[], int *invert, int *my_optind, int argc)
123 {
124         if (option && strcmp(option, "!") == 0) {
125                 if (*invert)
126                         exit_error(PARAMETER_PROBLEM,
127                                    "Multiple `!' flags not allowed");
128                 *invert = TRUE;
129                 if (my_optind != NULL) {
130                         ++*my_optind;
131                         if (argc && *my_optind > argc)
132                                 exit_error(PARAMETER_PROBLEM,
133                                            "no argument following `!'");
134                 }
135
136                 return TRUE;
137         }
138         return FALSE;
139 }
140
141 /*XXX: TC_CONFIG_XT_H */
142 void exit_error(enum exittype status, const char *msg, ...)
143 {
144         va_list args;
145
146         va_start(args, msg);
147         fprintf(stderr, "%s v%s: ", pname, pversion);
148         vfprintf(stderr, msg, args);
149         va_end(args);
150         fprintf(stderr, "\n");
151         /* On error paths, make sure that we don't leak memory */
152         exit(status);
153 }
154
155 /*XXX: TC_CONFIG_XT_H */
156 static void set_revision(char *name, u_int8_t revision)
157 {
158         /* Old kernel sources don't have ".revision" field,
159         *  but we stole a byte from name. */
160         name[IPT_FUNCTION_MAXNAMELEN - 2] = '\0';
161         name[IPT_FUNCTION_MAXNAMELEN - 1] = revision;
162 }
163
164 /*
165  * we may need to check for version mismatch
166 */
167 int
168 build_st(struct xtables_target *target, struct xt_entry_target *t)
169 {
170
171         size_t size =
172                     XT_ALIGN(sizeof (struct xt_entry_target)) + target->size;
173
174         if (NULL == t) {
175                 target->t = fw_calloc(1, size);
176                 target->t->u.target_size = size;
177                 strcpy(target->t->u.user.name, target->name);
178                 set_revision(target->t->u.user.name, target->revision);
179
180                 if (target->init != NULL)
181                         target->init(target->t);
182         } else {
183                 target->t = t;
184         }
185         return 0;
186
187 }
188
189 inline void set_lib_dir(void)
190 {
191
192         lib_dir = getenv("XTABLES_LIBDIR");
193         if (!lib_dir) {
194                 lib_dir = getenv("IPTABLES_LIB_DIR");
195                 if (lib_dir)
196                         fprintf(stderr, "using deprecated IPTABLES_LIB_DIR \n");
197         }
198         if (lib_dir == NULL)
199                 lib_dir = XT_LIB_DIR;
200
201 }
202
203 static int parse_ipt(struct action_util *a,int *argc_p,
204                      char ***argv_p, int tca_id, struct nlmsghdr *n)
205 {
206         struct xtables_target *m = NULL;
207         struct ipt_entry fw;
208         struct rtattr *tail;
209         int c;
210         int rargc = *argc_p;
211         char **argv = *argv_p;
212         int argc = 0, iargc = 0;
213         char k[16];
214         int res = -1;
215         int size = 0;
216         int iok = 0, ok = 0;
217         __u32 hook = 0, index = 0;
218         res = 0;
219
220         set_lib_dir();
221
222         {
223                 int i;
224                 for (i = 0; i < rargc; i++) {
225                         if (NULL == argv[i] || 0 == strcmp(argv[i], "action")) {
226                                 break;
227                         }
228                 }
229                 iargc = argc = i;
230         }
231
232         if (argc <= 2) {
233                 fprintf(stderr,"bad arguements to ipt %d vs %d \n", argc, rargc);
234                 return -1;
235         }
236
237         while (1) {
238                 c = getopt_long(argc, argv, "j:", opts, NULL);
239                 if (c == -1)
240                         break;
241                 switch (c) {
242                 case 'j':
243                         m = find_target(optarg, TRY_LOAD);
244                         if (NULL != m) {
245
246                                 if (0 > build_st(m, NULL)) {
247                                         printf(" %s error \n", m->name);
248                                         return -1;
249                                 }
250                                 opts =
251                                     merge_options(opts, m->extra_opts,
252                                                   &m->option_offset);
253                         } else {
254                                 fprintf(stderr," failed to find target %s\n\n", optarg);
255                                 return -1;
256                         }
257                         ok++;
258                         break;
259
260                 default:
261                         memset(&fw, 0, sizeof (fw));
262                         if (m) {
263                                 m->parse(c - m->option_offset, argv, 0,
264                                          &m->tflags, NULL, &m->t);
265                         } else {
266                                 fprintf(stderr," failed to find target %s\n\n", optarg);
267                                 return -1;
268
269                         }
270                         ok++;
271                         break;
272
273                 }
274         }
275
276         if (iargc > optind) {
277                 if (matches(argv[optind], "index") == 0) {
278                         if (get_u32(&index, argv[optind + 1], 10)) {
279                                 fprintf(stderr, "Illegal \"index\"\n");
280                                 free_opts(opts);
281                                 return -1;
282                         }
283                         iok++;
284
285                         optind += 2;
286                 }
287         }
288
289         if (!ok && !iok) {
290                 fprintf(stderr," ipt Parser BAD!! (%s)\n", *argv);
291                 return -1;
292         }
293
294         /* check that we passed the correct parameters to the target */
295         if (m)
296                 m->final_check(m->tflags);
297
298         {
299                 struct tcmsg *t = NLMSG_DATA(n);
300                 if (t->tcm_parent != TC_H_ROOT
301                     && t->tcm_parent == TC_H_MAJ(TC_H_INGRESS)) {
302                         hook = NF_IP_PRE_ROUTING;
303                 } else {
304                         hook = NF_IP_POST_ROUTING;
305                 }
306         }
307
308         tail = NLMSG_TAIL(n);
309         addattr_l(n, MAX_MSG, tca_id, NULL, 0);
310         fprintf(stdout, "tablename: %s hook: %s\n ", tname, ipthooks[hook]);
311         fprintf(stdout, "\ttarget: ");
312
313         if (m)
314                 m->print(NULL, m->t, 0);
315         fprintf(stdout, " index %d\n", index);
316
317         if (strlen(tname) > 16) {
318                 size = 16;
319                 k[15] = 0;
320         } else {
321                 size = 1 + strlen(tname);
322         }
323         strncpy(k, tname, size);
324
325         addattr_l(n, MAX_MSG, TCA_IPT_TABLE, k, size);
326         addattr_l(n, MAX_MSG, TCA_IPT_HOOK, &hook, 4);
327         addattr_l(n, MAX_MSG, TCA_IPT_INDEX, &index, 4);
328         if (m)
329                 addattr_l(n, MAX_MSG, TCA_IPT_TARG, m->t, m->t->u.target_size);
330         tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
331
332         argc -= optind;
333         argv += optind;
334         *argc_p = rargc - iargc;
335         *argv_p = argv;
336
337         optind = 0;
338         free_opts(opts);
339         /* Clear flags if target will be used again */
340         m->tflags=0;
341         m->used=0;
342         /* Free allocated memory */
343         if (m->t)
344             free(m->t);
345
346
347         return 0;
348
349 }
350
351 static int
352 print_ipt(struct action_util *au,FILE * f, struct rtattr *arg)
353 {
354         struct rtattr *tb[TCA_IPT_MAX + 1];
355         struct xt_entry_target *t = NULL;
356
357         if (arg == NULL)
358                 return -1;
359
360         set_lib_dir();
361
362         parse_rtattr_nested(tb, TCA_IPT_MAX, arg);
363
364         if (tb[TCA_IPT_TABLE] == NULL) {
365                 fprintf(f, "[NULL ipt table name ] assuming mangle ");
366         } else {
367                 fprintf(f, "tablename: %s ",
368                         (char *) RTA_DATA(tb[TCA_IPT_TABLE]));
369         }
370
371         if (tb[TCA_IPT_HOOK] == NULL) {
372                 fprintf(f, "[NULL ipt hook name ]\n ");
373                 return -1;
374         } else {
375                 __u32 hook;
376                 hook = *(__u32 *) RTA_DATA(tb[TCA_IPT_HOOK]);
377                 fprintf(f, " hook: %s \n", ipthooks[hook]);
378         }
379
380         if (tb[TCA_IPT_TARG] == NULL) {
381                 fprintf(f, "\t[NULL ipt target parameters ] \n");
382                 return -1;
383         } else {
384                 struct xtables_target *m = NULL;
385                 t = RTA_DATA(tb[TCA_IPT_TARG]);
386                 m = find_target(t->u.user.name, TRY_LOAD);
387                 if (NULL != m) {
388                         if (0 > build_st(m, t)) {
389                                 fprintf(stderr, " %s error \n", m->name);
390                                 return -1;
391                         }
392
393                         opts =
394                             merge_options(opts, m->extra_opts,
395                                           &m->option_offset);
396                 } else {
397                         fprintf(stderr, " failed to find target %s\n\n",
398                                 t->u.user.name);
399                         return -1;
400                 }
401                 fprintf(f, "\ttarget ");
402                 m->print(NULL, m->t, 0);
403                 if (tb[TCA_IPT_INDEX] == NULL) {
404                         fprintf(f, " [NULL ipt target index ]\n");
405                 } else {
406                         __u32 index;
407                         index = *(__u32 *) RTA_DATA(tb[TCA_IPT_INDEX]);
408                         fprintf(f, " \n\tindex %d", index);
409                 }
410
411                 if (tb[TCA_IPT_CNT]) {
412                         struct tc_cnt *c  = RTA_DATA(tb[TCA_IPT_CNT]);;
413                         fprintf(f, " ref %d bind %d", c->refcnt, c->bindcnt);
414                 }
415                 if (show_stats) {
416                         if (tb[TCA_IPT_TM]) {
417                                 struct tcf_t *tm = RTA_DATA(tb[TCA_IPT_TM]);
418                                 print_tm(f,tm);
419                         }
420                 }
421                 fprintf(f, " \n");
422
423         }
424         free_opts(opts);
425
426         return 0;
427 }
428
429 struct action_util ipt_action_util = {
430         .id = "ipt",
431         .parse_aopt = parse_ipt,
432         .print_aopt = print_ipt,
433 };
434