/*
- * m_ipt.c iptables based targets
+ * m_ipt.c iptables based targets
* utilities mostly ripped from iptables <duh, its the linux way>
*
* This program is free software; you can distribute it and/or
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * Authors: J Hadi Salim (hadi@cyberus.ca)
- *
- * TODO: bad bad hardcoding IPT_LIB_DIR and PROC_SYS_MODPROBE
- *
-*/
+ * Authors: J Hadi Salim (hadi@cyberus.ca)
+ */
#include <syslog.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
+#include <linux/if.h>
#include <iptables.h>
+#include <linux/netfilter.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include "utils.h"
#include "tc_util.h"
#include <stdlib.h>
#include <ctype.h>
#include <stdarg.h>
-#include <limits.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
-const char *pname = "tc-ipt";
-const char *tname = "mangle";
-const char *pversion = "0.1";
-
-#ifndef TRUE
-#define TRUE 1
-#endif
-#ifndef FALSE
-#define FALSE 0
-#endif
-
-#ifndef IPT_LIB_DIR
-#define IPT_LIB_DIR "/usr/local/lib/iptables"
-#endif
-
-#ifndef PROC_SYS_MODPROBE
-#define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe"
-#endif
+static const char *pname = "tc-ipt";
+static const char *tname = "mangle";
+static const char *pversion = "0.1";
static const char *ipthooks[] = {
"NF_IP_PRE_ROUTING",
};
static struct iptables_target *t_list = NULL;
+static struct option *opts = original_opts;
static unsigned int global_option_offset = 0;
#define OPTION_OFFSET 256
-#if 0
-/* no clue why register match is within targets
- figure out later. Talk to Harald -- JHS
-*/
-void
-register_match(struct iptables_match *me)
-{
-/* fprintf(stderr, "\nDummy register_match\n"); */
-}
+char *lib_dir;
void
register_target(struct iptables_target *me)
t_list = me;
}
-#endif
+
+void
+xtables_register_target(struct iptables_target *me)
+{
+ me->next = t_list;
+ t_list = me;
+}
void
exit_tryhelp(int status)
return buf;
}
-int string_to_number_ll(const char *s, unsigned long long min,
+int string_to_number_ll(const char *s, unsigned long long min,
unsigned long long max,
unsigned long long *ret)
{
return result;
}
-#if 0
-static int
-string_to_number(const char *s, unsigned int min, unsigned int max,
- unsigned int *ret)
+static void free_opts(struct option *local_opts)
{
- long number;
- char *end;
-
- /* Handle hex, octal, etc. */
- errno = 0;
- number = strtol(s, &end, 0);
- if (*end == '\0' && end != s) {
- /* we parsed a number, let's see if we want this */
- if (errno != ERANGE && min <= number && number <= max) {
- *ret = number;
- return 0;
- }
+ if (local_opts != original_opts) {
+ free(local_opts);
+ opts = original_opts;
+ global_option_offset = 0;
}
- return -1;
-}
-#endif
-
-static struct option *
-copy_options(struct option *oldopts)
-{
- struct option *merge;
- unsigned int num_old;
- for (num_old = 0; oldopts[num_old].name; num_old++) ;
- merge = malloc(sizeof (struct option) * (num_old + 1));
- if (NULL == merge)
- return NULL;
- memcpy(merge, oldopts, num_old * sizeof (struct option));
- memset(merge + num_old, 0, sizeof (struct option));
- return merge;
}
static struct option *
return p;
}
-#if 0
-static void *
-fw_malloc(size_t size)
-{
- void *p;
-
- if ((p = (void *) malloc(size)) == NULL) {
- perror("iptables: malloc failed");
- exit(1);
- }
- return p;
-}
-
-static int
-check_inverse(const char option[], int *invert)
-{
- if (option && strcmp(option, "!") == 0) {
- if (*invert)
- exit_error(PARAMETER_PROBLEM,
- "Multiple `!' flags not allowed");
-
- *invert = TRUE;
- return TRUE;
- }
- return FALSE;
-}
-#endif
-
static struct iptables_target *
find_t(char *name)
{
}
static struct iptables_target *
-get_target_name(char *name)
+get_target_name(const char *name)
{
void *handle;
char *error;
char *new_name, *lname;
struct iptables_target *m;
+ char path[strlen(lib_dir) + sizeof ("/libipt_.so") + strlen(name)];
- char path[sizeof (IPT_LIB_DIR) + sizeof ("/libipt_.so") + strlen(name)];
+#ifdef NO_SHARED_LIBS
+ return NULL;
+#endif
new_name = malloc(strlen(name) + 1);
lname = malloc(strlen(name) + 1);
}
}
- sprintf(path, IPT_LIB_DIR "/libipt_%s.so", new_name);
+ /* try libxt_xx first */
+ sprintf(path, "%s/libxt_%s.so", lib_dir, new_name);
handle = dlopen(path, RTLD_LAZY);
if (!handle) {
- sprintf(path, IPT_LIB_DIR "/libipt_%s.so", lname);
+ /* try libipt_xx next */
+ sprintf(path, "%s/libipt_%s.so", lib_dir, new_name);
handle = dlopen(path, RTLD_LAZY);
+
+ if (!handle) {
+ sprintf(path, "%s/libxt_%s.so", lib_dir , lname);
+ handle = dlopen(path, RTLD_LAZY);
+ }
+
+ if (!handle) {
+ sprintf(path, "%s/libipt_%s.so", lib_dir , lname);
+ handle = dlopen(path, RTLD_LAZY);
+ }
+ /* ok, lets give up .. */
if (!handle) {
fputs(dlerror(), stderr);
printf("\n");
+ free(new_name);
+ free(lname);
return NULL;
}
}
fputs(error, stderr);
fprintf(stderr, "\n");
dlclose(handle);
+ free(new_name);
+ free(lname);
return NULL;
}
}
}
}
+ free(new_name);
+ free(lname);
return m;
}
-#if 0
-static char *
-addr_to_dotted(const struct in_addr *addrp)
-{
- static char buf[20];
- const unsigned char *bytep;
-
- bytep = (const unsigned char *) &(addrp->s_addr);
- sprintf(buf, "%d.%d.%d.%d", bytep[0], bytep[1], bytep[2], bytep[3]);
- return buf;
-}
-#endif
struct in_addr *dotted_to_addr(const char *dotted)
{
return &addr;
}
+static void set_revision(char *name, u_int8_t revision)
+{
+ /* Old kernel sources don't have ".revision" field,
+ * but we stole a byte from name. */
+ name[IPT_FUNCTION_MAXNAMELEN - 2] = '\0';
+ name[IPT_FUNCTION_MAXNAMELEN - 1] = revision;
+}
+
+/*
+ * we may need to check for version mismatch
+*/
int
build_st(struct iptables_target *target, struct ipt_entry_target *t)
{
if (NULL == t) {
target->t = fw_calloc(1, size);
- target->init(target->t, &nfcache);
target->t->u.target_size = size;
+
+ if (target->init != NULL)
+ target->init(target->t, &nfcache);
+ set_revision(target->t->u.user.name, target->revision);
} else {
target->t = t;
}
return -1;
}
-static int parse_ipt(struct action_util *a,int *argc_p,
+static int parse_ipt(struct action_util *a,int *argc_p,
char ***argv_p, int tca_id, struct nlmsghdr *n)
{
struct iptables_target *m = NULL;
int c;
int rargc = *argc_p;
char **argv = *argv_p;
- struct option *opts;
int argc = 0, iargc = 0;
char k[16];
- int res = -1;
int size = 0;
int iok = 0, ok = 0;
__u32 hook = 0, index = 0;
- res = 0;
+
+ lib_dir = getenv("IPTABLES_LIB_DIR");
+ if (!lib_dir)
+ lib_dir = IPT_LIB_DIR;
{
int i;
return -1;
}
- opts = copy_options(original_opts);
-
- if (NULL == opts)
- return -1;
-
while (1) {
c = getopt_long(argc, argv, "j:", opts, NULL);
if (c == -1)
default:
memset(&fw, 0, sizeof (fw));
if (m) {
- unsigned int fake_flags = 0;
m->parse(c - m->option_offset, argv, 0,
- &fake_flags, NULL, &m->t);
+ &m->tflags, NULL, &m->t);
} else {
fprintf(stderr," failed to find target %s\n\n", optarg);
return -1;
}
ok++;
-
- /*m->final_check(m->t); -- Is this necessary?
- ** useful when theres depencies
- ** eg ipt_TCPMSS.c has have the TCP match loaded
- ** before this can be used;
- ** also seems the ECN target needs it
- */
-
break;
}
if (matches(argv[optind], "index") == 0) {
if (get_u32(&index, argv[optind + 1], 10)) {
fprintf(stderr, "Illegal \"index\"\n");
+ free_opts(opts);
return -1;
}
iok++;
return -1;
}
+ /* check that we passed the correct parameters to the target */
+ if (m)
+ m->final_check(m->tflags);
+
{
struct tcmsg *t = NLMSG_DATA(n);
if (t->tcm_parent != TC_H_ROOT
argv += optind;
*argc_p = rargc - iargc;
*argv_p = argv;
-
- optind = 1;
+
+ optind = 0;
+ free_opts(opts);
+ /* Clear flags if target will be used again */
+ m->tflags=0;
+ m->used=0;
+ /* Free allocated memory */
+ if (m->t)
+ free(m->t);
+
return 0;
{
struct rtattr *tb[TCA_IPT_MAX + 1];
struct ipt_entry_target *t = NULL;
- struct option *opts;
if (arg == NULL)
return -1;
- opts = copy_options(original_opts);
-
- if (NULL == opts)
- return -1;
+ lib_dir = getenv("IPTABLES_LIB_DIR");
+ if (!lib_dir)
+ lib_dir = IPT_LIB_DIR;
parse_rtattr_nested(tb, TCA_IPT_MAX, arg);
fprintf(f, "[NULL ipt table name ] assuming mangle ");
} else {
fprintf(f, "tablename: %s ",
- (char *) RTA_DATA(tb[TCA_IPT_TABLE]));
+ rta_getattr_str(tb[TCA_IPT_TABLE]));
}
if (tb[TCA_IPT_HOOK] == NULL) {
return -1;
} else {
__u32 hook;
- hook = *(__u32 *) RTA_DATA(tb[TCA_IPT_HOOK]);
+ hook = rta_getattr_u32(tb[TCA_IPT_HOOK]);
fprintf(f, " hook: %s \n", ipthooks[hook]);
}
fprintf(f, " [NULL ipt target index ]\n");
} else {
__u32 index;
- index = *(__u32 *) RTA_DATA(tb[TCA_IPT_INDEX]);
+ index = rta_getattr_u32(tb[TCA_IPT_INDEX]);
fprintf(f, " \n\tindex %d", index);
}
struct tcf_t *tm = RTA_DATA(tb[TCA_IPT_TM]);
print_tm(f,tm);
}
- }
+ }
fprintf(f, " \n");
}
+ free_opts(opts);
return 0;
}