]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
src: add/create/delete stateful objects
authorPablo Neira Ayuso <pablo@netfilter.org>
Sun, 27 Nov 2016 22:34:53 +0000 (23:34 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Tue, 3 Jan 2017 13:21:53 +0000 (14:21 +0100)
This patch allows you to add and to delete objects, eg.

 # nft add quota filter test 1234567 bytes
 # nft list quotas
 table ip filter {
        quota test {
                 1234567 bytes
        }

 }
 # nft delete quota filter test

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
include/mnl.h
include/netlink.h
include/rule.h
src/evaluate.c
src/mnl.c
src/netlink.c
src/parser_bison.y
src/rule.c

index ad036aefabbd8bbf29b25d1c7f05f2928e1e8d40..d178bd27a75a7992da59501558cf035b7c074f64 100644 (file)
@@ -88,6 +88,11 @@ int mnl_nft_setelem_get(struct mnl_socket *nf_sock, struct nftnl_set *nls);
 
 struct nftnl_obj_list *mnl_nft_obj_dump(struct mnl_socket *nf_sock, int family,
                                        const char *table);
+int mnl_nft_obj_batch_add(struct nftnl_obj *nln, unsigned int flags,
+                         uint32_t seqnum);
+int mnl_nft_obj_batch_del(struct nftnl_obj *nln, unsigned int flags,
+                         uint32_t seqnum);
+
 struct nftnl_ruleset *mnl_nft_ruleset_dump(struct mnl_socket *nf_sock,
                                         uint32_t family);
 int mnl_nft_event_listener(struct mnl_socket *nf_sock,
index ce577871761f51feeba794aea189b97eccdf53ca..841211c43760ca1049d11e71a7b0a051048765bc 100644 (file)
@@ -171,12 +171,17 @@ extern int netlink_flush_setelems(struct netlink_ctx *ctx, const struct handle *
 
 extern int netlink_list_objs(struct netlink_ctx *ctx, const struct handle *h,
                               const struct location *loc);
+extern int netlink_add_obj(struct netlink_ctx *ctx, const struct handle *h,
+                          struct obj *obj, bool excl);
+extern int netlink_delete_obj(struct netlink_ctx *ctx, const struct handle *h,
+                             struct location *loc, enum stmt_types type);
 
 extern void netlink_dump_table(const struct nftnl_table *nlt);
 extern void netlink_dump_chain(const struct nftnl_chain *nlc);
 extern void netlink_dump_rule(const struct nftnl_rule *nlr);
 extern void netlink_dump_expr(const struct nftnl_expr *nle);
 extern void netlink_dump_set(const struct nftnl_set *nls);
+extern void netlink_dump_obj(struct nftnl_obj *nlo);
 
 extern int netlink_batch_send(struct list_head *err_list);
 
index e0f891393276996243c7cbcecb79c3a375ebe2e8..88acbcc7b1633e076d71e665ea89bdc43694eceb 100644 (file)
@@ -282,7 +282,7 @@ struct obj *obj_alloc(const struct location *loc);
 void obj_free(struct obj *obj);
 void obj_add_hash(struct obj *obj, struct table *table);
 void obj_print(const struct obj *n);
-const char *obj_type_name(enum stmt_types type);
+const char *obj_type_name(uint32_t type);
 
 /**
  * enum cmd_ops - command operations
@@ -415,6 +415,7 @@ struct cmd {
                struct table    *table;
                struct monitor  *monitor;
                struct export   *export;
+               struct obj      *object;
        };
        const void              *arg;
 };
index b3630c303920ef3c9612f4d3495960fd0e2a372e..9bc3b7d6477aafde5bf3e44756b04884d90c74f7 100644 (file)
@@ -2758,6 +2758,9 @@ static int cmd_evaluate_add(struct eval_ctx *ctx, struct cmd *cmd)
                return chain_evaluate(ctx, cmd->chain);
        case CMD_OBJ_TABLE:
                return table_evaluate(ctx, cmd->table);
+       case CMD_OBJ_COUNTER:
+       case CMD_OBJ_QUOTA:
+               return 0;
        default:
                BUG("invalid command object type %u\n", cmd->obj);
        }
@@ -2778,6 +2781,8 @@ static int cmd_evaluate_delete(struct eval_ctx *ctx, struct cmd *cmd)
        case CMD_OBJ_RULE:
        case CMD_OBJ_CHAIN:
        case CMD_OBJ_TABLE:
+       case CMD_OBJ_COUNTER:
+       case CMD_OBJ_QUOTA:
                return 0;
        default:
                BUG("invalid command object type %u\n", cmd->obj);
index 534d02f4ff32b2fcde6a55d176d7177369664aa1..9458e21bf8b437db6599ef5b197ce59c2f0ee61f 100644 (file)
--- a/src/mnl.c
+++ b/src/mnl.c
@@ -796,6 +796,36 @@ err:
        return NULL;
 }
 
+int mnl_nft_obj_batch_add(struct nftnl_obj *nln, unsigned int flags,
+                         uint32_t seqnum)
+{
+       struct nlmsghdr *nlh;
+
+       nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(batch),
+                       NFT_MSG_NEWOBJ,
+                       nftnl_obj_get_u32(nln, NFTNL_OBJ_FAMILY),
+                       NLM_F_CREATE | flags, seqnum);
+       nftnl_obj_nlmsg_build_payload(nlh, nln);
+       mnl_nft_batch_continue();
+
+       return 0;
+}
+
+int mnl_nft_obj_batch_del(struct nftnl_obj *nln, unsigned int flags,
+                         uint32_t seqnum)
+{
+       struct nlmsghdr *nlh;
+
+       nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(batch),
+                       NFT_MSG_DELOBJ,
+                       nftnl_obj_get_u32(nln, NFTNL_OBJ_FAMILY),
+                       flags, seqnum);
+       nftnl_obj_nlmsg_build_payload(nlh, nln);
+       mnl_nft_batch_continue();
+
+       return 0;
+}
+
 static int obj_cb(const struct nlmsghdr *nlh, void *data)
 {
        struct nftnl_obj_list *nln_list = data;
index bbf675f90def3d9654d13ae62dcd34a9f1f03412..d11b3c01f2645a1bb577e941975d104208c4ac1b 100644 (file)
@@ -21,6 +21,7 @@
 #include <libnftnl/trace.h>
 #include <libnftnl/chain.h>
 #include <libnftnl/expr.h>
+#include <libnftnl/object.h>
 #include <libnftnl/set.h>
 #include <libnftnl/udata.h>
 #include <libnftnl/common.h>
@@ -270,6 +271,51 @@ static struct nftnl_set_elem *alloc_nftnl_setelem(const struct expr *expr)
        return nlse;
 }
 
+static struct nftnl_obj *
+__alloc_nftnl_obj(const struct handle *h, uint32_t type)
+{
+       struct nftnl_obj *nlo;
+
+       nlo = nftnl_obj_alloc();
+       if (nlo == NULL)
+               memory_allocation_error();
+
+       nftnl_obj_set_u32(nlo, NFTNL_OBJ_FAMILY, h->family);
+       nftnl_obj_set_str(nlo, NFTNL_OBJ_TABLE, h->table);
+       if (h->obj != NULL)
+               nftnl_obj_set_str(nlo, NFTNL_OBJ_NAME, h->obj);
+
+       nftnl_obj_set_u32(nlo, NFTNL_OBJ_TYPE, type);
+
+       return nlo;
+}
+
+static struct nftnl_obj *
+alloc_nftnl_obj(const struct handle *h, struct obj *obj)
+{
+       struct nftnl_obj *nlo;
+
+       nlo = __alloc_nftnl_obj(h, obj->type);
+
+       switch (obj->type) {
+       case NFT_OBJECT_COUNTER:
+               nftnl_obj_set_u64(nlo, NFTNL_OBJ_CTR_PKTS,
+                                 obj->counter.packets);
+               nftnl_obj_set_u64(nlo, NFTNL_OBJ_CTR_BYTES,
+                                 obj->counter.bytes);
+               break;
+       case NFT_OBJECT_QUOTA:
+               nftnl_obj_set_u64(nlo, NFTNL_OBJ_QUOTA_BYTES,
+                                 obj->quota.bytes);
+               nftnl_obj_set_u64(nlo, NFTNL_OBJ_QUOTA_CONSUMED,
+                                 obj->quota.used);
+               nftnl_obj_set_u32(nlo, NFTNL_OBJ_QUOTA_FLAGS,
+                                 obj->quota.flags);
+               break;
+       }
+       return nlo;
+}
+
 void netlink_gen_raw_data(const mpz_t value, enum byteorder byteorder,
                          unsigned int len, struct nft_data_linearize *data)
 {
@@ -1608,6 +1654,55 @@ out:
        return err;
 }
 
+void netlink_dump_obj(struct nftnl_obj *nln)
+{
+#ifdef DEBUG
+       char buf[4096];
+
+       if (!(debug_level & DEBUG_NETLINK))
+               return;
+
+       nftnl_obj_snprintf(buf, sizeof(buf), nln, 0, 0);
+       fprintf(stdout, "%s\n", buf);
+#endif
+}
+
+int netlink_add_obj(struct netlink_ctx *ctx, const struct handle *h,
+                   struct obj *obj, bool excl)
+{
+       struct nftnl_obj *nlo;
+       int err;
+
+       nlo = alloc_nftnl_obj(h, obj);
+       netlink_dump_obj(nlo);
+
+       err = mnl_nft_obj_batch_add(nlo, excl ? NLM_F_EXCL : 0, ctx->seqnum);
+       if (err < 0)
+               netlink_io_error(ctx, &obj->location, "Could not add %s: %s",
+                                obj_type_name(obj->type), strerror(errno));
+       nftnl_obj_free(nlo);
+
+       return err;
+}
+
+int netlink_delete_obj(struct netlink_ctx *ctx, const struct handle *h,
+                      struct location *loc, uint32_t type)
+{
+       struct nftnl_obj *nlo;
+       int err;
+
+       nlo = __alloc_nftnl_obj(h, type);
+       netlink_dump_obj(nlo);
+
+       err = mnl_nft_obj_batch_del(nlo, 0, ctx->seqnum);
+       if (err < 0)
+               netlink_io_error(ctx, loc, "Could not delete %s: %s",
+                                obj_type_name(type), strerror(errno));
+       nftnl_obj_free(nlo);
+
+       return err;
+}
+
 static struct obj *netlink_delinearize_obj(struct netlink_ctx *ctx,
                                           struct nftnl_obj *nlo)
 {
index 2213f3808db439a9ec50ceee098cee6c44339dbc..fd3f0d8251a67caca9a0ee1e28d853e18585d003 100644 (file)
@@ -133,6 +133,9 @@ static void location_update(struct location *loc, struct location *rhs, int n)
        struct stmt             *stmt;
        struct expr             *expr;
        struct set              *set;
+       struct obj              *obj;
+       struct counter          *counter;
+       struct quota            *quota;
        const struct datatype   *datatype;
        struct handle_spec      handle_spec;
        struct position_spec    position_spec;
@@ -444,8 +447,8 @@ static void location_update(struct location *loc, struct location *rhs, int n)
 
 %type <handle>                 table_spec chain_spec chain_identifier ruleid_spec handle_spec position_spec rule_position ruleset_spec
 %destructor { handle_free(&$$); } table_spec chain_spec chain_identifier ruleid_spec handle_spec position_spec rule_position ruleset_spec
-%type <handle>                 set_spec set_identifier obj_spec
-%destructor { handle_free(&$$); } set_spec set_identifier obj_spec
+%type <handle>                 set_spec set_identifier obj_spec obj_identifier
+%destructor { handle_free(&$$); } set_spec set_identifier obj_spec obj_identifier
 %type <val>                    family_spec family_spec_explicit chain_policy prio_spec
 
 %type <string>                 dev_spec quota_unit
@@ -468,6 +471,9 @@ static void location_update(struct location *loc, struct location *rhs, int n)
 %type <set>                    map_block_alloc map_block
 %destructor { set_free($$); }  map_block_alloc
 
+%type <obj>                    obj_block_alloc counter_block quota_block
+%destructor { obj_free($$); }  obj_block_alloc
+
 %type <list>                   stmt_list
 %destructor { stmt_list_free($$); xfree($$); } stmt_list
 %type <stmt>                   stmt match_stmt verdict_stmt
@@ -553,6 +559,8 @@ static void location_update(struct location *loc, struct location *rhs, int n)
 %type <expr>                   and_rhs_expr exclusive_or_rhs_expr inclusive_or_rhs_expr
 %destructor { expr_free($$); } and_rhs_expr exclusive_or_rhs_expr inclusive_or_rhs_expr
 
+%type <obj>                    counter_obj quota_obj
+%destructor { obj_free($$); }  counter_obj quota_obj
 
 %type <expr>                   relational_expr
 %destructor { expr_free($$); } relational_expr
@@ -616,6 +624,11 @@ static void location_update(struct location *loc, struct location *rhs, int n)
 %destructor { xfree($$); }     monitor_event
 %type <val>                    monitor_object  monitor_format
 
+%type <counter>                        counter_config
+%destructor { xfree($$); }     counter_config
+%type <quota>                  quota_config
+%destructor { xfree($$); }     quota_config
+
 %%
 
 input                  :       /* empty */
@@ -768,6 +781,23 @@ add_cmd                    :       TABLE           table_spec
                        {
                                $$ = cmd_alloc(CMD_ADD, CMD_OBJ_SETELEM, &$2, &@$, $3);
                        }
+                       |       COUNTER         obj_spec
+                       {
+                               struct obj *obj;
+
+                               obj = obj_alloc(&@$);
+                               obj->type = NFT_OBJECT_COUNTER;
+                               handle_merge(&obj->handle, &$2);
+                               $$ = cmd_alloc(CMD_ADD, CMD_OBJ_COUNTER, &$2, &@$, obj);
+                       }
+                       |       COUNTER         obj_spec        counter_obj
+                       {
+                               $$ = cmd_alloc(CMD_ADD, CMD_OBJ_COUNTER, &$2, &@$, $3);
+                       }
+                       |       QUOTA           obj_spec        quota_obj
+                       {
+                               $$ = cmd_alloc(CMD_ADD, CMD_OBJ_QUOTA, &$2, &@$, $3);
+                       }
                        ;
 
 replace_cmd            :       RULE            ruleid_spec     rule
@@ -817,6 +847,23 @@ create_cmd         :       TABLE           table_spec
                        {
                                $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_SETELEM, &$2, &@$, $3);
                        }
+                       |       COUNTER         obj_spec
+                       {
+                               struct obj *obj;
+
+                               obj = obj_alloc(&@$);
+                               obj->type = NFT_OBJECT_COUNTER;
+                               handle_merge(&obj->handle, &$2);
+                               $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_COUNTER, &$2, &@$, obj);
+                       }
+                       |       COUNTER         obj_spec        counter_obj
+                       {
+                               $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_COUNTER, &$2, &@$, $3);
+                       }
+                       |       QUOTA           obj_spec        quota_obj
+                       {
+                               $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_QUOTA, &$2, &@$, $3);
+                       }
                        ;
 
 insert_cmd             :       RULE            rule_position   rule
