]> git.ipfire.org Git - thirdparty/libnftnl.git/commitdiff
rule: add NFT_RULE_ATTR_USERDATA support
authorPablo Neira Ayuso <pablo@netfilter.org>
Tue, 25 Feb 2014 23:10:50 +0000 (00:10 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Thu, 27 Feb 2014 15:59:59 +0000 (16:59 +0100)
This allows us to manipulate the user data area of the rule.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
include/libnftnl/rule.h
include/linux/netfilter/nf_tables.h
src/rule.c

index 9e6efaf491da1062a86321ff69b33db7b8b461ad..62dba599d95ec5ad71778153f1310e6d1abd6192 100644 (file)
@@ -26,6 +26,7 @@ enum {
        NFT_RULE_ATTR_COMPAT_PROTO,
        NFT_RULE_ATTR_COMPAT_FLAGS,
        NFT_RULE_ATTR_POSITION,
+       NFT_RULE_ATTR_USERDATA,
        __NFT_RULE_ATTR_MAX
 };
 #define NFT_RULE_ATTR_MAX (__NFT_RULE_ATTR_MAX - 1)
index f722ba527c5eb9ef779833c6eeba1f4a0b3cdc7a..bb160d5f7d9e902959c1a6ba014ef406c202fb11 100644 (file)
@@ -1,7 +1,8 @@
 #ifndef _LINUX_NF_TABLES_H
 #define _LINUX_NF_TABLES_H
 
-#define NFT_CHAIN_MAXNAMELEN 32
+#define NFT_CHAIN_MAXNAMELEN   32
+#define NFT_USERDATA_MAXLEN    256
 
 enum nft_registers {
        NFT_REG_VERDICT,
@@ -156,6 +157,7 @@ enum nft_chain_attributes {
  * @NFTA_RULE_EXPRESSIONS: list of expressions (NLA_NESTED: nft_expr_attributes)
  * @NFTA_RULE_COMPAT: compatibility specifications of the rule (NLA_NESTED: nft_rule_compat_attributes)
  * @NFTA_RULE_POSITION: numeric handle of the previous rule (NLA_U64)
+ * @NFTA_RULE_USERDATA: user data (NLA_BINARY, NFT_USERDATA_MAXLEN)
  */
 enum nft_rule_attributes {
        NFTA_RULE_UNSPEC,
@@ -165,6 +167,7 @@ enum nft_rule_attributes {
        NFTA_RULE_EXPRESSIONS,
        NFTA_RULE_COMPAT,
        NFTA_RULE_POSITION,
+       NFTA_RULE_USERDATA,
        __NFTA_RULE_MAX
 };
 #define NFTA_RULE_MAX          (__NFTA_RULE_MAX - 1)
index eb9f41c8d87f0a2a6617d0ce558ac2fbb16bb4cd..162a0a1a8a2d7a153975cbc623b69cbdff1dbe46 100644 (file)
@@ -19,6 +19,7 @@
 #include <netinet/in.h>
 #include <errno.h>
 #include <inttypes.h>
+#include <ctype.h>
 
 #include <libmnl/libmnl.h>
 #include <linux/netfilter/nfnetlink.h>
@@ -39,6 +40,10 @@ struct nft_rule {
        const char      *chain;
        uint64_t        handle;
        uint64_t        position;
+       struct {
+                       void            *data;
+                       uint32_t        len;
+       } user;
        struct {
                        uint32_t        flags;
                        uint32_t        proto;
@@ -106,6 +111,7 @@ void nft_rule_attr_unset(struct nft_rule *r, uint16_t attr)
        case NFT_RULE_ATTR_COMPAT_FLAGS:
        case NFT_RULE_ATTR_POSITION:
        case NFT_RULE_ATTR_FAMILY:
+       case NFT_RULE_ATTR_USERDATA:
                break;
        }
 
@@ -157,6 +163,10 @@ void nft_rule_attr_set_data(struct nft_rule *r, uint16_t attr,
        case NFT_RULE_ATTR_POSITION:
                r->position = *((uint64_t *)data);
                break;
+       case NFT_RULE_ATTR_USERDATA:
+               r->user.data = (void *)data;
+               r->user.len = data_len;
+               break;
        }
        r->flags |= (1 << attr);
 }
@@ -212,6 +222,9 @@ const void *nft_rule_attr_get_data(const struct nft_rule *r, uint16_t attr,
        case NFT_RULE_ATTR_POSITION:
                *data_len = sizeof(uint64_t);
                return &r->position;
+       case NFT_RULE_ATTR_USERDATA:
+               *data_len = r->user.len;
+               return r->user.data;
        }
        return NULL;
 }
@@ -276,6 +289,10 @@ void nft_rule_nlmsg_build_payload(struct nlmsghdr *nlh, struct nft_rule *r)
                mnl_attr_put_u64(nlh, NFTA_RULE_HANDLE, htobe64(r->handle));
        if (r->flags & (1 << NFT_RULE_ATTR_POSITION))
                mnl_attr_put_u64(nlh, NFTA_RULE_POSITION, htobe64(r->position));
+       if (r->flags & (1 << NFT_RULE_ATTR_USERDATA)) {
+               mnl_attr_put(nlh, NFTA_RULE_USERDATA, r->user.len,
+                            r->user.data);
+       }
 
        if (!list_empty(&r->expr_list)) {
                nest = mnl_attr_nest_start(nlh, NFTA_RULE_EXPRESSIONS);
@@ -338,6 +355,12 @@ static int nft_rule_parse_attr_cb(const struct nlattr *attr, void *data)
                        return MNL_CB_ERROR;
                }
                break;
+       case NFTA_RULE_USERDATA:
+               if (mnl_attr_validate(attr, MNL_TYPE_BINARY) < 0) {
+                       perror("mnl_attr_validate");
+                       return MNL_CB_ERROR;
+               }
+               break;
        }
 
        tb[type] = attr;
@@ -478,6 +501,22 @@ int nft_rule_nlmsg_parse(const struct nlmsghdr *nlh, struct nft_rule *r)
                r->position = be64toh(mnl_attr_get_u64(tb[NFTA_RULE_POSITION]));
                r->flags |= (1 << NFT_RULE_ATTR_POSITION);
        }
+       if (tb[NFTA_RULE_USERDATA]) {
+               const void *udata =
+                       mnl_attr_get_payload(tb[NFTA_RULE_USERDATA]);
+
+               if (r->user.data)
+                       xfree(r->user.data);
+
+               r->user.len = mnl_attr_get_payload_len(tb[NFTA_RULE_USERDATA]);
+
+               r->user.data = malloc(r->user.len);
+               if (r->user.data == NULL)
+                       return -1;
+
+               memcpy(r->user.data, udata, r->user.len);
+               r->flags |= (1 << NFT_RULE_ATTR_USERDATA);
+       }
 
        r->family = nfg->nfgen_family;
        r->flags |= (1 << NFT_RULE_ATTR_FAMILY);
@@ -830,7 +869,7 @@ static int nft_rule_snprintf_default(char *buf, size_t size, struct nft_rule *r,
                                     uint32_t type, uint32_t flags)
 {
        struct nft_rule_expr *expr;
-       int ret, len = size, offset = 0;
+       int ret, len = size, offset = 0, i;
 
        ret = snprintf(buf, len, "%s %s %s %"PRIu64" %"PRIu64"\n",
                        nft_family2str(r->family), r->table, r->chain,
@@ -849,6 +888,23 @@ static int nft_rule_snprintf_default(char *buf, size_t size, struct nft_rule *r,
                SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
        }
 
+       if (r->user.len) {
+               ret = snprintf(buf+offset, len, "  userdata = { ");
+               SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+               for (i = 0; i < r->user.len; i++) {
+                       char *c = r->user.data;
+
+                       ret = snprintf(buf+offset, len, "%c",
+                                      isalnum(c[i]) ? c[i] : 0);
+                       SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+               }
+
+               ret = snprintf(buf+offset, len, " }\n");
+               SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+       }
+
        return offset;
 }