All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/4] nf: netfilter: nf_tables_api: Add new attributes into nft_set to store user data.
@ 2016-01-03 19:38 Carlos Falgueras García
  2016-01-03 19:38 ` [PATCH 2/4] libnftnl: set: Add new attribute into 'set' to store an arbitrary length " Carlos Falgueras García
                   ` (4 more replies)
  0 siblings, 5 replies; 7+ messages in thread
From: Carlos Falgueras García @ 2016-01-03 19:38 UTC (permalink / raw)
  To: netfilter-devel; +Cc: pablo, kaber

User data is stored at after 'nft_set_ops' private data into 'data[]'
flexible array. The field 'udata' points to user data and 'udlen' stores
its length.

Add new flag NFTA_SET_USERDATA.

Signed-off-by: Carlos Falgueras García <carlosfg@riseup.net>
---
 include/net/netfilter/nf_tables.h        |  4 ++++
 include/uapi/linux/netfilter/nf_tables.h |  2 ++
 net/netfilter/nf_tables_api.c            | 21 ++++++++++++++++++++-
 3 files changed, 26 insertions(+), 1 deletion(-)

diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
index 4bd7508..1324aae 100644
--- a/include/net/netfilter/nf_tables.h
+++ b/include/net/netfilter/nf_tables.h
@@ -293,6 +293,8 @@ void nft_unregister_set(struct nft_set_ops *ops);
  * 	@timeout: default timeout value in msecs
  * 	@gc_int: garbage collection interval in msecs
  *	@policy: set parameterization (see enum nft_set_policies)
+ *	@udlen: user data length
+ *	@udata: user data
  * 	@ops: set ops
  * 	@pnet: network namespace
  * 	@flags: set flags