@@ -849,6 +896,14 @@ delete_cmd         :       TABLE           table_spec
                        {
                                $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_SETELEM, &$2, &@$, $3);
                        }
+                       |       COUNTER         obj_spec
+                       {
+                               $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_COUNTER, &$2, &@$, NULL);
+                       }
+                       |       QUOTA           obj_spec
+                       {
+                               $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_QUOTA, &$2, &@$, NULL);
+                       }
                        ;
 
 list_cmd               :       TABLE           table_spec
@@ -1043,6 +1098,28 @@ table_block              :       /* empty */     { $$ = $<table>-1; }
                                list_add_tail(&$4->list, &$1->sets);
                                $$ = $1;
                        }
+                       |       table_block     COUNTER         obj_identifier
+                                       obj_block_alloc '{'     counter_block   '}'
+                                       stmt_seperator
+                       {
+                               $4->location = @3;
+                               $4->type = NFT_OBJECT_COUNTER;
+                               handle_merge(&$4->handle, &$3);
+                               handle_free(&$3);
+                               list_add_tail(&$4->list, &$1->objs);
+                               $$ = $1;
+                       }
+                       |       table_block     QUOTA           obj_identifier
+                                       obj_block_alloc '{'     quota_block     '}'
+                                       stmt_seperator
+                       {
+                               $4->location = @3;
+                               $4->type = NFT_OBJECT_QUOTA;
+                               handle_merge(&$4->handle, &$3);
+                               handle_free(&$3);
+                               list_add_tail(&$4->list, &$1->objs);
+                               $$ = $1;
+                       }
                        ;
 
 chain_block_alloc      :       /* empty */
