]> git.ipfire.org Git - thirdparty/iptables.git/commitdiff
ebtables-compat: add watchers support
authorArturo Borrero <arturo.borrero.glez@gmail.com>
Mon, 9 Feb 2015 12:16:12 +0000 (13:16 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Wed, 11 Feb 2015 00:23:23 +0000 (01:23 +0100)
ebtables watchers are targets which always return EBT_CONTINUE.

Signed-off-by: Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
iptables/nft-bridge.c
iptables/nft-bridge.h
iptables/nft-shared.c
iptables/nft-shared.h
iptables/xtables-eb.c

index 62aab0419dbc3f337d993e61c83ffac6ec863c8e..e3ab667fa8ccbeccbe92beb9ddd1611116a0b688 100644 (file)
 #include "nft-bridge.h"
 #include "nft.h"
 
+void ebt_cs_clean(struct ebtables_command_state *cs)
+{
+       struct ebt_match *m, *nm;
+
+       xtables_rule_matches_free(&cs->matches);
+
+       for (m = cs->match_list; m;) {
+               nm = m->next;
+               if (!m->ismatch)
+                       free(m->u.watcher->t);
+               free(m);
+               m = nm;
+       }
+}
+
 /* 0: default, print only 2 digits if necessary
  * 2: always print 2 digits, a printed mac address
  * then always has the same length
@@ -139,7 +154,7 @@ static int _add_action(struct nft_rule *r, struct ebtables_command_state *cs)
 static int nft_bridge_add(struct nft_rule *r, void *data)
 {
        struct ebtables_command_state *cs = data;
-       struct xtables_rule_match *matchp;
+       struct ebt_match *iter;
        struct ebt_entry *fw = &cs->fw;
        uint32_t op;
        char *addr;
@@ -189,9 +204,14 @@ static int nft_bridge_add(struct nft_rule *r, void *data)
 
        add_compat(r, fw->ethproto, fw->invflags);
 
-       for (matchp = cs->matches; matchp; matchp = matchp->next) {
-               if (add_match(r, matchp->match->m) < 0)
-                       break;
+       for (iter = cs->match_list; iter; iter = iter->next) {
+               if (iter->ismatch) {
+                       if (add_match(r, iter->u.match->m))
+                               break;
+               } else {
+                       if (add_target(r, iter->u.watcher->t))
+                               break;
+               }
        }
 
        if (add_counters(r, cs->counters.pcnt, cs->counters.bcnt) < 0)
@@ -296,10 +316,44 @@ static void nft_bridge_parse_immediate(const char *jumpto, bool nft_goto,
        cs->jumpto = jumpto;
 }
 
+static void parse_watcher(void *object, struct ebt_match **match_list,
+                         bool ismatch)
+{
+       struct ebt_match *m;
+
+       m = calloc(1, sizeof(struct ebt_match));
+       if (m == NULL)
+               xtables_error(OTHER_PROBLEM, "Can't allocate memory");
+
+       if (ismatch)
+               m->u.match = object;
+       else
+               m->u.watcher = object;
+
+       m->ismatch = ismatch;
+       if (*match_list == NULL)
+               *match_list = m;
+       else
+               (*match_list)->next = m;
+}
+
+static void nft_bridge_parse_match(struct xtables_match *m, void *data)
+{
+       struct ebtables_command_state *cs = data;
+
+       parse_watcher(m, &cs->match_list, true);
+}
+
 static void nft_bridge_parse_target(struct xtables_target *t, void *data)
 {
        struct ebtables_command_state *cs = data;
 
+       /* harcoded names :-( */
+       if (strcmp(t->name, "log") == 0) {
+               parse_watcher(t, &cs->match_list, false);
+               return;
+       }
+
        cs->target = t;
 }
 
