contrib/fwd: initial xtables binding
authorJo-Philipp Wich <jow@openwrt.org>
Mon, 14 Dec 2009 02:25:55 +0000 (02:25 +0000)
committerJo-Philipp Wich <jow@openwrt.org>
Mon, 14 Dec 2009 02:25:55 +0000 (02:25 +0000)
contrib/fwd/src/Makefile
contrib/fwd/src/fwd_xtables.c [new file with mode: 0644]
contrib/fwd/src/fwd_xtables.h [new file with mode: 0644]

index 3a7736d54a4a6cb6c65e964432e7d412787ec273..89efd7b065ea1526b0248539fbe76c6256a8593b 100644 (file)
@@ -1,13 +1,14 @@
 CFLAGS  := -g -Wall -I./uci -I./iptables-1.4.5/include
-LDFLAGS := -luci -liptc -L./iptables-1.4.5/libiptc/.libs
+LDFLAGS := -luci -liptc -lxtables -ldl -L./iptables-1.4.5/libiptc/.libs -L./iptables-1.4.5/.libs -Wl,--export-dynamic
 
 fwd:
        $(CC) $(CFLAGS) -c -o ucix.o ucix.c
        $(CC) $(CFLAGS) -c -o fwd_addr.o fwd_addr.c
        $(CC) $(CFLAGS) -c -o fwd_rules.o fwd_rules.c
        $(CC) $(CFLAGS) -c -o fwd_config.o fwd_config.c
+       $(CC) $(CFLAGS) -c -o fwd_xtables.o fwd_xtables.c
        $(CC) $(CFLAGS) -c -o fwd.o fwd.c
-       $(CC) $(LDFLAGS) -o fwd fwd.o fwd_addr.o fwd_rules.o fwd_config.o ucix.o
+       $(CC) $(LDFLAGS) -o fwd fwd.o fwd_addr.o fwd_rules.o fwd_config.o fwd_xtables.o ucix.o
 
 clean:
        rm -f *~ fwd *.o