@@ -1193,6 +1270,32 @@ type_identifier_list     :       type_identifier
                        }
                        ;
 
+obj_block_alloc                :       /* empty */
+                       {
+                               $$ = obj_alloc(NULL);
+                       }
+                       ;
+
+counter_block          :       /* empty */     { $$ = $<obj>-1; }
+                       |       counter_block     common_block
+                       |       counter_block     stmt_seperator
+                       |       counter_block     counter_config
+                       {
+                               $1->counter = *$2;
+                               $$ = $1;
+                       }
+                       ;
+
+quota_block            :       /* empty */     { $$ = $<obj>-1; }
+                       |       quota_block     common_block
+                       |       quota_block     stmt_seperator
+                       |       quota_block     quota_config
+                       {
+                               $1->quota = *$2;
+                               $$ = $1;
+                       }
+                       ;
+
 type_identifier                :       STRING  { $$ = $1; }
                        |       MARK    { $$ = xstrdup("mark"); }
                        |       DSCP    { $$ = xstrdup("dscp"); }
@@ -1325,6 +1428,13 @@ obj_spec         :       table_spec      identifier
                        }
                        ;
 
+obj_identifier         :       identifier
+                       {
+                               memset(&$$, 0, sizeof($$));
+                               $$.obj          = $1;
+                       }
+                       ;
+
 handle_spec            :       HANDLE          NUM
                        {
                                memset(&$$, 0, sizeof($$));
@@ -2325,6 +2435,53 @@ initializer_expr :       rhs_expr
                        |       list_rhs_expr
                        ;
 
+counter_config         :       PACKETS         NUM     BYTES   NUM
+                       {
+                               struct counter *counter;
+
+                               counter = xzalloc(sizeof(*counter));
+                               counter->packets = $2;
+                               counter->bytes = $4;
+                               $$ = counter;
+                       }
+                       ;
+
+counter_obj            :       counter_config
+                       {
+                               $$ = obj_alloc(&@$);
+                               $$->type = NFT_OBJECT_COUNTER;
+                               $$->counter = *$1;
+                       }
+                       ;
+
+quota_config           :       quota_mode NUM quota_unit quota_used
+                       {
+                               struct error_record *erec;
+                               struct quota *quota;
+                               uint64_t rate;
+
+                               erec = data_unit_parse(&@$, $3, &rate);
+                               if (erec != NULL) {
+                                       erec_queue(erec, state->msgs);
+                                       YYERROR;
+                               }
+
+                               quota = xzalloc(sizeof(*quota));
+                               quota->bytes    = $2 * rate;
+                               quota->used     = $4;
+                               quota->flags    = $1;
+                               $$ = quota;
+                       }
+                       ;
+
+quota_obj              :       quota_config
+                       {
+                               $$ = obj_alloc(&@$);
+                               $$->type = NFT_OBJECT_QUOTA;
+                               $$->quota = *$1;
+                       }
+                       ;
+
 relational_expr                :       expr    /* implicit */  rhs_expr
                        {
                                $$ = relational_expr_alloc(&@$, OP_IMPLICIT, $1, $2);
index 05f0eb87b16266d41dd1edf72d19814fc7066b85..29b1450666dbf720341eeaba1d80b810cbe8a78d 100644 (file)
@@ -44,6 +44,8 @@ void handle_merge(struct handle *dst, const struct handle *src)
                dst->chain = xstrdup(src->chain);
        if (dst->set == NULL && src->set != NULL)
                dst->set = xstrdup(src->set);
+       if (dst->obj == NULL && src->obj != NULL)
+               dst->obj = xstrdup(src->obj);
        if (dst->handle.id == 0)
                dst->handle = src->handle;
        if (dst->position.id == 0)
@@ -875,6 +877,10 @@ void cmd_free(struct cmd *cmd)
                case CMD_OBJ_EXPORT:
                        export_free(cmd->export);
                        break;
+               case CMD_OBJ_COUNTER:
+               case CMD_OBJ_QUOTA:
+                       obj_free(cmd->object);
+                       break;
                default:
                        BUG("invalid command object type %u\n", cmd->obj);
                }
@@ -940,6 +946,7 @@ static int do_add_table(struct netlink_ctx *ctx, const struct handle *h,
                        bool excl)
 {
        struct chain *chain;
+       struct obj *obj;
        struct set *set;
 
        if (netlink_add_table(ctx, h, loc, table, excl) < 0)
@@ -951,6 +958,11 @@ static int do_add_table(struct netlink_ctx *ctx, const struct handle *h,
                                              excl) < 0)
                                return -1;
                }