@@ -382,7 +436,9 @@ static void nft_bridge_print_header(unsigned int format, const char *chain,
 static void nft_bridge_print_firewall(struct nft_rule *r, unsigned int num,
                                      unsigned int format)
 {
-       struct xtables_rule_match *matchp;
+       struct xtables_match *matchp;
+       struct xtables_target *watcherp;
+       struct ebt_match *m;
        struct ebtables_command_state cs = {};
        char *addr;
 
@@ -456,10 +512,19 @@ static void nft_bridge_print_firewall(struct nft_rule *r, unsigned int num,
                print_iface(cs.fw.out);
        }
 
-       for (matchp = cs.matches; matchp; matchp = matchp->next) {
-               if (matchp->match->print != NULL) {
-                       matchp->match->print(&cs.fw, matchp->match->m,
-                                            format & FMT_NUMERIC);
+       for (m = cs.match_list; m; m = m->next) {
+               if (m->ismatch) {
+                       matchp = m->u.match;
+                       if (matchp->print != NULL) {
+                               matchp->print(&cs.fw, matchp->m,
+                                             format & FMT_NUMERIC);
+                       }
+               } else {
+                       watcherp = m->u.watcher;
+                       if (watcherp->print != NULL) {
+                               watcherp->print(&cs.fw, watcherp->t,
+                                               format & FMT_NUMERIC);
+                       }
                }
        }
 
@@ -476,6 +541,8 @@ static void nft_bridge_print_firewall(struct nft_rule *r, unsigned int num,
 
        if (!(format & FMT_NONEWLINE))
                fputc('\n', stdout);
+
+       ebt_cs_clean(&cs);
 }
 
 static bool nft_bridge_is_same(const void *data_a, const void *data_b)
@@ -567,6 +634,7 @@ struct nft_family_ops nft_family_ops_bridge = {
        .parse_meta             = nft_bridge_parse_meta,
        .parse_payload          = nft_bridge_parse_payload,
        .parse_immediate        = nft_bridge_parse_immediate,
+       .parse_match            = nft_bridge_parse_match,
        .parse_target           = nft_bridge_parse_target,
        .print_table_header     = nft_bridge_print_table_header,
        .print_header           = nft_bridge_print_header,
index cd63c11a17e5c364518828668e1dc3ab52ea303d..1c4a96ea821aba799c5341a916810c203dd5f8c2 100644 (file)
@@ -93,10 +93,21 @@ struct ebt_entry {
        unsigned char out_mask[IFNAMSIZ];
 };
 
+/* trick for ebtables-compat, since watchers are targets */
+struct ebt_match {
+       struct ebt_match                                *next;
+       union {
+               struct xtables_match            *match;
+               struct xtables_target           *watcher;
+       } u;
+       bool                                    ismatch;
+};
+
 struct ebtables_command_state {
        struct ebt_entry fw;
        struct xtables_target *target;
        struct xtables_rule_match *matches;
+       struct ebt_match *match_list;
        const char *jumpto;
        struct xt_counters counters;
        int invert;
@@ -155,4 +166,6 @@ static inline const char *ebt_target_name(unsigned int verdict)
        *flags |= mask;                                         \
 })                                                             \
 
+void ebt_cs_clean(struct ebtables_command_state *cs);
+
 #endif
index 76984e818843b3dc327b2bb27ff508277d0c4529..620da3e77b39ba3437c26259c824d46c02fc50cc 100644 (file)
@@ -328,6 +328,7 @@ void nft_parse_match(struct nft_xt_ctx *ctx, struct nft_rule_expr *e)
        struct xtables_match *match;
        struct xtables_rule_match **matches;
        struct xt_entry_match *m;
+       struct nft_family_ops *ops;
 
        switch (ctx->family) {
        case NFPROTO_IPV4:
@@ -359,6 +360,10 @@ void nft_parse_match(struct nft_xt_ctx *ctx, struct nft_rule_expr *e)
        strcpy(m->u.user.name, match->name);
 
        match->m = m;
+
+       ops = nft_family_ops_lookup(ctx->family);
+       if (ops->parse_match != NULL)
+               ops->parse_match(match, nft_get_data(ctx));
 }
 
 void print_proto(uint16_t proto, int invert)
index 33582aaa150d70c30269a21324c4eb2a45319b5e..fbce5b5d5b244e2ca2cad5c83c9ece9b18ce13f6 100644 (file)
@@ -97,6 +97,7 @@ struct nft_family_ops {
                            struct xtables_args *args);
        void (*post_parse)(int command, struct iptables_command_state *cs,
                           struct xtables_args *args);
+       void (*parse_match)(struct xtables_match *m, void *data);
        void (*parse_target)(struct xtables_target *t, void *data);
        bool (*rule_find)(struct nft_family_ops *ops, struct nft_rule *r,
                          void *data);
index db1717c9da6adc414dce6b77ce155599830e682c..efbb3cd0ddbdc3743a44fb86ad32014b4c63d9bd 100644 (file)
@@ -610,19 +610,49 @@ static void ebt_load_match(const char *name)
                xtables_error(OTHER_PROBLEM, "Can't alloc memory");
 }
 
-static void ebt_load_matches(void)
+static void ebt_load_watcher(const char *name)
+{
+       struct xtables_target *watcher;
+       size_t size;
+
+       watcher = xtables_find_target(name, XTF_LOAD_MUST_SUCCEED);
+       if (!watcher)
+               xtables_error(OTHER_PROBLEM,
+                             "Unable to load %s watcher", name);
+
+       size = XT_ALIGN(sizeof(struct xt_entry_target)) + watcher->size;
+
+       watcher->t = xtables_calloc(1, size);
+       watcher->t->u.target_size = size;
+       strncpy(watcher->t->u.user.name, name,
+               sizeof(watcher->t->u.user.name));
+       watcher->t->u.user.name[sizeof(watcher->t->u.user.name)-1] = '\0';
+       watcher->t->u.user.revision = watcher->revision;
+
+       xs_init_target(watcher);
+
+       opts = merge_options(opts, watcher->extra_opts,
+                            &watcher->option_offset);
+       if (opts == NULL)
+               xtables_error(OTHER_PROBLEM, "Can't alloc memory");
+}
+
+static void ebt_load_match_extensions(void)
 {
        opts = ebt_original_options;
        ebt_load_match("802_3");
        ebt_load_match("ip");
        ebt_load_match("mark_m");
+
+       ebt_load_watcher("log");
 }
 
 static void ebt_add_match(struct xtables_match *m,
-                         struct xtables_rule_match **rule_matches)
+                         struct ebtables_command_state *cs)
 {
-       struct xtables_rule_match *i;
+       struct xtables_rule_match *i, **rule_matches = &cs->matches;
        struct xtables_match *newm;
+       struct ebt_match *newnode;
 
        /* match already in rule_matches, skip inclusion */
        for (i = *rule_matches; i; i = i->next) {
@@ -638,6 +668,45 @@ static void ebt_add_match(struct xtables_match *m,
                              "Unable to add match %s", m->name);
 
        newm->mflags = m->mflags;
+
+       /* glue code for watchers */
+       newnode = calloc(1, sizeof(struct ebt_match));
+       if (newnode == NULL)
+               xtables_error(OTHER_PROBLEM, "Unable to alloc memory");
+
+       newnode->ismatch = true;
+       newnode->u.match = newm;
+
+       if (cs->match_list == NULL)
+               cs->match_list = newnode;
+       else
+               cs->match_list->next = newnode;
+}
+
+static void ebt_add_watcher(struct xtables_target *watcher,
+                           struct ebtables_command_state *cs)
+{
+       struct ebt_match *i, *newnode;
+
+       for (i = cs->match_list; i; i = i->next) {
+               if (i->ismatch)
+                       continue;
+               if (strcmp(i->u.watcher->name, watcher->name) == 0) {
+                       i->u.watcher->tflags |= watcher->tflags;
+                       return;
+               }
+       }
+
+       newnode = calloc(1, sizeof(struct ebt_match));
+       if (newnode == NULL)
+               xtables_error(OTHER_PROBLEM, "Unable to alloc memory");
+
+       newnode->u.watcher = watcher;
+
+       if (cs->match_list == NULL)
+               cs->match_list = newnode;
+       else
+               cs->match_list->next = newnode;
 }
 
 /* We use exec_style instead of #ifdef's because ebtables.so is a shared object. */
@@ -651,7 +720,7 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table)
        int rule_nr_end = 0;
        int ret = 0;
        unsigned int flags = 0;
-       struct xtables_target *t;
+       struct xtables_target *t, *w;
        struct xtables_match *m;
        struct ebtables_command_state cs;
        char command = 'h';
@@ -660,6 +729,7 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table)
        int exec_style = EXEC_STYLE_PRG;
        int selected_chain = -1;
        struct xtables_rule_match *xtrm_i;
+       struct ebt_match *match;
 
        memset(&cs, 0, sizeof(cs));
        cs.argv = argv;
@@ -676,7 +746,7 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table)
         * don't use '-m matchname' and the match can't loaded dinamically when
         * the user calls it.
         */
