Now is it possible to store multiple variable length user data into a rule.

Signed-off-by: Carlos Falgueras García <carlo...@riseup.net>
---
 src/rule.c | 158 ++++++++++++++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 130 insertions(+), 28 deletions(-)

diff --git a/src/rule.c b/src/rule.c
index 3a32bf6..4e6f375 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -28,6 +28,7 @@
 #include <libnftnl/rule.h>
 #include <libnftnl/set.h>
 #include <libnftnl/expr.h>
+#include <libnftnl/attr.h>
 
 struct nftnl_rule {
        struct list_head head;
@@ -38,10 +39,7 @@ struct nftnl_rule {
        const char      *chain;
        uint64_t        handle;
        uint64_t        position;
-       struct {
-                       void            *data;
-                       uint32_t        len;
-       } user;
+       struct nftnl_attrbuf    *userdata;
        struct {
                        uint32_t        flags;
                        uint32_t        proto;
@@ -50,6 +48,14 @@ struct nftnl_rule {
        struct list_head expr_list;
 };
 
+static void nftnl_rule_parse_userdata(const struct nftnl_attrbuf *attrbuf,
+                                     const struct nftnl_attr *tb[]);
+static size_t nftnl_rule_snprintf_data2str(char *buf, size_t size,
+                                          const void *data, size_t datalen);
+static size_t nftnl_rule_snprintf_userdata(char *buf, size_t size,
+                                          const struct nftnl_attr *tb[],
+                                          enum nftnl_attr_data_type dtype);
+
 struct nftnl_rule *nftnl_rule_alloc(void)
 {
        struct nftnl_rule *r;
@@ -75,6 +81,8 @@ void nftnl_rule_free(struct nftnl_rule *r)
                xfree(r->table);
        if (r->chain != NULL)
                xfree(r->chain);
+       if (r->flags & (1 << NFTNL_RULE_USERDATA))
+               nftnl_attrbuf_free(r->userdata);
 
        xfree(r);
 }
@@ -162,8 +170,12 @@ void nftnl_rule_set_data(struct nftnl_rule *r, uint16_t 
attr,
                r->position = *((uint64_t *)data);
                break;
        case NFTNL_RULE_USERDATA:
-               r->user.data = (void *)data;
-               r->user.len = data_len;
+               (r->userdata = nftnl_attrbuf_alloc(data_len));
+               if (!r->userdata) {
+                       perror("nftnl_rule_set_data - userdata");
+                       exit(EXIT_FAILURE);
+               }
+               nftnl_attrbuf_copy_data(r->userdata, data, data_len);
                break;
        }
        r->flags |= (1 << attr);
@@ -221,8 +233,8 @@ const void *nftnl_rule_get_data(const struct nftnl_rule *r, 
uint16_t attr,
                *data_len = sizeof(uint64_t);
                return &r->position;
        case NFTNL_RULE_USERDATA:
-               *data_len = r->user.len;
-               return r->user.data;
+               *data_len = nftnl_attrbuf_get_len(r->userdata);
+               return (void *)nftnl_attrbuf_get_data(r->userdata);
        }
        return NULL;
 }
@@ -288,8 +300,9 @@ void nftnl_rule_nlmsg_build_payload(struct nlmsghdr *nlh, 
struct nftnl_rule *r)
        if (r->flags & (1 << NFTNL_RULE_POSITION))
                mnl_attr_put_u64(nlh, NFTA_RULE_POSITION, htobe64(r->position));
        if (r->flags & (1 << NFTNL_RULE_USERDATA)) {
-               mnl_attr_put(nlh, NFTA_RULE_USERDATA, r->user.len,
-                            r->user.data);
+               mnl_attr_put(nlh, NFTA_RULE_USERDATA,
+                            nftnl_attrbuf_get_len(r->userdata),
+                            nftnl_attrbuf_get_data(r->userdata));
        }
 
        if (!list_empty(&r->expr_list)) {
@@ -447,19 +460,17 @@ int nftnl_rule_nlmsg_parse(const struct nlmsghdr *nlh, 
struct nftnl_rule *r)
                r->flags |= (1 << NFTNL_RULE_POSITION);
        }
        if (tb[NFTA_RULE_USERDATA]) {
+               uint16_t udata_size;
                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]);
+               udata_size = mnl_attr_get_payload_len(tb[NFTA_RULE_USERDATA]);
 
-               r->user.data = malloc(r->user.len);
-               if (r->user.data == NULL)
+               (r->userdata = nftnl_attrbuf_alloc(udata_size));
+               if (!r->userdata)
                        return -1;
+               nftnl_attrbuf_copy_data(r->userdata, udata, udata_size);
 
-               memcpy(r->user.data, udata, r->user.len);
                r->flags |= (1 << NFTNL_RULE_USERDATA);
        }
 
@@ -757,6 +768,29 @@ static int nftnl_rule_snprintf_json(char *buf, size_t 
size, struct nftnl_rule *r
                SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
        }
 
