2 * m_ipt.c iptables based targets
3 * utilities mostly ripped from iptables <duh, its the linux way>
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.
10 * Authors: J Hadi Salim (hadi@cyberus.ca)
14 #include <sys/socket.h>
15 #include <netinet/in.h>
16 #include <arpa/inet.h>
18 #include <linux/netfilter.h>
19 #include <linux/netfilter_ipv4/ip_tables.h>
22 #include <linux/tc_act/tc_ipt.h>
36 static const char *pname
= "tc-ipt";
37 static const char *tname
= "mangle";
38 static const char *pversion
= "0.1";
40 static const char *ipthooks
[] = {
48 static struct option original_opts
[] = {
53 static struct xtables_target
*t_list
;
54 static struct option
*opts
= original_opts
;
55 static unsigned int global_option_offset
;
56 #define OPTION_OFFSET 256
61 xtables_register_target(struct xtables_target
*me
)
68 static void exit_tryhelp(int status
)
70 fprintf(stderr
, "Try `%s -h' or '%s --help' for more information.\n",
75 static void exit_error(enum xtables_exittype status
, char *msg
, ...)
80 fprintf(stderr
, "%s v%s: ", pname
, pversion
);
81 vfprintf(stderr
, msg
, args
);
83 fprintf(stderr
, "\n");
84 if (status
== PARAMETER_PROBLEM
)
86 if (status
== VERSION_PROBLEM
)
88 "Perhaps iptables or your kernel needs to be upgraded.\n");
92 /* stolen from iptables 1.2.11
93 They should really have them as a library so i can link to them
94 Email them next time i remember
97 static void free_opts(struct option
*local_opts
)
99 if (local_opts
!= original_opts
) {
101 opts
= original_opts
;
102 global_option_offset
= 0;
106 static struct option
*
107 merge_options(struct option
*oldopts
, const struct option
*newopts
,
108 unsigned int *option_offset
)
110 struct option
*merge
;
111 unsigned int num_old
, num_new
, i
;
113 for (num_old
= 0; oldopts
[num_old
].name
; num_old
++);
114 for (num_new
= 0; newopts
[num_new
].name
; num_new
++);
116 *option_offset
= global_option_offset
+ OPTION_OFFSET
;
118 merge
= malloc(sizeof(struct option
) * (num_new
+ num_old
+ 1));
119 memcpy(merge
, oldopts
, num_old
* sizeof(struct option
));
120 for (i
= 0; i
< num_new
; i
++) {
121 merge
[num_old
+ i
] = newopts
[i
];
122 merge
[num_old
+ i
].val
+= *option_offset
;
124 memset(merge
+ num_old
+ num_new
, 0, sizeof(struct option
));
130 fw_calloc(size_t count
, size_t size
)
134 if ((p
= (void *) calloc(count
, size
)) == NULL
) {
135 perror("iptables: calloc failed");
141 static struct xtables_target
*
144 struct xtables_target
*m
;
146 for (m
= t_list
; m
; m
= m
->next
) {
147 if (strcmp(m
->name
, name
) == 0)
154 static struct xtables_target
*
155 get_target_name(const char *name
)
159 char *new_name
, *lname
;
160 struct xtables_target
*m
;
161 char path
[strlen(lib_dir
) + sizeof("/libipt_.so") + strlen(name
)];
163 #ifdef NO_SHARED_LIBS
167 new_name
= calloc(1, strlen(name
) + 1);
168 lname
= calloc(1, strlen(name
) + 1);
170 exit_error(PARAMETER_PROBLEM
, "get_target_name");
172 exit_error(PARAMETER_PROBLEM
, "get_target_name");
174 strcpy(new_name
, name
);
177 if (isupper(lname
[0])) {
180 for (i
= 0; i
< strlen(name
); i
++) {
181 lname
[i
] = tolower(lname
[i
]);
185 if (islower(new_name
[0])) {
188 for (i
= 0; i
< strlen(new_name
); i
++) {
189 new_name
[i
] = toupper(new_name
[i
]);
193 /* try libxt_xx first */
194 sprintf(path
, "%s/libxt_%s.so", lib_dir
, new_name
);
195 handle
= dlopen(path
, RTLD_LAZY
);
197 /* try libipt_xx next */
198 sprintf(path
, "%s/libipt_%s.so", lib_dir
, new_name
);
199 handle
= dlopen(path
, RTLD_LAZY
);
202 sprintf(path
, "%s/libxt_%s.so", lib_dir
, lname
);
203 handle
= dlopen(path
, RTLD_LAZY
);
207 sprintf(path
, "%s/libipt_%s.so", lib_dir
, lname
);
208 handle
= dlopen(path
, RTLD_LAZY
);
210 /* ok, lets give up .. */
212 fputs(dlerror(), stderr
);
220 m
= dlsym(handle
, new_name
);
221 if ((error
= dlerror()) != NULL
) {
222 m
= (struct xtables_target
*) dlsym(handle
, lname
);
223 if ((error
= dlerror()) != NULL
) {
224 m
= find_t(new_name
);
228 fputs(error
, stderr
);
229 fprintf(stderr
, "\n");
244 static void set_revision(char *name
, u_int8_t revision
)
246 /* Old kernel sources don't have ".revision" field,
247 * but we stole a byte from name. */
248 name
[IPT_FUNCTION_MAXNAMELEN
- 2] = '\0';
249 name
[IPT_FUNCTION_MAXNAMELEN
- 1] = revision
;
253 * we may need to check for version mismatch
255 static int build_st(struct xtables_target
*target
, struct ipt_entry_target
*t
)
261 XT_ALIGN(sizeof(struct ipt_entry_target
)) + target
->size
;
264 target
->t
= fw_calloc(1, size
);
265 target
->t
->u
.target_size
= size
;
267 if (target
->init
!= NULL
)
268 target
->init(target
->t
);
269 set_revision(target
->t
->u
.user
.name
, target
->revision
);
273 strcpy(target
->t
->u
.user
.name
, target
->name
);
280 static int parse_ipt(struct action_util
*a
, int *argc_p
,
281 char ***argv_p
, int tca_id
, struct nlmsghdr
*n
)
283 struct xtables_target
*m
= NULL
;
288 char **argv
= *argv_p
;
289 int argc
= 0, iargc
= 0;
293 __u32 hook
= 0, index
= 0;
295 lib_dir
= getenv("IPTABLES_LIB_DIR");
297 lib_dir
= IPT_LIB_DIR
;
302 for (i
= 0; i
< rargc
; i
++) {
303 if (NULL
== argv
[i
] || 0 == strcmp(argv
[i
], "action")) {
311 fprintf(stderr
, "bad arguments to ipt %d vs %d\n", argc
, rargc
);
316 c
= getopt_long(argc
, argv
, "j:", opts
, NULL
);
321 m
= get_target_name(optarg
);
324 if (build_st(m
, NULL
) < 0) {
325 printf(" %s error\n", m
->name
);
329 merge_options(opts
, m
->extra_opts
,
332 fprintf(stderr
, " failed to find target %s\n\n", optarg
);
339 memset(&fw
, 0, sizeof(fw
));
341 m
->parse(c
- m
->option_offset
, argv
, 0,
342 &m
->tflags
, NULL
, &m
->t
);
344 fprintf(stderr
, " failed to find target %s\n\n", optarg
);
354 if (iargc
> optind
) {
355 if (matches(argv
[optind
], "index") == 0) {
356 if (get_u32(&index
, argv
[optind
+ 1], 10)) {
357 fprintf(stderr
, "Illegal \"index\"\n");
368 fprintf(stderr
, " ipt Parser BAD!! (%s)\n", *argv
);
372 /* check that we passed the correct parameters to the target */
374 m
->final_check(m
->tflags
);
377 struct tcmsg
*t
= NLMSG_DATA(n
);
379 if (t
->tcm_parent
!= TC_H_ROOT
380 && t
->tcm_parent
== TC_H_MAJ(TC_H_INGRESS
)) {
381 hook
= NF_IP_PRE_ROUTING
;
383 hook
= NF_IP_POST_ROUTING
;
387 tail
= NLMSG_TAIL(n
);
388 addattr_l(n
, MAX_MSG
, tca_id
, NULL
, 0);
389 fprintf(stdout
, "tablename: %s hook: %s\n ", tname
, ipthooks
[hook
]);
390 fprintf(stdout
, "\ttarget: ");
393 m
->print(NULL
, m
->t
, 0);
394 fprintf(stdout
, " index %d\n", index
);
396 if (strlen(tname
) > 16) {
400 size
= 1 + strlen(tname
);
402 strncpy(k
, tname
, size
);
404 addattr_l(n
, MAX_MSG
, TCA_IPT_TABLE
, k
, size
);
405 addattr_l(n
, MAX_MSG
, TCA_IPT_HOOK
, &hook
, 4);
406 addattr_l(n
, MAX_MSG
, TCA_IPT_INDEX
, &index
, 4);
408 addattr_l(n
, MAX_MSG
, TCA_IPT_TARG
, m
->t
, m
->t
->u
.target_size
);
409 tail
->rta_len
= (void *) NLMSG_TAIL(n
) - (void *) tail
;
413 *argc_p
= rargc
- iargc
;
418 /* Clear flags if target will be used again */
421 /* Free allocated memory */
431 print_ipt(struct action_util
*au
, FILE * f
, struct rtattr
*arg
)
433 struct rtattr
*tb
[TCA_IPT_MAX
+ 1];
434 struct ipt_entry_target
*t
= NULL
;
439 lib_dir
= getenv("IPTABLES_LIB_DIR");
441 lib_dir
= IPT_LIB_DIR
;
443 parse_rtattr_nested(tb
, TCA_IPT_MAX
, arg
);
445 if (tb
[TCA_IPT_TABLE
] == NULL
) {
446 fprintf(f
, "[NULL ipt table name ] assuming mangle ");
448 fprintf(f
, "tablename: %s ",
449 rta_getattr_str(tb
[TCA_IPT_TABLE
]));
452 if (tb
[TCA_IPT_HOOK
] == NULL
) {
453 fprintf(f
, "[NULL ipt hook name ]\n ");
458 hook
= rta_getattr_u32(tb
[TCA_IPT_HOOK
]);
459 fprintf(f
, " hook: %s\n", ipthooks
[hook
]);
462 if (tb
[TCA_IPT_TARG
] == NULL
) {
463 fprintf(f
, "\t[NULL ipt target parameters ]\n");
466 struct xtables_target
*m
= NULL
;
468 t
= RTA_DATA(tb
[TCA_IPT_TARG
]);
469 m
= get_target_name(t
->u
.user
.name
);
471 if (build_st(m
, t
) < 0) {
472 fprintf(stderr
, " %s error\n", m
->name
);
477 merge_options(opts
, m
->extra_opts
,
480 fprintf(stderr
, " failed to find target %s\n\n",
484 fprintf(f
, "\ttarget ");
485 m
->print(NULL
, m
->t
, 0);
486 if (tb
[TCA_IPT_INDEX
] == NULL
) {
487 fprintf(f
, " [NULL ipt target index ]\n");
491 index
= rta_getattr_u32(tb
[TCA_IPT_INDEX
]);
492 fprintf(f
, "\n\tindex %u", index
);
495 if (tb
[TCA_IPT_CNT
]) {
496 struct tc_cnt
*c
= RTA_DATA(tb
[TCA_IPT_CNT
]);
498 fprintf(f
, " ref %d bind %d", c
->refcnt
, c
->bindcnt
);
501 if (tb
[TCA_IPT_TM
]) {
502 struct tcf_t
*tm
= RTA_DATA(tb
[TCA_IPT_TM
]);
515 struct action_util ipt_action_util
= {
517 .parse_aopt
= parse_ipt
,
518 .print_aopt
= print_ipt
,