diff --git a/contrib/fwd/src/fwd_xtables.c b/contrib/fwd/src/fwd_xtables.c
new file mode 100644 (file)
index 0000000..3d057af
--- /dev/null
@@ -0,0 +1,316 @@
+/*
+ * fwd - OpenWrt firewall daemon - libiptc/libxtables interface
+ *
+ *   Copyright (C) 2009 Jo-Philipp Wich <xm@subsignal.org>
+ *
+ * The fwd program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * The fwd program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with the fwd program. If not, see http://www.gnu.org/licenses/.
+ */
+
+
+#include "fwd.h"
+#include "fwd_xtables.h"
+
+
+/* Required by certain extensions like SNAT and DNAT */
+int kernel_version;
+
+extern void
+get_kernel_version(void) {
+       static struct utsname uts;
+       int x = 0, y = 0, z = 0;
+
+       if (uname(&uts) == -1) {
+               fprintf(stderr, "Unable to retrieve kernel version.\n");
+               xtables_free_opts(1);
+               exit(1);
+       }
+
+       sscanf(uts.release, "%d.%d.%d", &x, &y, &z);
+       kernel_version = LINUX_VERSION(x, y, z);
+}
+
+
+static void xt_exit_error(enum xtables_exittype status, const char *msg, ...)
+{
+       va_list ap;
+       va_start(ap, msg);
+       vprintf(msg, ap);
+       va_end(ap);     
+       exit(1);
+}
+
+void fwd_xt_init(void)
+{
+       struct xtables_globals xt_globals = {
+               .option_offset = 0,
+               .program_version = IPTABLES_VERSION,
+               .opts = 0,
+               .orig_opts = 0,
+               .exit_err = (void *)&xt_exit_error,
+       };
+
+       xtables_init();
+       xtables_set_nfproto(NFPROTO_IPV4);
+       xtables_set_params(&xt_globals);
+}
+
+
+struct fwd_xt_rule * fwd_xt_init_rule(const char *table)
+{
+       struct fwd_xt_rule *r;
+
+       if( (r = fwd_alloc_ptr(struct fwd_xt_rule)) != NULL )
+       {
+               if( (r->entry = fwd_alloc_ptr(struct ipt_entry)) != NULL )
+               {
+                       if( (r->iptc = iptc_init(table)) != NULL )
+                       {
+                               return r;
+                       }
+               }
+       }
+
+       fwd_free_ptr(r);
+       return NULL;
+}
+
+
+void fwd_xt_parse_proto(
+       struct fwd_xt_rule *r, struct fwd_proto *p, int inv
+) {
+       if( p != NULL )
+       {
+               switch(p->type)
+               {
+                       case FWD_PR_TCP:
+                               r->entry->ip.proto = 6;
+                               break;
+
+                       case FWD_PR_UDP:
+                               r->entry->ip.proto = 17;
+                               break;
+
+                       case FWD_PR_ICMP:
+                               r->entry->ip.proto = 1;
+                               break;
+
+                       case FWD_PR_CUSTOM:
+                               r->entry->ip.proto = p->proto;
+                               break;
+
+                       case FWD_PR_ALL:
+                       case FWD_PR_TCPUDP:
+                               r->entry->ip.proto = 0;
+                               break;
+               }
+
+               if( inv )
+                       r->entry->ip.invflags |= IPT_INV_PROTO;
+       }
+}
+
+void fwd_xt_parse_in(
+       struct fwd_xt_rule *r, struct fwd_network_list *n, int inv
+) {
+       if( n != NULL )
+       {
+               strncpy(r->entry->ip.iniface, n->ifname, IFNAMSIZ);
+
+               if( inv )
+                       r->entry->ip.invflags |= IPT_INV_VIA_IN;
+       }
+}
+
+void fwd_xt_parse_out(
+       struct fwd_xt_rule *r, struct fwd_network_list *n, int inv
+) {
+       if( n != NULL )
+       {
+               strncpy(r->entry->ip.outiface, n->ifname, IFNAMSIZ);
+
+               if( inv )
+                       r->entry->ip.invflags |= IPT_INV_VIA_OUT;
+       }
+}
+
+void fwd_xt_parse_src(
+       struct fwd_xt_rule *r, struct fwd_cidr *c, int inv
+) {
+       if( c != NULL )
+       {
+               r->entry->ip.src.s_addr  = c->addr.s_addr;
+               r->entry->ip.smsk.s_addr = htonl(~((1 << (32 - c->prefix)) - 1));
+
+               if( inv )
+                       r->entry->ip.invflags |= IPT_INV_SRCIP;
+       }
+}
+
+void fwd_xt_parse_dest(
+       struct fwd_xt_rule *r, struct fwd_cidr *c, int inv
+) {
+       if( c != NULL )
+       {
+               r->entry->ip.dst.s_addr  = c->addr.s_addr;
+               r->entry->ip.dmsk.s_addr = htonl(~((1 << (32 - c->prefix)) - 1));
+
+               if( inv )
+                       r->entry->ip.invflags |= IPT_INV_DSTIP;
+       }
+}
+
+
+struct xtables_match * fwd_xt_get_match(
+       struct fwd_xt_rule *r, const char *name
+) {
+       struct xtables_match *m = xtables_find_match(name, XTF_TRY_LOAD, &r->matches);
+       size_t s;
+
+       if( m != NULL )
+       {
+               s = IPT_ALIGN(sizeof(struct ipt_entry_match)) + m->size;
+
+               if(     (m->m = malloc(s)) != NULL )
+               {
+                       memset(m->m, 0, s);
+                       strcpy(m->m->u.user.name, m->name);
+                       m->m->u.match_size = s;
+
+                       if( m->init )
+                               m->init(m->m);
+
+                       return m;
+               }
+       }
+
+       return NULL;
+}
+
+void fwd_xt_parse_match(
+       struct fwd_xt_rule *r, struct xtables_match *m,
+       const char *opt, const char *val
+) {
+       char optcode;
+       const char *opts[3] = { "x", opt, val };
+
+       optind  = 0;
+       optcode = getopt_long(val ? 3 : 2, (char **)opts, "", m->extra_opts, NULL);
+
+       if( (optcode > -1) && (optcode != '?') )
+               m->parse(optcode, (char **)opts, 0, &m->mflags, r->entry, &m->m);
+}
+
+
+struct xtables_target * fwd_xt_get_target(
+       struct fwd_xt_rule *r, const char *name
+) {
+       struct xtables_target *t = xtables_find_target(name, XTF_TRY_LOAD);
+       size_t s;
+
+       if( !t )
+               t = xtables_find_target(IPT_STANDARD_TARGET, XTF_LOAD_MUST_SUCCEED);
+
+       if( t != NULL )
+       {
+               s = IPT_ALIGN(sizeof(struct ipt_entry_target)) + t->size;
+
+               if(     (t->t = malloc(s)) != NULL )
+               {
+                       memset(t->t, 0, s);
+                       strcpy(t->t->u.user.name, name);
+                       t->t->u.target_size = s;
+                       xtables_set_revision(t->t->u.user.name, t->revision);
+
+                       if( t->init )
+                               t->init(t->t);
+
+                       r->target = t;
+
+                       return t;
+               }
+       }
+
+       return NULL;
+}
+
+void fwd_xt_parse_target(
+       struct fwd_xt_rule *r, struct xtables_target *t,
+       const char *opt, const char *val
+) {
+       char optcode;
+       const char *opts[3] = { "x", opt, val };
+
+       optind  = 0;
+       optcode = getopt_long(val ? 3 : 2, (char **)opts, "", t->extra_opts, NULL);
+
+       if( (optcode > -1) && (optcode != '?') )
+               t->parse(optcode, (char **)opts, 0, &t->tflags, r->entry, &t->t);
+}
+
+int fwd_xt_exec_rule(struct fwd_xt_rule *r, const char *chain)
+{
+       size_t s;
+       struct xtables_rule_match *m, *next;
+       struct ipt_entry *e;
+       int rv = 0;
+
+       s = IPT_ALIGN(sizeof(struct ipt_entry));
+
+       for( m = r->matches; m; m = m->next )
+               s += m->match->m->u.match_size;
+
+       if( (e = malloc(s + r->target->t->u.target_size)) != NULL )
+       {
+               memset(e, 0, s + r->target->t->u.target_size);
+               memcpy(e, r->entry, sizeof(struct ipt_entry));
+
+               e->target_offset = s;
+               e->next_offset = s + r->target->t->u.target_size;
+
+               s = 0;
+
+               for( m = r->matches; m; m = m->next )
+               {
+                       memcpy(e->elems + s, m->match->m, m->match->m->u.match_size);
+                       s += m->match->m->u.match_size;
+               }
+
+               memcpy(e->elems + s, r->target->t, r->target->t->u.target_size);
+
+               if( (rv = iptc_append_entry(chain, e, r->iptc)) > 0 )
+                       iptc_commit(r->iptc);
+       }
+       else
+       {
+               errno = ENOMEM;
+       }
+
+
+       fwd_free_ptr(e);
+       fwd_free_ptr(r->entry);
+       fwd_free_ptr(r->target->t);
+
+       for( m = r->matches; m; )
+       {
+               next = m->next;
+               fwd_free_ptr(m->match->m);
+               fwd_free_ptr(m);
+               m = next;
+       }
+
+       iptc_free(r->iptc);
+       fwd_free_ptr(r);
+
+       return rv;
+}
+
diff --git a/contrib/fwd/src/fwd_xtables.h b/contrib/fwd/src/fwd_xtables.h
new file mode 100644 (file)
index 0000000..126746a
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * fwd - OpenWrt firewall daemon - libiptc/libxtables interface headers
+ *
+ *   Copyright (C) 2009 Jo-Philipp Wich <xm@subsignal.org>
+ *
+ * The fwd program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * The fwd program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with the fwd program. If not, see http://www.gnu.org/licenses/.
+ */
+
+
+#ifndef __FWD_XTABLES_H__
+#define __FWD_XTABLES_H__
+
+#include <iptables.h>
+#include <xtables.h>
+#include <libiptc/libxtc.h>
+
+#include <dlfcn.h>
+#include <errno.h>
+
+#include <sys/stat.h>
+#include <sys/utsname.h>
+
+
+
+struct fwd_xt_rule {
+       struct iptc_handle *iptc;
+       struct ipt_entry *entry;
+       struct xtables_rule_match *matches;
+       struct xtables_target *target;
+};
+
+
+/* Required by certain extensions like SNAT and DNAT */
+extern int kernel_version;
+extern void get_kernel_version(void);
+
+
+void fwd_xt_init(void);
+
+struct fwd_xt_rule * fwd_xt_init_rule(const char *table);
+
+void fwd_xt_parse_proto(struct fwd_xt_rule *r, struct fwd_proto *p, int inv);
+void fwd_xt_parse_in(struct fwd_xt_rule *r, struct fwd_network_list *n, int inv);
+void fwd_xt_parse_out(struct fwd_xt_rule *r, struct fwd_network_list *n, int inv);
+void fwd_xt_parse_src(struct fwd_xt_rule *r, struct fwd_cidr *c, int inv);
+void fwd_xt_parse_dest(struct fwd_xt_rule *r, struct fwd_cidr *c, int inv);
+
+struct xtables_match * fwd_xt_get_match(struct fwd_xt_rule *r, const char *name);
+void fwd_xt_parse_match(struct fwd_xt_rule *r, struct xtables_match *m, const char *opt, const char *val);
+
+struct xtables_target * fwd_xt_get_target(struct fwd_xt_rule *r, const char *name);
+void fwd_xt_parse_target(struct fwd_xt_rule *r, struct xtables_target *t, const char *opt, const char *val);
+
+int fwd_xt_exec_rule(struct fwd_xt_rule *r, const char *chain);
+
+#endif