+               list_for_each_entry(obj, &table->objs, list) {
+                       handle_merge(&obj->handle, &table->handle);
+                       if (netlink_add_obj(ctx, &obj->handle, obj, excl) < 0)
+                               return -1;
+               }
                list_for_each_entry(set, &table->sets, list) {
                        handle_merge(&set->handle, &table->handle);
                        if (do_add_set(ctx, &set->handle, set, excl) < 0)
@@ -980,6 +992,9 @@ static int do_command_add(struct netlink_ctx *ctx, struct cmd *cmd, bool excl)
                return do_add_set(ctx, &cmd->handle, cmd->set, excl);
        case CMD_OBJ_SETELEM:
                return do_add_setelems(ctx, &cmd->handle, cmd->expr, excl);
+       case CMD_OBJ_COUNTER:
+       case CMD_OBJ_QUOTA:
+               return netlink_add_obj(ctx, &cmd->handle, cmd->object, excl);
        default:
                BUG("invalid command object type %u\n", cmd->obj);
        }
@@ -1043,6 +1058,12 @@ static int do_command_delete(struct netlink_ctx *ctx, struct cmd *cmd)
                return netlink_delete_set(ctx, &cmd->handle, &cmd->location);
        case CMD_OBJ_SETELEM:
                return do_delete_setelems(ctx, &cmd->handle, cmd->expr);
+       case CMD_OBJ_COUNTER:
+               return netlink_delete_obj(ctx, &cmd->handle, &cmd->location,
+                                         NFT_OBJECT_COUNTER);
+       case CMD_OBJ_QUOTA:
+               return netlink_delete_obj(ctx, &cmd->handle, &cmd->location,
+                                         NFT_OBJECT_QUOTA);
        default:
                BUG("invalid command object type %u\n", cmd->obj);
        }