-       ebt_load_matches();
+       ebt_load_match_extensions();
 
        /* clear mflags in case do_commandeb gets called a second time
         * (we clear the global list of all matches for security)*/
@@ -1164,16 +1234,21 @@ big_iface_length:
                        /* Is it a match_option? */
                        for (m = xtables_matches; m; m = m->next) {
                                if (m->parse(c - m->option_offset, argv, ebt_invert, &m->mflags, NULL, &m->m)) {
-                                       ebt_add_match(m, &cs.matches);
+                                       ebt_add_match(m, &cs);
                                        goto check_extension;
                                }
                        }
 
                        /* Is it a watcher option? */
-                       /*for (w = ebt_watchers; w; w = w->next)
-                               if (w->parse(c - w->option_offset, argv, argc, new_entry, &w->flags, &w->w))
-                                       break;
-
+                       for (w = xtables_targets; w; w = w->next) {
+                               if (w->parse(c - w->option_offset, argv,
+                                            ebt_invert, &w->tflags,
+                                            NULL, &w->t)) {
+                                       ebt_add_watcher(w, &cs);
+                                       goto check_extension;
+                               }
+                       }
+                       /*
                        if (w == NULL && c == '?')
                                ebt_print_error2("Unknown argument: '%s'", argv[optind - 1], (char)optopt, (char)c);
                        else if (w == NULL) {
@@ -1216,6 +1291,13 @@ check_extension:
                for (xtrm_i = cs.matches; xtrm_i; xtrm_i = xtrm_i->next)
                        xtables_option_mfcall(xtrm_i->match);
 
+               for (match = cs.match_list; match; match = match->next) {
+                       if (match->ismatch)
+                               continue;
+
+                       xtables_option_tfcall(match->u.watcher);
+               }
+
                if (cs.target != NULL)
                        xtables_option_tfcall(cs.target);
        }
@@ -1278,5 +1360,7 @@ check_extension:
 
                if (replace->nentries)
                        ebt_deliver_counters(replace);*/
+
+       ebt_cs_clean(&cs);
        return ret;
 }