Merge pull request #267 from n3ph/master
[project/luci.git] / contrib / fwd / src / fwd_xtables.c
index 3d057af..895715d 100644 (file)
@@ -19,6 +19,7 @@
 
 #include "fwd.h"
 #include "fwd_xtables.h"
+#include "fwd_utils.h"
 
 
 /* Required by certain extensions like SNAT and DNAT */
@@ -65,7 +66,7 @@ void fwd_xt_init(void)
 }
 
 
-struct fwd_xt_rule * fwd_xt_init_rule(const char *table)
+struct fwd_xt_rule * fwd_xt_init_rule(struct iptc_handle *h)
 {
        struct fwd_xt_rule *r;
 
@@ -73,10 +74,8 @@ struct fwd_xt_rule * fwd_xt_init_rule(const char *table)
        {
                if( (r->entry = fwd_alloc_ptr(struct ipt_entry)) != NULL )
                {
-                       if( (r->iptc = iptc_init(table)) != NULL )
-                       {
-                               return r;
-                       }
+                       r->iptc = h;
+                       return r;
                }
        }
 
@@ -84,6 +83,17 @@ struct fwd_xt_rule * fwd_xt_init_rule(const char *table)
        return NULL;
 }
 
+void fwd_xt_parse_frag(
+       struct fwd_xt_rule *r, int frag, int inv
+) {
+       if( frag )
+       {
+               r->entry->ip.flags |= IPT_F_FRAG;
+
+               if( inv )
+                       r->entry->ip.invflags |= IPT_INV_FRAG;
+       }
+}
 
 void fwd_xt_parse_proto(
        struct fwd_xt_rule *r, struct fwd_proto *p, int inv
@@ -120,7 +130,7 @@ void fwd_xt_parse_proto(
 }
 
 void fwd_xt_parse_in(
-       struct fwd_xt_rule *r, struct fwd_network_list *n, int inv
+       struct fwd_xt_rule *r, struct fwd_network *n, int inv
 ) {
        if( n != NULL )
        {
@@ -132,7 +142,7 @@ void fwd_xt_parse_in(
 }
 
 void fwd_xt_parse_out(
-       struct fwd_xt_rule *r, struct fwd_network_list *n, int inv
+       struct fwd_xt_rule *r, struct fwd_network *n, int inv
 ) {
        if( n != NULL )
        {
@@ -196,18 +206,46 @@ struct xtables_match * fwd_xt_get_match(
        return NULL;
 }
 
-void fwd_xt_parse_match(
-       struct fwd_xt_rule *r, struct xtables_match *m,
-       const char *opt, const char *val
+void __fwd_xt_parse_match(
+       struct fwd_xt_rule *r, struct xtables_match *m, ...
 ) {
-       char optcode;
-       const char *opts[3] = { "x", opt, val };
+       char optc;
+       char *s, **opts;
+       size_t len = 1;
+       int inv = 0;
+
+       va_list ap;
+       va_start(ap, m);
+
+       opts = malloc(len * sizeof(*opts));
+       opts[0] = "x";
+
+       while( (s = (char *)va_arg(ap, char *)) != NULL )
+       {
+               opts = realloc(opts, ++len * sizeof(*opts));
+               opts[len-1] = s;
+       }
+
+       va_end(ap);
+
+       if( len > 1 )
+       {
+               optind = 0;
 
-       optind  = 0;
-       optcode = getopt_long(val ? 3 : 2, (char **)opts, "", m->extra_opts, NULL);
+               while( (optc = getopt_long(len, opts, "", m->extra_opts, NULL)) > -1 )
+               {
+                       if( (optc == '?') && (optarg[0] == '!') && (optarg[1] == '\0') )
+                       {
+                               inv = 1;
+                               continue;
+                       }
 
-       if( (optcode > -1) && (optcode != '?') )
-               m->parse(optcode, (char **)opts, 0, &m->mflags, r->entry, &m->m);
+                       m->parse(optc, opts, inv, &m->mflags, r->entry, &m->m);
+                       inv = 0;
+               }
+       }
+
+       free(opts);
 }
 
 
@@ -243,24 +281,55 @@ struct xtables_target * fwd_xt_get_target(
        return NULL;
 }
 
-void fwd_xt_parse_target(
-       struct fwd_xt_rule *r, struct xtables_target *t,
-       const char *opt, const char *val
+void __fwd_xt_parse_target(
+       struct fwd_xt_rule *r, struct xtables_target *t, ...
 ) {
-       char optcode;
-       const char *opts[3] = { "x", opt, val };
+       char optc;
+       char *s, **opts;
+       size_t len = 1;
+       int inv = 0;
 
-       optind  = 0;
-       optcode = getopt_long(val ? 3 : 2, (char **)opts, "", t->extra_opts, NULL);
+       va_list ap;
+       va_start(ap, t);
+
+       opts = malloc(len * sizeof(*opts));
+       opts[0] = "x";
 
-       if( (optcode > -1) && (optcode != '?') )
-               t->parse(optcode, (char **)opts, 0, &t->tflags, r->entry, &t->t);
+       while( (s = (char *)va_arg(ap, char *)) != NULL )
+       {
+               opts = realloc(opts, ++len * sizeof(*opts));
+               opts[len-1] = s;
+       }
+
+       va_end(ap);
+
+       if( len > 1 )
+       {
+               optind = 0;
+
+               while( (optc = getopt_long(len, opts, "", t->extra_opts, NULL)) > -1 )
+               {
+                       if( (optc == '?') && (optarg[0] == '!') && (optarg[1] == '\0') )
+                       {
+                               inv = 1;
+                               continue;
+                       }
+
+                       t->parse(optc, opts, inv, &t->tflags, r->entry, &t->t);
+                       inv = 0;
+               }
+       }
+
+       free(opts);
 }
 
-int fwd_xt_exec_rule(struct fwd_xt_rule *r, const char *chain)
+
+static int fwd_xt_exec_rule(struct fwd_xt_rule *r, const char *chain, int pos)
 {
        size_t s;
        struct xtables_rule_match *m, *next;
+       struct xtables_match *em;
+       struct xtables_target *et;
        struct ipt_entry *e;
        int rv = 0;
 
@@ -287,8 +356,10 @@ int fwd_xt_exec_rule(struct fwd_xt_rule *r, const char *chain)
 
                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);
+               rv = (pos > -1)
+                       ? iptc_insert_entry(chain, e, (unsigned int) pos, r->iptc)
+                       : iptc_append_entry(chain, e, r->iptc)
+               ;
        }
        else
        {
@@ -304,13 +375,38 @@ int fwd_xt_exec_rule(struct fwd_xt_rule *r, const char *chain)
        {
                next = m->next;
                fwd_free_ptr(m->match->m);
+
+               if( m->match == m->match->next )
+                       fwd_free_ptr(m->match);
+
                fwd_free_ptr(m);
                m = next;
        }
 
-       iptc_free(r->iptc);
        fwd_free_ptr(r);
 
+       /* reset all targets and matches */
+       for (em = xtables_matches; em; em = em->next)
+               em->mflags = 0;
+
+       for (et = xtables_targets; et; et = et->next)
+       {
+               et->tflags = 0;
+               et->used = 0;
+       }
+
        return rv;
 }
 
+int fwd_xt_insert_rule(
+       struct fwd_xt_rule *r, const char *chain, unsigned int pos
+) {
+       return fwd_xt_exec_rule(r, chain, pos);
+}
+
+int fwd_xt_append_rule(
+       struct fwd_xt_rule *r, const char *chain
+) {
+       return fwd_xt_exec_rule(r, chain, -1);
+}
+