OpenWrt – Rev 1

Subversion Repositories:
Rev:
From: Harsha Sharma <harshasharmaiitr@gmail.com>
Date: Wed, 27 Dec 2017 00:59:00 +0530
Subject: [PATCH] netfilter: nf_tables: allocate handle and delete objects via
 handle

This patch allows deletion of objects via unique handle which can be
listed via '-a' option.

Signed-off-by: Harsha Sharma <harshasharmaiitr@gmail.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---

--- a/include/net/netfilter/nf_tables.h
+++ b/include/net/netfilter/nf_tables.h
@@ -370,6 +370,7 @@ void nft_unregister_set(struct nft_set_t
  *     @list: table set list node
  *     @bindings: list of set bindings
  *     @name: name of the set
+ *     @handle: unique handle of the set
  *     @ktype: key type (numeric type defined by userspace, not used in the kernel)
  *     @dtype: data type (verdict or numeric type defined by userspace)
  *     @objtype: object type (see NFT_OBJECT_* definitions)
@@ -392,6 +393,7 @@ struct nft_set {
        struct list_head                list;
        struct list_head                bindings;
        char                            *name;
+       u64                             handle;
        u32                             ktype;
        u32                             dtype;
        u32                             objtype;
@@ -941,6 +943,7 @@ unsigned int nft_do_chain(struct nft_pkt
  *     @objects: stateful objects in the table
  *     @flowtables: flow tables in the table
  *     @hgenerator: handle generator state
+ *     @handle: table handle
  *     @use: number of chain references to this table
  *     @flags: table flag (see enum nft_table_flags)
  *     @genmask: generation mask
@@ -954,6 +957,7 @@ struct nft_table {
        struct list_head                objects;
        struct list_head                flowtables;
        u64                             hgenerator;
+       u64                             handle;
        u32                             use;
        u16                             family:6,
                                        flags:8,
@@ -978,9 +982,9 @@ int nft_verdict_dump(struct sk_buff *skb
  *     @name: name of this stateful object
  *     @genmask: generation mask
  *     @use: number of references to this stateful object
- *     @data: object data, layout depends on type
+ *     @handle: unique object handle
  *     @ops: object operations
- *     @data: pointer to object data
+ *     @data: object data, layout depends on type
  */
 struct nft_object {
        struct list_head                list;
@@ -988,6 +992,7 @@ struct nft_object {
        struct nft_table                *table;
        u32                             genmask:2,
                                        use:30;
+       u64                             handle;
        /* runtime data below here */
        const struct nft_object_ops     *ops ____cacheline_aligned;
        unsigned char                   data[]
@@ -1069,6 +1074,7 @@ void nft_unregister_obj(struct nft_objec
  *     @ops_len: number of hooks in array
  *     @genmask: generation mask
  *     @use: number of references to this flow table
+ *     @handle: unique object handle
  *     @data: rhashtable and garbage collector
  *     @ops: array of hooks
  */
@@ -1081,6 +1087,7 @@ struct nft_flowtable {
        int                             ops_len;
        u32                             genmask:2,
                                        use:30;
+       u64                             handle;
        /* runtime data below here */
        struct nf_hook_ops              *ops ____cacheline_aligned;
        struct nf_flowtable             data;
--- a/include/uapi/linux/netfilter/nf_tables.h
+++ b/include/uapi/linux/netfilter/nf_tables.h
@@ -174,6 +174,8 @@ enum nft_table_attributes {
        NFTA_TABLE_NAME,
        NFTA_TABLE_FLAGS,
        NFTA_TABLE_USE,
+       NFTA_TABLE_HANDLE,
+       NFTA_TABLE_PAD,
        __NFTA_TABLE_MAX
 };
 #define NFTA_TABLE_MAX         (__NFTA_TABLE_MAX - 1)
@@ -317,6 +319,7 @@ enum nft_set_desc_attributes {
  * @NFTA_SET_GC_INTERVAL: garbage collection interval (NLA_U32)
  * @NFTA_SET_USERDATA: user data (NLA_BINARY)
  * @NFTA_SET_OBJ_TYPE: stateful object type (NLA_U32: NFT_OBJECT_*)
+ * @NFTA_SET_HANDLE: set handle (NLA_U64)
  */
 enum nft_set_attributes {
        NFTA_SET_UNSPEC,
@@ -335,6 +338,7 @@ enum nft_set_attributes {
        NFTA_SET_USERDATA,
        NFTA_SET_PAD,
        NFTA_SET_OBJ_TYPE,
+       NFTA_SET_HANDLE,
        __NFTA_SET_MAX
 };
 #define NFTA_SET_MAX           (__NFTA_SET_MAX - 1)
@@ -1314,6 +1318,7 @@ enum nft_ct_helper_attributes {
  * @NFTA_OBJ_TYPE: stateful object type (NLA_U32)
  * @NFTA_OBJ_DATA: stateful object data (NLA_NESTED)
  * @NFTA_OBJ_USE: number of references to this expression (NLA_U32)
+ * @NFTA_OBJ_HANDLE: object handle (NLA_U64)
  */
 enum nft_object_attributes {
        NFTA_OBJ_UNSPEC,
@@ -1322,6 +1327,8 @@ enum nft_object_attributes {
        NFTA_OBJ_TYPE,
        NFTA_OBJ_DATA,
        NFTA_OBJ_USE,
+       NFTA_OBJ_HANDLE,
+       NFTA_OBJ_PAD,
        __NFTA_OBJ_MAX
 };
 #define NFTA_OBJ_MAX           (__NFTA_OBJ_MAX - 1)
@@ -1333,6 +1340,7 @@ enum nft_object_attributes {
  * @NFTA_FLOWTABLE_NAME: name of this flow table (NLA_STRING)
  * @NFTA_FLOWTABLE_HOOK: netfilter hook configuration(NLA_U32)
  * @NFTA_FLOWTABLE_USE: number of references to this flow table (NLA_U32)
+ * @NFTA_FLOWTABLE_HANDLE: object handle (NLA_U64)
  */
 enum nft_flowtable_attributes {
        NFTA_FLOWTABLE_UNSPEC,
@@ -1340,6 +1348,8 @@ enum nft_flowtable_attributes {
        NFTA_FLOWTABLE_NAME,
        NFTA_FLOWTABLE_HOOK,
        NFTA_FLOWTABLE_USE,
+       NFTA_FLOWTABLE_HANDLE,
+       NFTA_FLOWTABLE_PAD,
        __NFTA_FLOWTABLE_MAX
 };
 #define NFTA_FLOWTABLE_MAX     (__NFTA_FLOWTABLE_MAX - 1)
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -26,6 +26,7 @@
 static LIST_HEAD(nf_tables_expressions);
 static LIST_HEAD(nf_tables_objects);
 static LIST_HEAD(nf_tables_flowtables);
+static u64 table_handle;
 
 static void nft_ctx_init(struct nft_ctx *ctx,
                         struct net *net,
@@ -361,6 +362,20 @@ static struct nft_table *nft_table_looku
        return NULL;
 }
 
+static struct nft_table *nft_table_lookup_byhandle(const struct net *net,
+                                                  const struct nlattr *nla,
+                                                  u8 genmask)
+{
+       struct nft_table *table;
+
+       list_for_each_entry(table, &net->nft.tables, list) {
+               if (be64_to_cpu(nla_get_be64(nla)) == table->handle &&
+                   nft_active_genmask(table, genmask))
+                       return table;
+       }
+       return NULL;
+}
+
 static struct nft_table *nf_tables_table_lookup(const struct net *net,
                                                const struct nlattr *nla,
                                                u8 family, u8 genmask)
@@ -377,6 +392,22 @@ static struct nft_table *nf_tables_table
        return ERR_PTR(-ENOENT);
 }
 
+static struct nft_table *nf_tables_table_lookup_byhandle(const struct net *net,
+                                                        const struct nlattr *nla,
+                                                        u8 genmask)
+{
+       struct nft_table *table;
+
+       if (nla == NULL)
+               return ERR_PTR(-EINVAL);
+
+       table = nft_table_lookup_byhandle(net, nla, genmask);
+       if (table != NULL)
+               return table;
+
+       return ERR_PTR(-ENOENT);
+}
+
 static inline u64 nf_tables_alloc_handle(struct nft_table *table)
 {
        return ++table->hgenerator;
@@ -423,6 +454,7 @@ static const struct nla_policy nft_table
        [NFTA_TABLE_NAME]       = { .type = NLA_STRING,
                                    .len = NFT_TABLE_MAXNAMELEN - 1 },
        [NFTA_TABLE_FLAGS]      = { .type = NLA_U32 },
+       [NFTA_TABLE_HANDLE]     = { .type = NLA_U64 },
 };
 
 static int nf_tables_fill_table_info(struct sk_buff *skb, struct net *net,
@@ -444,7 +476,9 @@ static int nf_tables_fill_table_info(str
 
        if (nla_put_string(skb, NFTA_TABLE_NAME, table->name) ||
            nla_put_be32(skb, NFTA_TABLE_FLAGS, htonl(table->flags)) ||
-           nla_put_be32(skb, NFTA_TABLE_USE, htonl(table->use)))
+           nla_put_be32(skb, NFTA_TABLE_USE, htonl(table->use)) ||
+           nla_put_be64(skb, NFTA_TABLE_HANDLE, cpu_to_be64(table->handle),
+                        NFTA_TABLE_PAD))
                goto nla_put_failure;
 
        nlmsg_end(skb, nlh);
@@ -703,6 +737,7 @@ static int nf_tables_newtable(struct net
        INIT_LIST_HEAD(&table->flowtables);
        table->family = family;
        table->flags = flags;
+       table->handle = ++table_handle;
 
        nft_ctx_init(&ctx, net, skb, nlh, family, table, NULL, nla);
        err = nft_trans_table_add(&ctx, NFT_MSG_NEWTABLE);
@@ -820,11 +855,18 @@ static int nf_tables_deltable(struct net
        struct nft_ctx ctx;
 
        nft_ctx_init(&ctx, net, skb, nlh, 0, NULL, NULL, nla);
-       if (family == AF_UNSPEC || nla[NFTA_TABLE_NAME] == NULL)
+       if (family == AF_UNSPEC ||
+           (!nla[NFTA_TABLE_NAME] && !nla[NFTA_TABLE_HANDLE]))
                return nft_flush(&ctx, family);
 
-       table = nf_tables_table_lookup(net, nla[NFTA_TABLE_NAME], family,
-                                      genmask);
+       if (nla[NFTA_TABLE_HANDLE])
+               table = nf_tables_table_lookup_byhandle(net,
+                                                       nla[NFTA_TABLE_HANDLE],
+                                                       genmask);
+       else
+               table = nf_tables_table_lookup(net, nla[NFTA_TABLE_NAME],
+                                              family, genmask);
+
        if (IS_ERR(table))
                return PTR_ERR(table);
 
@@ -1581,6 +1623,7 @@ static int nf_tables_delchain(struct net
        struct nft_rule *rule;
        int family = nfmsg->nfgen_family;
        struct nft_ctx ctx;
+       u64 handle;
        u32 use;
        int err;
 
@@ -1589,7 +1632,12 @@ static int nf_tables_delchain(struct net
        if (IS_ERR(table))
                return PTR_ERR(table);
 
-       chain = nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME], genmask);
+       if (nla[NFTA_CHAIN_HANDLE]) {
+               handle = be64_to_cpu(nla_get_be64(nla[NFTA_CHAIN_HANDLE]));
+               chain = nf_tables_chain_lookup_byhandle(table, handle, genmask);
+       } else {
+               chain = nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME], genmask);
+       }
        if (IS_ERR(chain))
                return PTR_ERR(chain);
 
@@ -2557,6 +2605,7 @@ static const struct nla_policy nft_set_p
        [NFTA_SET_USERDATA]             = { .type = NLA_BINARY,
                                            .len  = NFT_USERDATA_MAXLEN },
        [NFTA_SET_OBJ_TYPE]             = { .type = NLA_U32 },
+       [NFTA_SET_HANDLE]               = { .type = NLA_U64 },
 };
 
 static const struct nla_policy nft_set_desc_policy[NFTA_SET_DESC_MAX + 1] = {
@@ -2600,6 +2649,22 @@ static struct nft_set *nf_tables_set_loo
        return ERR_PTR(-ENOENT);
 }
 
+static struct nft_set *nf_tables_set_lookup_byhandle(const struct nft_table *table,
+                                                    const struct nlattr *nla, u8 genmask)
+{
+       struct nft_set *set;
+
+       if (nla == NULL)
+               return ERR_PTR(-EINVAL);
+
+       list_for_each_entry(set, &table->sets, list) {
+               if (be64_to_cpu(nla_get_be64(nla)) == set->handle &&
+                   nft_active_genmask(set, genmask))
+                       return set;
+       }
+       return ERR_PTR(-ENOENT);
+}
+
 static struct nft_set *nf_tables_set_lookup_byid(const struct net *net,
                                                 const struct nlattr *nla,
                                                 u8 genmask)
@@ -2716,6 +2781,9 @@ static int nf_tables_fill_set(struct sk_
                goto nla_put_failure;
        if (nla_put_string(skb, NFTA_SET_NAME, set->name))
                goto nla_put_failure;
+       if (nla_put_be64(skb, NFTA_SET_HANDLE, cpu_to_be64(set->handle),
+                        NFTA_SET_PAD))
+               goto nla_put_failure;
        if (set->flags != 0)
                if (nla_put_be32(skb, NFTA_SET_FLAGS, htonl(set->flags)))
                        goto nla_put_failure;
@@ -3124,6 +3192,7 @@ static int nf_tables_newset(struct net *
        set->udata  = udata;
        set->timeout = timeout;
        set->gc_int = gc_int;
+       set->handle = nf_tables_alloc_handle(table);
 
        err = ops->init(set, &desc, nla);
        if (err < 0)
@@ -3183,7 +3252,10 @@ static int nf_tables_delset(struct net *
        if (err < 0)
                return err;
 
-       set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME], genmask);
+       if (nla[NFTA_SET_HANDLE])
+               set = nf_tables_set_lookup_byhandle(ctx.table, nla[NFTA_SET_HANDLE], genmask);
+       else
+               set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME], genmask);
        if (IS_ERR(set))
                return PTR_ERR(set);
 
@@ -4244,6 +4316,21 @@ struct nft_object *nf_tables_obj_lookup(
 }
 EXPORT_SYMBOL_GPL(nf_tables_obj_lookup);
 
+struct nft_object *nf_tables_obj_lookup_byhandle(const struct nft_table *table,
+                                                const struct nlattr *nla,
+                                                u32 objtype, u8 genmask)
+{
+       struct nft_object *obj;
+
+       list_for_each_entry(obj, &table->objects, list) {
+               if (be64_to_cpu(nla_get_be64(nla)) == obj->handle &&
+                   objtype == obj->ops->type->type &&
+                   nft_active_genmask(obj, genmask))
+                       return obj;
+       }
+       return ERR_PTR(-ENOENT);
+}
+
 static const struct nla_policy nft_obj_policy[NFTA_OBJ_MAX + 1] = {
        [NFTA_OBJ_TABLE]        = { .type = NLA_STRING,
                                    .len = NFT_TABLE_MAXNAMELEN - 1 },
@@ -4251,6 +4338,7 @@ static const struct nla_policy nft_obj_p
                                    .len = NFT_OBJ_MAXNAMELEN - 1 },
        [NFTA_OBJ_TYPE]         = { .type = NLA_U32 },
        [NFTA_OBJ_DATA]         = { .type = NLA_NESTED },
+       [NFTA_OBJ_HANDLE]       = { .type = NLA_U64},
 };
 
 static struct nft_object *nft_obj_init(const struct nft_ctx *ctx,
@@ -4398,6 +4486,8 @@ static int nf_tables_newobj(struct net *
                goto err1;
        }
        obj->table = table;
+       obj->handle = nf_tables_alloc_handle(table);
+
        obj->name = nla_strdup(nla[NFTA_OBJ_NAME], GFP_KERNEL);
        if (!obj->name) {
                err = -ENOMEM;
@@ -4444,7 +4534,9 @@ static int nf_tables_fill_obj_info(struc
            nla_put_string(skb, NFTA_OBJ_NAME, obj->name) ||
            nla_put_be32(skb, NFTA_OBJ_TYPE, htonl(obj->ops->type->type)) ||
            nla_put_be32(skb, NFTA_OBJ_USE, htonl(obj->use)) ||
-           nft_object_dump(skb, NFTA_OBJ_DATA, obj, reset))
+           nft_object_dump(skb, NFTA_OBJ_DATA, obj, reset) ||
+           nla_put_be64(skb, NFTA_OBJ_HANDLE, cpu_to_be64(obj->handle),
+                        NFTA_OBJ_PAD))
                goto nla_put_failure;
 
        nlmsg_end(skb, nlh);
@@ -4642,7 +4734,7 @@ static int nf_tables_delobj(struct net *
        u32 objtype;
 
        if (!nla[NFTA_OBJ_TYPE] ||
-           !nla[NFTA_OBJ_NAME])
+           (!nla[NFTA_OBJ_NAME] && !nla[NFTA_OBJ_HANDLE]))
                return -EINVAL;
 
        table = nf_tables_table_lookup(net, nla[NFTA_OBJ_TABLE], family,
@@ -4651,7 +4743,12 @@ static int nf_tables_delobj(struct net *
                return PTR_ERR(table);
 
        objtype = ntohl(nla_get_be32(nla[NFTA_OBJ_TYPE]));
-       obj = nf_tables_obj_lookup(table, nla[NFTA_OBJ_NAME], objtype, genmask);
+       if (nla[NFTA_OBJ_HANDLE])
+               obj = nf_tables_obj_lookup_byhandle(table, nla[NFTA_OBJ_HANDLE],
+                                                   objtype, genmask);
+       else
+               obj = nf_tables_obj_lookup(table, nla[NFTA_OBJ_NAME],
+                                          objtype, genmask);
        if (IS_ERR(obj))
                return PTR_ERR(obj);
        if (obj->use > 0)
@@ -4723,6 +4820,7 @@ static const struct nla_policy nft_flowt
        [NFTA_FLOWTABLE_NAME]           = { .type = NLA_STRING,
                                            .len = NFT_NAME_MAXLEN - 1 },
        [NFTA_FLOWTABLE_HOOK]           = { .type = NLA_NESTED },
+       [NFTA_FLOWTABLE_HANDLE]         = { .type = NLA_U64 },
 };
 
 struct nft_flowtable *nf_tables_flowtable_lookup(const struct nft_table *table,
@@ -4740,6 +4838,20 @@ struct nft_flowtable *nf_tables_flowtabl
 }
 EXPORT_SYMBOL_GPL(nf_tables_flowtable_lookup);
 
+struct nft_flowtable *
+nf_tables_flowtable_lookup_byhandle(const struct nft_table *table,
+                                   const struct nlattr *nla, u8 genmask)
+{
+       struct nft_flowtable *flowtable;
+
+       list_for_each_entry(flowtable, &table->flowtables, list) {
+               if (be64_to_cpu(nla_get_be64(nla)) == flowtable->handle &&
+                   nft_active_genmask(flowtable, genmask))
+                       return flowtable;
+       }
+       return ERR_PTR(-ENOENT);
+}
+
 #define NFT_FLOWTABLE_DEVICE_MAX       8
 
 static int nf_tables_parse_devices(const struct nft_ctx *ctx,
@@ -4948,6 +5060,8 @@ static int nf_tables_newflowtable(struct
                return -ENOMEM;
 
        flowtable->table = table;
+       flowtable->handle = nf_tables_alloc_handle(table);
+
        flowtable->name = nla_strdup(nla[NFTA_FLOWTABLE_NAME], GFP_KERNEL);
        if (!flowtable->name) {
                err = -ENOMEM;
@@ -5022,8 +5136,14 @@ static int nf_tables_delflowtable(struct
        if (IS_ERR(table))
                return PTR_ERR(table);
 
-       flowtable = nf_tables_flowtable_lookup(table, nla[NFTA_FLOWTABLE_NAME],
-                                              genmask);
+       if (nla[NFTA_FLOWTABLE_HANDLE])
+               flowtable = nf_tables_flowtable_lookup_byhandle(table,
+                                                               nla[NFTA_FLOWTABLE_HANDLE],
+                                                               genmask);
+       else
+               flowtable = nf_tables_flowtable_lookup(table,
+                                                      nla[NFTA_FLOWTABLE_NAME],
+                                                      genmask);
        if (IS_ERR(flowtable))
                 return PTR_ERR(flowtable);
        if (flowtable->use > 0)
@@ -5056,7 +5176,9 @@ static int nf_tables_fill_flowtable_info
 
        if (nla_put_string(skb, NFTA_FLOWTABLE_TABLE, flowtable->table->name) ||
            nla_put_string(skb, NFTA_FLOWTABLE_NAME, flowtable->name) ||
-           nla_put_be32(skb, NFTA_FLOWTABLE_USE, htonl(flowtable->use)))
+           nla_put_be32(skb, NFTA_FLOWTABLE_USE, htonl(flowtable->use)) ||
+           nla_put_be64(skb, NFTA_FLOWTABLE_HANDLE, cpu_to_be64(flowtable->handle),
+                        NFTA_FLOWTABLE_PAD))
                goto nla_put_failure;
 
        nest = nla_nest_start(skb, NFTA_FLOWTABLE_HOOK);