+       if (r->flags & (1 << NFTNL_RULE_USERDATA)) {
+               const struct nftnl_attr *tb[NFTNL_ATTR_TYPE_MAX+1] = {NULL};
+
+               nftnl_rule_parse_userdata(r->userdata, tb);
+
+               ret = snprintf(buf+offset, len, "\"userdata\":[");
+               SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+               if (tb[NFTNL_ATTR_TYPE_COMMENT]) {
+                       ret = snprintf(buf+offset, len, "{\"comment\":\"");
+                       SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+                       ret = nftnl_rule_snprintf_userdata(buf+offset, size, tb,
+                                               NFTNL_ATTR_TYPE_COMMENT);
+                       SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+                       ret = snprintf(buf+offset, len, "\"}");
+                       SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+               }
+
+               ret = snprintf(buf+offset, len, "],\n");
+               SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+       }
+
        ret = snprintf(buf+offset, len, "\"expr\":[");
        SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
 
@@ -855,11 +889,76 @@ static int nftnl_rule_snprintf_xml(char *buf, size_t 
size, struct nftnl_rule *r,
        return offset;
 }
 
+static int nftnl_rule_parse_userdata_cb(const struct nftnl_attr *attr,
+                                       void *data)
+{
+       const struct nftnl_attr **tb = data;
+       uint8_t type = nftnl_attr_get_type(attr);
+       uint8_t len = nftnl_attr_get_len(attr);
+       unsigned char *value = nftnl_attr_get_value(attr);
+
+       /* Validation */
+       switch (type) {
+       case NFTNL_ATTR_TYPE_COMMENT:
+               if (value[len-1] != '\0')
+                       return NFTNL_CB_ERROR;
+       default:
+               return NFTNL_CB_ERROR;
+       };
+
+       tb[type] = attr;
+       return NFTNL_CB_OK;
+}
+
+static void nftnl_rule_parse_userdata(const struct nftnl_attrbuf *attrbuf,
+                                     const struct nftnl_attr *tb[])
+{
+       if (nftnl_attr_parse(attrbuf, nftnl_rule_parse_userdata_cb, tb)
+               != NFTNL_CB_OK
+       ) {
+               fprintf(stderr, "Error parsing rule userdata\n");
+               exit(EXIT_FAILURE);
+       }
+}
+
+static size_t nftnl_rule_snprintf_data2str(char *buf, size_t size,
+                                          const void *data, size_t datalen)
+{
+       int i;
+       size_t ret, len = size, offset = 0;
+       const char *c = data;
+
+       for (i = 0; i < datalen; i++) {
+               ret = snprintf(buf+offset, len, "%c",
+                              isprint(c[i]) ? c[i] : '?');
+               SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+       }
+
+       return offset;
+}
+
+static size_t nftnl_rule_snprintf_userdata(char *buf, size_t size,
+                                          const struct nftnl_attr *tb[],
+                                          enum nftnl_attr_data_type dtype)
+{
+       size_t ret, offset = 0;
+
+       ret = nftnl_rule_snprintf_data2str(
+               buf,
+               size,
+               nftnl_attr_get_value(tb[dtype]),
+               nftnl_attr_get_len(tb[dtype])-1
+       );
+       SNPRINTF_BUFFER_SIZE(ret, size, size, offset);
+
+       return offset;
+}
+
 static int nftnl_rule_snprintf_default(char *buf, size_t size, struct 
nftnl_rule *r,
                                     uint32_t type, uint32_t flags)
 {
        struct nftnl_expr *expr;
-       int ret, len = size, offset = 0, i;
+       int ret, len = size, offset = 0;
 
        if (r->flags & (1 << NFTNL_RULE_FAMILY)) {
                ret = snprintf(buf+offset, len, "%s ",
@@ -905,20 +1004,23 @@ static int nftnl_rule_snprintf_default(char *buf, size_t 
size, struct nftnl_rule
                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;
+       if (r->flags & (1 << NFTNL_RULE_USERDATA)) {
+               const struct nftnl_attr *tb[NFTNL_ATTR_TYPE_MAX+1] = {NULL};
+
+               nftnl_rule_parse_userdata(r->userdata, tb);
 
-                       ret = snprintf(buf+offset, len, "%c",
-                                      isalnum(c[i]) ? c[i] : 0);
+               if (tb[NFTNL_ATTR_TYPE_COMMENT]) {
+                       ret = snprintf(buf+offset, len, "  userdata = { ");
                        SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-               }
 
-               ret = snprintf(buf+offset, len, " }\n");
-               SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+                       ret = nftnl_rule_snprintf_userdata(buf+offset, size, tb,
+                                               NFTNL_ATTR_TYPE_COMMENT);
+                       SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+                       ret = snprintf(buf+offset, len, " }\n");
+                       SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+               }
 
        }
 
-- 
2.7.0

--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to