@@ -312,6 +314,8 @@ struct nft_set {
 	u64				timeout;
 	u32				gc_int;
 	u16				policy;
+	u8				udlen;
+	unsigned char			*udata;
 	/* runtime data below here */
 	const struct nft_set_ops	*ops ____cacheline_aligned;
 	possible_net_t			pnet;
diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
index d8c8a7c..33ac070 100644
--- a/include/uapi/linux/netfilter/nf_tables.h
+++ b/include/uapi/linux/netfilter/nf_tables.h
@@ -289,6 +289,7 @@ enum nft_set_desc_attributes {
  * @NFTA_SET_ID: uniquely identifies a set in a transaction (NLA_U32)
  * @NFTA_SET_TIMEOUT: default timeout value (NLA_U64)
  * @NFTA_SET_GC_INTERVAL: garbage collection interval (NLA_U32)
+ * @NFTA_SET_USERDATA: user data (NLA_BINARY)
  */
 enum nft_set_attributes {
 	NFTA_SET_UNSPEC,
@@ -304,6 +305,7 @@ enum nft_set_attributes {
 	NFTA_SET_ID,
 	NFTA_SET_TIMEOUT,
 	NFTA_SET_GC_INTERVAL,
+	NFTA_SET_USERDATA,
 	__NFTA_SET_MAX
 };
 #define NFTA_SET_MAX		(__NFTA_SET_MAX - 1)
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 2cb429d..413678f 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -2333,6 +2333,8 @@ static const struct nla_policy nft_set_policy[NFTA_SET_MAX + 1] = {
 	[NFTA_SET_ID]			= { .type = NLA_U32 },
 	[NFTA_SET_TIMEOUT]		= { .type = NLA_U64 },
 	[NFTA_SET_GC_INTERVAL]		= { .type = NLA_U32 },
+	[NFTA_SET_USERDATA]		= { .type = NLA_BINARY,
+					    .len  = NFT_USERDATA_MAXLEN },
 };
 
 static const struct nla_policy nft_set_desc_policy[NFTA_SET_DESC_MAX + 1] = {
@@ -2494,6 +2496,9 @@ static int nf_tables_fill_set(struct sk_buff *skb, const struct nft_ctx *ctx,
 			goto nla_put_failure;
 	}
 
+	if (nla_put(skb, NFTA_SET_USERDATA, set->udlen, set->udata))
+		goto nla_put_failure;
+
 	desc = nla_nest_start(skb, NFTA_SET_DESC);
 	if (desc == NULL)
 		goto nla_put_failure;
@@ -2704,6 +2709,8 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
 	u64 timeout;
 	u32 ktype, dtype, flags, policy, gc_int;
 	struct nft_set_desc desc;
+	unsigned char udlen;
+	unsigned char *udata;
 	int err;
 
 	if (nla[NFTA_SET_TABLE] == NULL ||
@@ -2816,12 +2823,16 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
 	if (IS_ERR(ops))
 		return PTR_ERR(ops);
 
+	udlen = 0;
+	if (nla[NFTA_SET_USERDATA])
+		udlen = nla_len(nla[NFTA_SET_USERDATA]);
+
 	size = 0;
 	if (ops->privsize != NULL)
 		size = ops->privsize(nla);
 
 	err = -ENOMEM;
-	set = kzalloc(sizeof(*set) + size, GFP_KERNEL);
+	set = kzalloc(sizeof(*set) + size + udlen, GFP_KERNEL);
 	if (set == NULL)
 		goto err1;
 
@@ -2830,6 +2841,12 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
 	if (err < 0)
 		goto err2;
 
+	udata = NULL;
+	if (nla[NFTA_SET_USERDATA]) {
+		udata = set->data + size;
+		nla_memcpy(udata, nla[NFTA_SET_USERDATA], udlen);
+	}
+
 	INIT_LIST_HEAD(&set->bindings);
 	write_pnet(&set->pnet, net);
 	set->ops   = ops;
@@ -2840,6 +2857,8 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
 	set->flags = flags;
 	set->size  = desc.size;
 	set->policy = policy;
+	set->udlen  = udlen;
+	set->udata  = udata;
 	set->timeout = timeout;
 	set->gc_int = gc_int;
 
-- 
2.6.4

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

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/4] libnftnl: set: Add new attribute into 'set' to store an arbitrary length user data.
  2016-01-03 19:38 [PATCH 1/4] nf: netfilter: nf_tables_api: Add new attributes into nft_set to store user data Carlos Falgueras García
@ 2016-01-03 19:38 ` Carlos Falgueras García
  2016-01-03 19:38 ` [PATCH 3/4] libnftnl: set: Implement new buffer of TLV objects Carlos Falgueras García
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Carlos Falgueras García @ 2016-01-03 19:38 UTC (permalink / raw)
  To: netfilter-devel; +Cc: pablo, kaber

The new structure 'user' holds a pointer to user data and its length. The
kernel must have the flag NFTA_SET_USERDATA to support this feature.

Signed-off-by: Carlos Falgueras García <carlosfg@riseup.net>
---
 include/libnftnl/set.h              |  2 ++
 include/linux/netfilter/nf_tables.h |  2 ++
 include/set.h                       |  4 +++
 src/set.c                           | 50 +++++++++++++++++++++++++++++++++++++
 4 files changed, 58 insertions(+)

diff --git a/include/libnftnl/set.h b/include/libnftnl/set.h
index 11243f5..7a5a512 100644
--- a/include/libnftnl/set.h
+++ b/include/libnftnl/set.h
@@ -22,6 +22,7 @@ enum nftnl_set_attr {
 	NFTNL_SET_DESC_SIZE,
 	NFTNL_SET_TIMEOUT,
 	NFTNL_SET_GC_INTERVAL,
+	NFTNL_SET_USERDATA,
 	__NFTNL_SET_MAX
 };
 #define NFTNL_SET_MAX (__NFTNL_SET_MAX - 1)
@@ -158,6 +159,7 @@ enum {
 	NFT_SET_ATTR_DESC_SIZE,
 	NFT_SET_ATTR_TIMEOUT,
 	NFT_SET_ATTR_GC_INTERVAL,
+	NFT_SET_ATTR_USERDATA,
 	__NFT_SET_ATTR_MAX
 };
 #define NFT_SET_ATTR_MAX (__NFT_SET_ATTR_MAX - 1)
diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index f77693b..9beddc5 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -291,6 +291,7 @@ enum nft_set_desc_attributes {
  * @NFTA_SET_ID: uniquely identifies a set in a transaction (NLA_U32)
  * @NFTA_SET_TIMEOUT: default timeout value (NLA_U64)
  * @NFTA_SET_GC_INTERVAL: garbage collection interval (NLA_U32)
+ * @NFTA_SET_USERDATA: user data (NLA_BINARY)
  */
 enum nft_set_attributes {
 	NFTA_SET_UNSPEC,
@@ -306,6 +307,7 @@ enum nft_set_attributes {
 	NFTA_SET_ID,
 	NFTA_SET_TIMEOUT,
 	NFTA_SET_GC_INTERVAL,
+	NFTA_SET_USERDATA,
 	__NFTA_SET_MAX
 };
 #define NFTA_SET_MAX		(__NFTA_SET_MAX - 1)
diff --git a/include/set.h b/include/set.h
index c3b96f2..85bd389 100644
--- a/include/set.h
+++ b/include/set.h
@@ -14,6 +14,10 @@ struct nftnl_set {
 	uint32_t		key_len;
 	uint32_t		data_type;
 	uint32_t		data_len;
+	struct {
+		void		*data;
+		uint32_t	len;
+	} user;
 	uint32_t		id;
 	enum nft_set_policies	policy;
 	struct {
diff --git a/src/set.c b/src/set.c
index 8369f7f..315bced 100644
--- a/src/set.c
+++ b/src/set.c
@@ -19,6 +19,7 @@
 #include <netinet/in.h>
 #include <limits.h>
 #include <errno.h>
+#include <ctype.h>
 
 #include <libmnl/libmnl.h>
 #include <linux/netfilter/nfnetlink.h>
@@ -91,6 +92,7 @@ void nftnl_set_unset(struct nftnl_set *s, uint16_t attr)
 	case NFTNL_SET_DESC_SIZE:
 	case NFTNL_SET_TIMEOUT:
 	case NFTNL_SET_GC_INTERVAL:
+	case NFTNL_SET_USERDATA:
 		break;
 	default:
 		return;
@@ -167,6 +169,10 @@ void nftnl_set_set_data(struct nftnl_set *s, uint16_t attr, const void *data,
 	case NFTNL_SET_GC_INTERVAL:
 		s->gc_interval = *((uint32_t *)data);
 		break;
+	case NFTNL_SET_USERDATA:
+		s->user.data = (void *)data;
+		s->user.len  = data_len;
+		break;
 	}
 	s->flags |= (1 << attr);
 }
@@ -240,6 +246,9 @@ const void *nftnl_set_get_data(struct nftnl_set *s, uint16_t attr,
 	case NFTNL_SET_GC_INTERVAL:
 		*data_len = sizeof(uint32_t);
 		return &s->gc_interval;
+	case NFTNL_SET_USERDATA:
+		*data_len = s->user.len;
+		return s->user.data;
 	}
 	return NULL;
 }
@@ -348,6 +357,8 @@ void nftnl_set_nlmsg_build_payload(struct nlmsghdr *nlh, struct nftnl_set *s)
 		mnl_attr_put_u64(nlh, NFTA_SET_TIMEOUT, htobe64(s->timeout));
 	if (s->flags & (1 << NFTNL_SET_GC_INTERVAL))
 		mnl_attr_put_u32(nlh, NFTA_SET_GC_INTERVAL, htonl(s->gc_interval));
+	if (s->flags & (1 << NFTNL_SET_USERDATA))
+		mnl_attr_put(nlh, NFTA_SET_USERDATA, s->user.len, s->user.data);
 }
 EXPORT_SYMBOL_ALIAS(nftnl_set_nlmsg_build_payload, nft_set_nlmsg_build_payload);
 
@@ -376,6 +387,10 @@ static int nftnl_set_parse_attr_cb(const struct nlattr *attr, void *data)
 		if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
 			abi_breakage();
 		break;
+	case NFTA_SET_USERDATA:
+		if (mnl_attr_validate(attr, MNL_TYPE_BINARY) < 0)
+			abi_breakage();
+		break;
 	case NFTA_SET_TIMEOUT:
 		if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0)
 			abi_breakage();
@@ -480,6 +495,20 @@ int nftnl_set_nlmsg_parse(const struct nlmsghdr *nlh, struct nftnl_set *s)
 		s->gc_interval = ntohl(mnl_attr_get_u32(tb[NFTA_SET_GC_INTERVAL]));
 		s->flags |= (1 << NFTNL_SET_GC_INTERVAL);
 	}
+	if (tb[NFTA_SET_USERDATA]) {
+		const void *udata =
+			mnl_attr_get_payload(tb[NFTA_SET_USERDATA]);
+
+		if (s->user.data)
+			xfree(s->user.data);
+
+		s->user.len  = mnl_attr_get_payload_len(tb[NFTA_SET_USERDATA]);
+		s->user.data = malloc(s->user.len);
+		if (s->user.data == NULL)
+			return -1;
+		memcpy(s->user.data, udata, s->user.len);
+		s->flags |= (1 << NFTNL_SET_USERDATA);
+	}
 	if (tb[NFTA_SET_DESC])
 		ret = nftnl_set_desc_parse(s, tb[NFTA_SET_DESC]);
 
@@ -775,6 +804,7 @@ static int nftnl_set_snprintf_json(char *buf, size_t size, struct nftnl_set *s,
 				  uint32_t type, uint32_t flags)
 {
 	int len = size, offset = 0, ret;
+	int i;
 	struct nftnl_set_elem *elem;
 
 	ret = snprintf(buf, len, "{\"set\":{");
@@ -826,6 +856,26 @@ static int nftnl_set_snprintf_json(char *buf, size_t size, struct nftnl_set *s,
 		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
 	}
 
+	if (s->flags & (1 << NFTNL_SET_USERDATA)) {
+		ret = snprintf(buf + offset, len, ",\"userdata_len\":%u",
+			       s->user.len);
+		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+		ret = snprintf(buf + offset, len, ",\"userdata\":\"");
+		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+
+		char *c = s->user.data;
+
+		for (i = 0; i < s->user.len; i++) {
+			ret = snprintf(buf + offset, len, "%c",
+				       isprint(c[i]) ? c[i] : ' ');
+			SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+		}
+
+		ret = snprintf(buf + offset, len, "\"");
+		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+	}
+
 	if (s->flags & (1 << NFTNL_SET_DESC_SIZE)) {
 		ret = snprintf(buf + offset, len, ",\"desc_size\":%u",
 			       s->desc.size);
-- 
2.6.4

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

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 3/4] libnftnl: set: Implement new buffer of TLV objects.
  2016-01-03 19:38 [PATCH 1/4] nf: netfilter: nf_tables_api: Add new attributes into nft_set to store user data Carlos Falgueras García
  2016-01-03 19:38 ` [PATCH 2/4] libnftnl: set: Add new attribute into 'set' to store an arbitrary length " Carlos Falgueras García
@ 2016-01-03 19:38 ` Carlos Falgueras García
  2016-01-04 12:06   ` Patrick McHardy
  2016-01-03 19:38 ` [PATCH 4/4] libnftnl: examples: Modify the example to allow add TLV objects as user data Carlos Falgueras García
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 7+ messages in thread
From: Carlos Falgueras García @ 2016-01-03 19:38 UTC (permalink / raw)
  To: netfilter-devel; +Cc: pablo, kaber

These functions allow create a buffer (nftnl_attrbuf) of TLV objects
(nftnl_attr). It is inspired in libmnl/src/attr.c.

Signed-off-by: Carlos Falgueras García <carlosfg@riseup.net>
---
 include/libnftnl/set.h | 133 ++++++++++++++++++++
 include/set.h          |  39 ++++++
 src/libnftnl.map       |  47 +++++++
 src/set.c              | 327 +++++++++++++++++++++++++++++++++++++++++++++++--
 4 files changed, 536 insertions(+), 10 deletions(-)

diff --git a/include/libnftnl/set.h b/include/libnftnl/set.h
index 7a5a512..ec15603 100644
--- a/include/libnftnl/set.h
+++ b/include/libnftnl/set.h
@@ -278,4 +278,137 @@ void nft_set_elems_iter_destroy(struct nft_set_elems_iter *iter);
 int nft_set_elems_nlmsg_build_payload_iter(struct nlmsghdr *nlh,
 					   struct nft_set_elems_iter *iter);
 
+/*
+ * nftnl attributes API
+ */
+struct nftnl_attr;
+struct nftnl_attrbuf;
+
+/* nftnl_attrbuf */
+struct nftnl_attrbuf *nftnl_attrbuf_alloc(size_t size);
+void nftnl_attrbuf_delete(struct nftnl_attrbuf *attrbuf);
+void nftnl_attrbuf_free(struct nftnl_attrbuf *attrbuf);
+void nftnl_attrbuf_printf(const struct nftnl_attrbuf *attrbuf);
+size_t nftnl_attrbuf_len(const struct nftnl_attrbuf *attrbuf);
+size_t nftnl_attrbuf_size(const struct nftnl_attrbuf *attrbuf);
+void *nftnl_attrbuf_data(const struct nftnl_attrbuf *attrbuf);
+
+/* TLV attribute getters */
+uint16_t nftnl_attr_get_type(const struct nftnl_attr *attr);
+uint16_t nftnl_attr_get_len(const struct nftnl_attr *attr);
+void *nftnl_attr_get_value(const struct nftnl_attr *attr);
+uint32_t nftnl_attr_get_size(const struct nftnl_attr *attr);
+
+/* TLV attribute putters */
+struct nftnl_attr *nftnl_attr_put(struct nftnl_attrbuf *attrbuf,
+				  uint16_t type, size_t len, const void *data);
+struct nftnl_attr *nftnl_attr_put_check(struct nftnl_attrbuf *attrbuf,
+					size_t bufsize, uint16_t type,
+					size_t len, const void *data);
+
+/* TLV attribute nesting */
+struct nftnl_attr *nftnl_attr_nest_start(struct nftnl_attrbuf *attrbuf,
+					 uint16_t type);
+struct nftnl_attr *nftnl_attr_nest_start_check(struct nftnl_attrbuf *attrbuf,
+					       size_t bufsize, uint16_t type);
+void nftnl_attr_nest_end(struct nftnl_attrbuf *attrbuf,
+			 struct nftnl_attr *start);
+void nftnl_attr_nest_cancel(struct nftnl_attrbuf *attrbuf,
+			    struct nftnl_attr *start);
+
+/* TLV validation */
+enum nftnl_attr_data_type {
+	NFTNL_ATTR_TYPE_UNSPEC,
+	NFTNL_ATTR_TYPE_U8,
+	NFTNL_ATTR_TYPE_U16,
+	NFTNL_ATTR_TYPE_U32,
+	NFTNL_ATTR_TYPE_U64,
+	NFTNL_ATTR_TYPE_STRING,
+	NFTNL_ATTR_TYPE_FLAG,
+	NFTNL_ATTR_TYPE_MSECS,
+	NFTNL_ATTR_TYPE_NESTED,
+	NFTNL_ATTR_TYPE_NESTED_COMPAT,
+	NFTNL_ATTR_TYPE_NUL_STRING,
+	NFTNL_ATTR_TYPE_BINARY,
+	__NFTNL_ATTR_TYPE_MAX,
+};
+#define NFTNL_ATTR_TYPE_MAX (__NFTNL_ATTR_TYPE_MAX - 1)
+
+int nftnl_attr_type_valid(const struct nftnl_attr *attr);
+int nftnl_attr_validate(const struct nftnl_attr *attr);
+int nftnl_attr_validate2(const struct nftnl_attr *attr, size_t exp_len);
+
+/* TLV iterators */
+struct nftnl_attr *nftnl_attr_next(const struct nftnl_attr *attr);
+
+#define nftnl_attr_for_each(attr, attrbuf)                  \
+	for ((attr) = (struct nftnl_attr *)(attrbuf)->data; \
+	     (char *)(attrbuf)->tail > (char *)(attr);      \
+	     (attr) = nftnl_attr_next(attr))
+
+#define nftnl_attr_for_each_nested(attr, nest)                          \
+	for ((attr) = (struct nftnl_attr *)nftnl_attr_get_value(nest);  \
+	     (char *)(attr) - (char *)(nest) < nftnl_attr_get_len(nest);\
+	     (attr) = nftnl_attr_next(attr))
+
+#define nftnl_attr_for_each_payload(attr, payload, payload_len) \
+	for ((attr) = (struct nftnl_attr *)(payload);           \
+	     (char *)(attr) - (char *)(payload) < (payload_len);\
+	     (attr) = nftnl_attr_next(attr))
+
+int nftnl_attr_payload_snprint(const void *payload, size_t payload_len,
+			       char *buf, int bsize);
+/*
+ * Compact
+ */
+struct nft_attr;
+struct nft_attrbuf;
+
+struct nft_attrbuf *nft_attrbuf_alloc(size_t size);
+void nft_attrbuf_delete(struct nft_attrbuf *attrbuf);
+void nft_attrbuf_free(struct nft_attrbuf *attrbuf);
+void nft_attrbuf_printf(const struct nft_attrbuf *attrbuf);
+size_t nft_attrbuf_len(const struct nft_attrbuf *attrbuf);
+size_t nft_attrbuf_size(const struct nft_attrbuf *attrbuf);
+void *nft_attrbuf_data(const struct nft_attrbuf *attrbuf);
+
+/* TLV attribute getters */
+uint16_t nft_attr_get_type(const struct nft_attr *attr);
+uint16_t nft_attr_get_len(const struct nft_attr *attr);
+void *nft_attr_get_value(const struct nft_attr *attr);
+uint16_t nft_attr_get_size(const struct nft_attr *attr);
+
+/* TLV attribute putters */
+struct nft_attr *nft_attr_put(struct nft_attrbuf *attrbuf,
+			      uint16_t type, size_t len, const void *data);
+struct nft_attr *nft_attr_put_check(struct nft_attrbuf *attrbuf,
+				    size_t bufsize, uint16_t type,
+				    size_t len, const void *data);
+
+/* TLV attribute nesting */
+struct nft_attr *nft_attr_nest_start(struct nft_attrbuf *attrbuf,
+				     uint16_t type);
+struct nft_attr *nft_attr_nest_start_check(struct nft_attrbuf *attrbuf,
+					   size_t bufsize, uint16_t type);
+void nft_attr_nest_end(struct nft_attrbuf *attrbuf,
+		       struct nft_attr *start);
+void nft_attr_nest_cancel(struct nft_attrbuf *attrbuf,
+			  struct nft_attr *start);
+
+/* TLV validation */
+int nft_attr_type_valid(const struct nft_attr *attr);
+int nft_attr_validate(const struct nft_attr *attr);
+int nft_attr_validate2(const struct nft_attr *attr, size_t exp_len);
+
+/* TLV iterators */
+struct nft_attr *nft_attr_next(const struct nft_attr *attr);
+
+#define nft_attr_for_each(attr, attrbuf) nftnl_attr_for_each(attr, attrbuf)
+
+#define nft_attr_for_each_nested(attr, nest) \
+	nftnl_attr_for_each_nested(attr, attrbuf)
+
+int nft_attr_payload_snprint(const void *payload, size_t payload_len,
+			     char *buf, int bsize);
+
 #endif /* _LIBNFTNL_SET_H_ */
diff --git a/include/set.h b/include/set.h
index 85bd389..2b5ce98 100644
--- a/include/set.h
+++ b/include/set.h
@@ -35,4 +35,43 @@ struct nftnl_expr;
 int nftnl_set_lookup_id(struct nftnl_expr *e, struct nftnl_set_list *set_list,
 		      uint32_t *set_id);
 
+/*
+ * TLV structures:
+ * nftnl_attr
+ *  <-- sizeof(nftnl_attr) -->             <-- nftnl_attr->len -->
+ * +--------------------------+- - - - - -+- - - - -  -- - - - - -+- - - - - +
+ * |          Header          |  Pading   |       Payload         |  Pading  |
+ * |         (4 bytes)        | (4 bytes) |                       |          |
+ * +--------------------------+- - - - - -+- - - - - - - - - - - -+- - - - - +
+ *  <------------------------ nftnl_attr_get_size() ------------------------>
+ *
+ *
+ * nftnl_attr->type (16 bits)
+ * +---+---+-------------------------------+
+ * | N | O | Attribute Type                |
+ * +---+---+-------------------------------+
+ * N := Carries nested attributes
+ * O := Payload stored in network byte order
+ *
+ * Note: The N and O flag are mutually exclusive.
+ */
+
+struct nftnl_attr {
+	uint16_t type;
+	uint16_t len;
+	unsigned char value[] __aligned(__alignof__(uint64_t));
+};
+
+#define NFTNLA_F_NESTED		(1 << 15)
+#define NFTNLA_F_NET_BYTEORDER	(1 << 14)
+#define NFTNLA_TYPE_MASK	~(NFTNLA_F_NESTED | NFTNLA_F_NET_BYTEORDER)
+
+#define NFTNL_ALIGNTO		8
+#define NFTNL_ALIGN(len)	(((len)+NFTNL_ALIGNTO-1) & ~(NFTNL_ALIGNTO-1))
+
+struct nftnl_attrbuf {
+	struct nftnl_attr *tail;
+	unsigned char data[] __aligned(__alignof__(uint64_t);
+};
+
 #endif
diff --git a/src/libnftnl.map b/src/libnftnl.map
index 2e193b7..80f7ff5 100644
--- a/src/libnftnl.map
+++ b/src/libnftnl.map
@@ -136,6 +136,29 @@ global:
   nft_set_snprintf;
   nft_set_fprintf;
 
+  nft_attrbuf_alloc;
+  nft_attrbuf_delete;
+  nft_attrbuf_free;
+  nft_attrbuf_printf;
+  nft_attrbuf_len;
+  nft_attrbuf_size;
+  nft_attrbuf_data;
+  nft_attr_get_type;
+  nft_attr_get_len;
+  nft_attr_get_value;
+  nft_attr_get_size;
+  nft_attr_put;
+  nft_attr_put_check;
+  nft_attr_nest_start;
+  nft_attr_nest_start_check;
+  nft_attr_nest_end;
+  nft_attr_nest_cancel;
+  nft_attr_type_valid;
+  nft_attr_validate;
+  nft_attr_validate2;
+  nft_attr_next;
+  nft_attr_payload_snprint;
+
   nft_set_list_alloc;
   nft_set_list_free;
   nft_set_list_add;
@@ -336,6 +359,30 @@ global:
   nftnl_set_snprintf;
   nftnl_set_fprintf;
 
+  nftnl_attrbuf_alloc;
+  nftnl_attrbuf_delete;
+  nftnl_attrbuf_free;
+  nftnl_attrbuf_printf;
+  nftnl_attrbuf_len;
+  nftnl_attrbuf_size;
+  nftnl_attrbuf_data;
+  nftnl_attr_get_type;
+  nftnl_attr_get_len;
+  nftnl_attr_get_value;
+  nftnl_attr_get_size;
+  nftnl_attr_put;
+  nftnl_attr_put_check;
+  nftnl_attr_nest_start;
+  nftnl_attr_nest_start_check;
+  nftnl_attr_nest_end;
+  nftnl_attr_nest_cancel;
+  nftnl_attr_type_valid;
+  nftnl_attr_validate;
+  nftnl_attr_validate2;
+  nftnl_attr_next;
+  nftnl_attr_payload_snprint;
+
+
   nftnl_set_list_alloc;
   nftnl_set_list_free;
   nftnl_set_list_add;
diff --git a/src/set.c b/src/set.c
index 315bced..b9031e1 100644
--- a/src/set.c
+++ b/src/set.c
@@ -28,6 +28,12 @@
 #include <libnftnl/set.h>
 #include <libnftnl/expr.h>
 
+#define ATTRBUF_ENOUGH_SIZE(attrbuf, bufsize, attr_len) ( \
+	(bufsize) >= \
+		NFTNL_ALIGN(attr_len) + \
+		sizeof(struct nftnl_attr) + \
+		nftnl_attrbuf_len(attrbuf))
+
 struct nftnl_set *nftnl_set_alloc(void)
 {
 	struct nftnl_set *s;
@@ -804,7 +810,6 @@ static int nftnl_set_snprintf_json(char *buf, size_t size, struct nftnl_set *s,
 				  uint32_t type, uint32_t flags)
 {
 	int len = size, offset = 0, ret;
-	int i;
 	struct nftnl_set_elem *elem;
 
 	ret = snprintf(buf, len, "{\"set\":{");
@@ -861,18 +866,14 @@ static int nftnl_set_snprintf_json(char *buf, size_t size, struct nftnl_set *s,
 			       s->user.len);
 		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
 
-		ret = snprintf(buf + offset, len, ",\"userdata\":\"");
+		ret = snprintf(buf + offset, len, ",\"userdata\":[");
 		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
 
-		char *c = s->user.data;
-
-		for (i = 0; i < s->user.len; i++) {
-			ret = snprintf(buf + offset, len, "%c",
-				       isprint(c[i]) ? c[i] : ' ');
-			SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-		}
+		ret = nftnl_attr_payload_snprint(s->user.data, s->user.len,
+						 buf + offset, len);
+		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
 
-		ret = snprintf(buf + offset, len, "\"");
+		ret = snprintf(buf + offset, len, "]");
 		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
 	}
 
@@ -1270,3 +1271,309 @@ int nftnl_set_lookup_id(struct nftnl_expr *e,
 	*set_id = nftnl_set_get_u32(s, NFTNL_SET_ID);
 	return 1;
 }
+
+/* TLV */
+struct nftnl_attrbuf *nftnl_attrbuf_alloc(size_t size)
+{
+	struct nftnl_attrbuf *attrbuf;
+
+	attrbuf =
+		(struct nftnl_attrbuf *)malloc(sizeof(struct nftnl_attrbuf) +
+					       size
+					      );
+	attrbuf->tail = (struct nftnl_attr *)attrbuf->data;
+
+	return attrbuf;
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attrbuf_alloc, nft_attrbuf_alloc);
+
+void nftnl_attrbuf_delete(struct nftnl_attrbuf *attrbuf)
+{
+	attrbuf->tail = (struct nftnl_attr *)attrbuf->data;
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attrbuf_delete, nft_attrbuf_delete);
+
+void nftnl_attrbuf_free(struct nftnl_attrbuf *attrbuf)
+{
+	nftnl_attrbuf_delete(attrbuf);
+	free((void *)attrbuf);
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attrbuf_free, nft_attrbuf_free);
+
+size_t nftnl_attrbuf_len(const struct nftnl_attrbuf *attrbuf)
+{
+	return (size_t)((char *)attrbuf->tail - (char *)attrbuf->data);
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attrbuf_len, nft_attrbuf_len);
+
+size_t nftnl_attrbuf_size(const struct nftnl_attrbuf *attrbuf)
+{
+	return (size_t)((char *)attrbuf->tail - (char *)attrbuf);
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attrbuf_size, nft_attrbuf_size);
+
+void *nftnl_attrbuf_data(const struct nftnl_attrbuf *attrbuf)
+{
+	return (void *)attrbuf->data;
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attrbuf_data, nft_attrbuf_data);
+
+uint16_t nftnl_attr_get_type(const struct nftnl_attr *attr)
+{
+	return attr->type;
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attr_get_type, nft_attr_get_type);
+
+uint16_t nftnl_attr_get_len(const struct nftnl_attr *attr)
+{
+	return attr->len;
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attr_get_len, nft_attr_get_len);
+
+void *nftnl_attr_get_value(const struct nftnl_attr *attr)
+{
+	return (void *)attr->value;
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attr_get_value, nft_attr_get_value);
+
+uint32_t nftnl_attr_get_size(const struct nftnl_attr *attr)
+{
+	return (char *)nftnl_attr_next(attr) - (char *)attr;
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attr_get_size, nft_attr_get_size);
+
+struct nftnl_attr *nftnl_attr_put(struct nftnl_attrbuf *attrbuf,
+				  uint16_t type, size_t len, const void *data)
+{
+	struct nftnl_attr *attr = attrbuf->tail;
+
+	attr->len  = len;
+	attr->type = type;
+	memcpy(attr->value, data, len);
+
+	attrbuf->tail = nftnl_attr_next(attr);
+
+	return attr;
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attr_put, nft_attr_put);
+
+struct nftnl_attr *nftnl_attr_put_check(struct nftnl_attrbuf *attrbuf,
+					size_t bufsize, uint16_t type,
+					size_t len, const void *data)
+{
+	if (!ATTRBUF_ENOUGH_SIZE(attrbuf, bufsize, len))
+		return NULL;
+	return nftnl_attr_put(attrbuf, type, len, data);
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attr_put_check, nft_attr_put_check);
+
+struct nftnl_attr *nftnl_attr_nest_start(struct nftnl_attrbuf *attrbuf,
+					 uint16_t type)
+{
+	struct nftnl_attr *start;
+
+	start = attrbuf->tail;
+	start->len = 0;
+	start->type = NFTNLA_F_NESTED | type;
+
+	attrbuf->tail = nftnl_attr_next(attrbuf->tail);
+
+	return start;
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attr_nest_start, nft_attr_nest_start);
+
+struct nftnl_attr *nftnl_attr_nest_start_check(struct nftnl_attrbuf *attrbuf,
+					       size_t bufsize, uint16_t type)
+{
+	if (!ATTRBUF_ENOUGH_SIZE(attrbuf, bufsize, 0))
+		return NULL;
+	return nftnl_attr_nest_start(attrbuf, type);
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attr_nest_start_check, nft_attr_nest_start_check);
+
+void nftnl_attr_nest_end(struct nftnl_attrbuf *attrbuf,
+			 struct nftnl_attr *start)
+{
+	start->len = (char *)attrbuf->tail - (char *)start->value;
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attr_nest_end, nft_attr_nest_end);
+
+int nftnl_attr_type_valid(const struct nftnl_attr *attr)
+{
+	if (nftnl_attr_get_type(attr) > NFTNL_ATTR_TYPE_MAX) {
+		errno = EINVAL;
+		return -1;
+	}
+	return 1;
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attr_type_valid, nft_attr_type_valid);
+
+static const size_t nftnl_attr_data_type_len[MNL_TYPE_MAX] = {
+	[NFTNL_ATTR_TYPE_U8]	= sizeof(uint8_t),
+	[NFTNL_ATTR_TYPE_U16]	= sizeof(uint16_t),
+	[NFTNL_ATTR_TYPE_U32]	= sizeof(uint32_t),
+	[NFTNL_ATTR_TYPE_U64]	= sizeof(uint64_t),
+	[NFTNL_ATTR_TYPE_MSECS]	= sizeof(uint64_t),
+};
+
+int nftnl_attr_validate(const struct nftnl_attr *attr)
+{
+	int exp_len;
+
+	exp_len = nftnl_attr_data_type_len[nftnl_attr_get_type(attr)];
+	return nftnl_attr_validate2(attr, exp_len);
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attr_validate, nft_attr_validate);
+
+int nftnl_attr_validate2(const struct nftnl_attr *attr, size_t exp_len)
+{
+	uint16_t type = nftnl_attr_get_type(attr);
+	uint16_t len = nftnl_attr_get_len(attr);
+	const char *val = nftnl_attr_get_value(attr);
+
+	if (len != exp_len) {
+		errno = ERANGE;
+		return -1;
+	}
+
+	switch (type) {
+	case MNL_TYPE_FLAG:
+		if (len > 0) {
+			errno = ERANGE;
+			return -1;
+		}
+		break;
+	case MNL_TYPE_NUL_STRING:
+		if (len == 0) {
+			errno = ERANGE;
+			return -1;
+		}
+		if (val[len-1] != '\0') {
+			errno = EINVAL;
+			return -1;
+		}
+		break;
+	case MNL_TYPE_STRING:
+		if (len == 0) {
+			errno = ERANGE;
+			return -1;
+		}
+		break;
+	case MNL_TYPE_NESTED:
+		/*
+		 * Empty nested attributes are OK. If not empty,
+		 * they must contain one header
+		 */
+		if (len > 0 && len < sizeof(struct nftnl_attr)) {
+			errno = ERANGE;
+			return -1;
+		}
+		break;
+	default:
+		if (!nftnl_attr_type_valid(attr))
+			return -1;
+		break;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attr_validate2, nft_attr_validate2);
+
+void nftnl_attr_nest_cancel(struct nftnl_attrbuf *attrbuf,
+			    struct nftnl_attr *start)
+{
+	attrbuf->tail = start;
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attr_nest_cancel, nft_attr_nest_cancel);
+
+struct nftnl_attr *nftnl_attr_next(const struct nftnl_attr *attr)
+{
+	return (struct nftnl_attr *)&attr->value[NFTNL_ALIGN(attr->len)];
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attr_next, nft_attr_next);
+
+static int __attr_snprint(const struct nftnl_attr *attr,
+			char *buf, size_t bsize)
+{
+	int i;
+	int written, blen, boffset;
+	uint16_t alen;
+	char *aval;
+	struct nftnl_attr *pattr;
+
+	written = 0;
+	boffset = 0;
+	blen = bsize;
+	alen = nftnl_attr_get_len(attr);
+	aval = (char *)nftnl_attr_get_value(attr);
+
+
+	/* type */
+	written = snprintf(buf + boffset, blen, "{\"type\":%u,",
+			   nftnl_attr_get_type(attr));
+	SNPRINTF_BUFFER_SIZE(written, bsize, blen, boffset);
+
+	/* len */
+	written = snprintf(buf + boffset, blen, "\"len\":%u,", alen);
+	SNPRINTF_BUFFER_SIZE(written, bsize, blen, boffset);
+
+	/* value as string */
+	written = snprintf(buf + boffset, blen, "\"val\":");
+	SNPRINTF_BUFFER_SIZE(written, bsize, blen, boffset);
+
+	if (attr->type & NFTNLA_F_NESTED) {
+		written = snprintf(buf + boffset, blen, "[");
+		SNPRINTF_BUFFER_SIZE(written, bsize, blen, boffset);
+
+		nftnl_attr_for_each_nested(pattr, attr) {
+			written = __attr_snprint(pattr, buf + boffset, blen);
+			SNPRINTF_BUFFER_SIZE(written, bsize, blen, boffset);
+
+			written = snprintf(buf + boffset, blen, ",");
+			SNPRINTF_BUFFER_SIZE(written, bsize, blen, boffset);
+		}
+		boffset--; /* delete last comma */
+
+		written = snprintf(buf + boffset, blen, "]");
+		SNPRINTF_BUFFER_SIZE(written, bsize, blen, boffset);
+	} else {
+		written = snprintf(buf + boffset, blen, "\"");
+		SNPRINTF_BUFFER_SIZE(written, bsize, blen, boffset);
+
+		for (i = 0; i < alen; i++) {
+			written = snprintf(buf + boffset, blen, "%c",
+					   isprint(aval[i]) ? aval[i] : ' ');
+			SNPRINTF_BUFFER_SIZE(written, bsize, blen, boffset);
+		}
+
+		written = snprintf(buf + boffset, blen, "\"");
+		SNPRINTF_BUFFER_SIZE(written, bsize, blen, boffset);
+	}
+
+	written = snprintf(buf + boffset, blen, "}");
+	SNPRINTF_BUFFER_SIZE(written, bsize, blen, boffset);
+
+	return boffset;
+}
+
+int nftnl_attr_payload_snprint(const void *payload, size_t payload_len,
+			       char *buf, int bsize)
+{
+	struct nftnl_attr *attr;
+	int written, blen, boffset;
+
+	written = 0;
+	boffset = 0;
+	blen = bsize;
+
+	nftnl_attr_for_each_payload(attr, payload, payload_len) {
+		written = __attr_snprint(attr, buf + boffset, blen);
+		SNPRINTF_BUFFER_SIZE(written, bsize, blen, boffset);
+
+		written = snprintf(buf + boffset, blen, ",");
+		SNPRINTF_BUFFER_SIZE(written, bsize, blen, boffset);
+	}
+
+	return boffset-1; /* delete last comma */
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attr_payload_snprint, nft_attr_payload_snprint);
-- 
2.6.4

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

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 4/4] libnftnl: examples: Modify the example to allow add TLV objects as user data.
  2016-01-03 19:38 [PATCH 1/4] nf: netfilter: nf_tables_api: Add new attributes into nft_set to store user data Carlos Falgueras García
  2016-01-03 19:38 ` [PATCH 2/4] libnftnl: set: Add new attribute into 'set' to store an arbitrary length " Carlos Falgueras García
  2016-01-03 19:38 ` [PATCH 3/4] libnftnl: set: Implement new buffer of TLV objects Carlos Falgueras García
@ 2016-01-03 19:38 ` Carlos Falgueras García
  2016-01-04 12:32 ` [PATCH 1/4] nf: netfilter: nf_tables_api: Add new attributes into nft_set to store " Patrick McHardy
  2016-01-05 10:34 ` Pablo Neira Ayuso
  4 siblings, 0 replies; 7+ messages in thread
From: Carlos Falgueras García @ 2016-01-03 19:38 UTC (permalink / raw)
  To: netfilter-devel; +Cc: pablo, kaber

Example usage:
	> nft add table mytable
	> exmample/nft-set-add ip mytable myset "5:my data 0" "5:my data 1"
	> example/nft-set-get ip json | jq #jq: https://stedolan.github.io/jq/
	{
	  "set": {
	    "name": "myset",
	    "table": "mytable",
	    "flags": 2,
	    "family": "ip",
	    "key_type": 0,
	    "key_len": 2,
	    "userdata_len": 48,
	    "userdata": [
	      {
		"type": 5,
		"len": 9,
		"val": "my data 0"
	      },
	      {
		"type": 5,
		"len": 9,
		"val": "my data 1"
	      }
	    ]
	  }
	}

Signed-off-by: Carlos Falgueras García <carlosfg@riseup.net>
---
 examples/nft-set-add.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 49 insertions(+), 4 deletions(-)

diff --git a/examples/nft-set-add.c b/examples/nft-set-add.c
index e040aca..42ff3c8 100644
--- a/examples/nft-set-add.c
+++ b/examples/nft-set-add.c
@@ -28,8 +28,14 @@
 #include <libmnl/libmnl.h>
 #include <libnftnl/set.h>
 
+#define ATTRBUF_SIZE 256
+
+static bool parse_user_data(char *argv[], int argc,
+			    struct nftnl_attrbuf *attrbuf);
+
 static struct nftnl_set *setup_set(uint8_t family, const char *table,
-				 const char *name)
+				 const char *name, const char *udata,
+				 unsigned int udlen)
 {
 	struct nftnl_set *s = NULL;
 
@@ -44,6 +50,8 @@ static struct nftnl_set *setup_set(uint8_t family, const char *table,
 	nftnl_set_set_u32(s, NFTNL_SET_FAMILY, family);
 	nftnl_set_set_u32(s, NFTNL_SET_KEY_LEN, 2);
 	nftnl_set_set_u32(s, NFTNL_SET_ID, 1);
+	if (udata != NULL)
+		nftnl_set_set_data(s, NFTNL_SET_USERDATA, udata, udlen);
 	nftnl_set_set_u32(s, NFTNL_SET_FLAGS, NFT_SET_CONSTANT);
 
 	return s;
@@ -71,13 +79,17 @@ int main(int argc, char *argv[])
 	struct nftnl_set *s;
 	struct nlmsghdr *nlh;
 	struct mnl_nlmsg_batch *batch;
+	struct nftnl_attrbuf *attrbuf = NULL;
 	uint8_t family;
 	char buf[MNL_SOCKET_BUFFER_SIZE];
 	uint32_t seq = time(NULL);
 	int ret;
 
-	if (argc != 4) {
-		fprintf(stderr, "Usage: %s <family> <table> <setname>\n", argv[0]);
+	if (argc < 4) {
+		fprintf(stderr,
+			"Usage: %s <family> <table> <setname> [<type:user_data>[ <type:user_data>...]]\n",
+			argv[0]
+		);
 		exit(EXIT_FAILURE);
 	}
 
@@ -94,7 +106,21 @@ int main(int argc, char *argv[])
 		exit(EXIT_FAILURE);
 	}
 
-	s = setup_set(family, argv[2], argv[3]);
+	if (argc >= 5) {
+		attrbuf = nftnl_attrbuf_alloc(ATTRBUF_SIZE);
+		if (!parse_user_data(argv, argc, attrbuf)) {
+			fprintf(stderr, "Error parsing user data\n");
+			free(attrbuf);
+			return EXIT_FAILURE;
+		}
+
+		s = setup_set(family, argv[2], argv[3],
+			      (char *)nftnl_attrbuf_data(attrbuf),
+			      nftnl_attrbuf_len(attrbuf)
+			     );
+	} else {
+		s = setup_set(family, argv[2], argv[3], NULL, 0);
+	}
 
 	nl = mnl_socket_open(NETLINK_NETFILTER);
 	if (nl == NULL) {
@@ -147,6 +173,25 @@ int main(int argc, char *argv[])
 	}
 
 	mnl_socket_close(nl);
+	if (attrbuf)
+		free(attrbuf);
 
 	return EXIT_SUCCESS;
 }
+
+static bool parse_user_data(char *argv[], int argc,
+			    struct nftnl_attrbuf *attrbuf)
+{
+	int i;
+	char *type, *value;
+
+	for (i = 4; i < argc; i++) {
+		type = strchr(argv[i], ':') - 1;
+		value = type + 2;
+		if (!nftnl_attr_put_check(attrbuf, ATTRBUF_SIZE, atoi(type),
+					  strlen(value), value))
+			return false;
+	}
+
+	return true;
+}
-- 
2.6.4

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

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH 3/4] libnftnl: set: Implement new buffer of TLV objects.
  2016-01-03 19:38 ` [PATCH 3/4] libnftnl: set: Implement new buffer of TLV objects Carlos Falgueras García
@ 2016-01-04 12:06   ` Patrick McHardy
  0 siblings, 0 replies; 7+ messages in thread
From: Patrick McHardy @ 2016-01-04 12:06 UTC (permalink / raw)
  To: Carlos Falgueras García; +Cc: netfilter-devel, pablo

On 03.01, Carlos Falgueras García wrote:
> +/* TLV validation */
> +enum nftnl_attr_data_type {
> +	NFTNL_ATTR_TYPE_UNSPEC,
> +	NFTNL_ATTR_TYPE_U8,
> +	NFTNL_ATTR_TYPE_U16,
> +	NFTNL_ATTR_TYPE_U32,
> +	NFTNL_ATTR_TYPE_U64,
> +	NFTNL_ATTR_TYPE_STRING,
> +	NFTNL_ATTR_TYPE_FLAG,
> +	NFTNL_ATTR_TYPE_MSECS,
> +	NFTNL_ATTR_TYPE_NESTED,
> +	NFTNL_ATTR_TYPE_NESTED_COMPAT,
> +	NFTNL_ATTR_TYPE_NUL_STRING,
> +	NFTNL_ATTR_TYPE_BINARY,
> +	__NFTNL_ATTR_TYPE_MAX,

We don't need quite a few of these. Compat is obviously unnecessary. Same thing
goes for MSECS and NUL_STRING since the kernel doesn't do interpretation of
the user data. FLAG I would avoid since it uses a full u8, so better have
userspace simply use that and do interpretation as a flag.

> +/*
> + * TLV structures:
> + * nftnl_attr
> + *  <-- sizeof(nftnl_attr) -->             <-- nftnl_attr->len -->
> + * +--------------------------+- - - - - -+- - - - -  -- - - - - -+- - - - - +
> + * |          Header          |  Pading   |       Payload         |  Pading  |
> + * |         (4 bytes)        | (4 bytes) |                       |          |
> + * +--------------------------+- - - - - -+- - - - - - - - - - - -+- - - - - +
> + *  <------------------------ nftnl_attr_get_size() ------------------------>

We don't need a header I'd think. Just the raw attributes.

> + * nftnl_attr->type (16 bits)
> + * +---+---+-------------------------------+
> + * | N | O | Attribute Type                |
> + * +---+---+-------------------------------+
> + * N := Carries nested attributes
> + * O := Payload stored in network byte order
> + *
> + * Note: The N and O flag are mutually exclusive.
> + */
> +
> +struct nftnl_attr {
> +	uint16_t type;
> +	uint16_t len;

u16 is too large for both. Our maximum length is 256 anyways, without the
header u8 is enough. For type I'd also say u8 should be enough, especially
when considering the very limited space.

> +#define NFTNLA_F_NESTED		(1 << 15)
> +#define NFTNLA_F_NET_BYTEORDER	(1 << 14)
> +#define NFTNLA_TYPE_MASK	~(NFTNLA_F_NESTED | NFTNLA_F_NET_BYTEORDER)

Also unnecessary since the kernel doesn't do interpretation.

> +#define NFTNL_ALIGNTO		8
> +#define NFTNL_ALIGN(len)	(((len)+NFTNL_ALIGNTO-1) & ~(NFTNL_ALIGNTO-1))

I'd at least consider whether we really want this or whether userspace should
do an unconditional copy to avoid unaligned accesses. We have very limited
space and should try to pack tightly.
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/4] nf: netfilter: nf_tables_api: Add new attributes into nft_set to store user data.
  2016-01-03 19:38 [PATCH 1/4] nf: netfilter: nf_tables_api: Add new attributes into nft_set to store user data Carlos Falgueras García
                   ` (2 preceding siblings ...)
  2016-01-03 19:38 ` [PATCH 4/4] libnftnl: examples: Modify the example to allow add TLV objects as user data Carlos Falgueras García
@ 2016-01-04 12:32 ` Patrick McHardy
  2016-01-05 10:34 ` Pablo Neira Ayuso
  4 siblings, 0 replies; 7+ messages in thread
From: Patrick McHardy @ 2016-01-04 12:32 UTC (permalink / raw)
  To: Carlos Falgueras García; +Cc: netfilter-devel, pablo

On 03.01, Carlos Falgueras García wrote:
> @@ -2704,6 +2709,8 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
>  	u64 timeout;
>  	u32 ktype, dtype, flags, policy, gc_int;
>  	struct nft_set_desc desc;
> +	unsigned char udlen;

This will overflow at size 256. Please use an explicitly sized type (u16).

> +	unsigned char *udata;
>  	int err;
>  
>  	if (nla[NFTA_SET_TABLE] == NULL ||
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/4] nf: netfilter: nf_tables_api: Add new attributes into nft_set to store user data.
  2016-01-03 19:38 [PATCH 1/4] nf: netfilter: nf_tables_api: Add new attributes into nft_set to store user data Carlos Falgueras García
                   ` (3 preceding siblings ...)
  2016-01-04 12:32 ` [PATCH 1/4] nf: netfilter: nf_tables_api: Add new attributes into nft_set to store " Patrick McHardy
@ 2016-01-05 10:34 ` Pablo Neira Ayuso
  4 siblings, 0 replies; 7+ messages in thread
From: Pablo Neira Ayuso @ 2016-01-05 10:34 UTC (permalink / raw)
  To: Carlos Falgueras García; +Cc: netfilter-devel, kaber

On Sun, Jan 03, 2016 at 08:38:17PM +0100, Carlos Falgueras García wrote:
> @@ -2816,12 +2823,16 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
>  	if (IS_ERR(ops))
>  		return PTR_ERR(ops);
>  
> +	udlen = 0;
> +	if (nla[NFTA_SET_USERDATA])
> +		udlen = nla_len(nla[NFTA_SET_USERDATA]);
> +
>  	size = 0;
>  	if (ops->privsize != NULL)
>  		size = ops->privsize(nla);
>  
>  	err = -ENOMEM;
> -	set = kzalloc(sizeof(*set) + size, GFP_KERNEL);
> +	set = kzalloc(sizeof(*set) + size + udlen, GFP_KERNEL);
>  	if (set == NULL)
>  		goto err1;
>  
> @@ -2830,6 +2841,12 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
>  	if (err < 0)
>  		goto err2;
>  
> +	udata = NULL;
> +	if (nla[NFTA_SET_USERDATA]) {

I think this should be:

        if (udlen)

instead, to ignore zero length user data.

> +		udata = set->data + size;
> +		nla_memcpy(udata, nla[NFTA_SET_USERDATA], udlen);
> +	}
> +
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2016-01-05 10:34 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-01-03 19:38 [PATCH 1/4] nf: netfilter: nf_tables_api: Add new attributes into nft_set to store user data Carlos Falgueras García
2016-01-03 19:38 ` [PATCH 2/4] libnftnl: set: Add new attribute into 'set' to store an arbitrary length " Carlos Falgueras García
2016-01-03 19:38 ` [PATCH 3/4] libnftnl: set: Implement new buffer of TLV objects Carlos Falgueras García
2016-01-04 12:06   ` Patrick McHardy
2016-01-03 19:38 ` [PATCH 4/4] libnftnl: examples: Modify the example to allow add TLV objects as user data Carlos Falgueras García
2016-01-04 12:32 ` [PATCH 1/4] nf: netfilter: nf_tables_api: Add new attributes into nft_set to store " Patrick McHardy
2016-01-05 10:34 ` Pablo Neira Ayuso

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.