diff mbox series

[libnftnl,1/2] expr: add jool support

Message ID 20200407180050.19095-1-ydahhrk@gmail.com
State RFC
Delegated to: Pablo Neira
Headers show
Series [libnftnl,1/2] expr: add jool support | expand

Commit Message

Alberto Leiva April 7, 2020, 6 p.m. UTC
Jool statements are used to send packets to the Jool kernel module,
which is an IP/ICMP translator: www.jool.mx

This feature was requested in Jool's bug tracker:
https://github.com/NICMx/Jool/issues/285

Signed-off-by: Alberto Leiva Popper <ydahhrk@gmail.com>
---
 include/libnftnl/expr.h |   5 ++
 src/Makefile.am         |   1 +
 src/expr/jool.c         | 193 ++++++++++++++++++++++++++++++++++++++++
 src/expr_ops.c          |   2 +
 4 files changed, 201 insertions(+)
 create mode 100644 src/expr/jool.c
diff mbox series

Patch

diff --git a/include/libnftnl/expr.h b/include/libnftnl/expr.h
index cfe456d..5349e15 100644
--- a/include/libnftnl/expr.h
+++ b/include/libnftnl/expr.h
@@ -299,6 +299,11 @@  enum {
 	NFTNL_EXPR_SYNPROXY_FLAGS,
 };
 
+enum {
+	NFTNL_EXPR_JOOL_TYPE	= NFTNL_EXPR_BASE,
+	NFTNL_EXPR_JOOL_INSTANCE,
+};
+
 #ifdef __cplusplus
 } /* extern "C" */
 #endif
diff --git a/src/Makefile.am b/src/Makefile.am
index 90b1967..2c1c964 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -57,6 +57,7 @@  libnftnl_la_SOURCES = utils.c		\
 		      expr/hash.c	\
 		      expr/socket.c	\
 		      expr/synproxy.c	\
+		      expr/jool.c	\
 		      expr/osf.c	\
 		      expr/xfrm.c	\
 		      obj/counter.c	\
diff --git a/src/expr/jool.c b/src/expr/jool.c
new file mode 100644
index 0000000..bd680c7
--- /dev/null
+++ b/src/expr/jool.c
@@ -0,0 +1,193 @@ 
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <linux/netfilter/nf_tables.h>
+
+#include "internal.h"
+#include <libmnl/libmnl.h>
+#include <libnftnl/expr.h>
+#include <libnftnl/rule.h>
+
+enum nft_jool_attributes {
+	NFTA_JOOL_UNSPEC,
+	NFTA_JOOL_TYPE,
+	NFTA_JOOL_INSTANCE,
+	__NFTA_JOOL_MAX,
+};
+
+#define NFTA_JOOL_MAX (__NFTA_JOOL_MAX - 1)
+
+struct nftnl_expr_jool {
+	const char		*instance;
+	uint8_t			type;
+};
+
+#define XT_SIIT		(1 << 0)
+#define XT_NAT64	(1 << 1)
+
+static int
+nftnl_expr_jool_set(struct nftnl_expr *e, uint16_t type,
+		    const void *data, uint32_t data_len)
+{
+	struct nftnl_expr_jool *jool = nftnl_expr_data(e);
+
+	switch(type) {
+	case NFTNL_EXPR_JOOL_TYPE:
+		memcpy(&jool->type, data, sizeof(jool->type));
+		break;
+	case NFTNL_EXPR_JOOL_INSTANCE:
+		jool->instance = strdup(data);
+		if (!jool->instance)
+			return -1;
+		break;
+	default:
+		return -1;
+	}
+	return 0;
+}
+
+static const void *
+nftnl_expr_jool_get(const struct nftnl_expr *e, uint16_t type,
+		    uint32_t *data_len)
+{
+	struct nftnl_expr_jool *jool = nftnl_expr_data(e);
+
+	switch(type) {
+	case NFTNL_EXPR_JOOL_TYPE:
+		*data_len = sizeof(jool->type);
+		return &jool->type;
+	case NFTNL_EXPR_JOOL_INSTANCE:
+		*data_len = strlen(jool->instance) + 1;
+		return jool->instance;
+	}
+	return NULL;
+}
+
+static int
+nftnl_expr_jool_cb(const struct nlattr *attr, void *data)
+{
+	const struct nlattr **tb = data;
+	int type = mnl_attr_get_type(attr);
+
+	if (mnl_attr_type_valid(attr, NFTA_JOOL_MAX) < 0)
+		return MNL_CB_OK;
+
+	switch(type) {
+	case NFTNL_EXPR_JOOL_TYPE:
+		if (mnl_attr_validate(attr, MNL_TYPE_U8) < 0)
+			abi_breakage();
+		break;
+	case NFTNL_EXPR_JOOL_INSTANCE:
+		if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
+			abi_breakage();
+		break;
+	}
+
+	tb[type] = attr;
+	return MNL_CB_OK;
+}
+
+static void
+nftnl_expr_jool_build(struct nlmsghdr *nlh, const struct nftnl_expr *e)
+{
+	struct nftnl_expr_jool *jool = nftnl_expr_data(e);
+
+	if (e->flags & (1 << NFTNL_EXPR_JOOL_TYPE))
+		mnl_attr_put_u8(nlh, NFTA_JOOL_TYPE, jool->type);
+	if (e->flags & (1 << NFTNL_EXPR_JOOL_INSTANCE))
+		mnl_attr_put_strz(nlh, NFTA_JOOL_INSTANCE, jool->instance);
+}
+
+static int
+nftnl_expr_jool_parse(struct nftnl_expr *e, struct nlattr *attr)
+{
+	struct nftnl_expr_jool *jool = nftnl_expr_data(e);
+	struct nlattr *tb[NFTA_JOOL_MAX+1] = {};
+
+	if (mnl_attr_parse_nested(attr, nftnl_expr_jool_cb, tb) < 0)
+		return -1;
+
+	if (tb[NFTA_JOOL_TYPE]) {
+		jool->type = mnl_attr_get_u8(tb[NFTA_JOOL_TYPE]);
+		e->flags |= (1 << NFTNL_EXPR_JOOL_TYPE);
+	}
+	if (tb[NFTA_JOOL_INSTANCE]) {
+		jool->instance =
+			strdup(mnl_attr_get_str(tb[NFTA_JOOL_INSTANCE]));
+		if (!jool->instance)
+			return -1;
+		e->flags |= (1 << NFTNL_EXPR_JOOL_INSTANCE);
+	}
+
+	return 0;
+}
+
+static const char *jt2str(uint8_t xt)
+{
+	switch (xt) {
+	case XT_SIIT:
+		return "siit";
+	case XT_NAT64:
+		return "nat64";
+	default:
+		return "unknown";
+	}
+}
+
+static int
+nftnl_expr_jool_snprintf_default(char *buf, size_t size,
+				 const struct nftnl_expr *e)
+{
+	struct nftnl_expr_jool *jool = nftnl_expr_data(e);
+	int ret, remain = size, offset = 0;
+
+	if (nftnl_expr_is_set(e, NFTNL_EXPR_JOOL_TYPE)) {
+		ret = snprintf(buf + offset, remain, "type %s ",
+			       jt2str(jool->type));
+		SNPRINTF_BUFFER_SIZE(ret, remain, offset);
+	}
+
+	if (e->flags & (1 << NFTNL_EXPR_JOOL_INSTANCE)) {
+		ret = snprintf(buf, size, "instance %s ", jool->instance);
+		SNPRINTF_BUFFER_SIZE(ret, remain, offset);
+	}
+
+	return offset;
+}
+
+static int
+nftnl_expr_jool_snprintf(char *buf, size_t len, uint32_t type,
+			 uint32_t flags, const struct nftnl_expr *e)
+{
+	switch(type) {
+	case NFTNL_OUTPUT_DEFAULT:
+		return nftnl_expr_jool_snprintf_default(buf, len, e);
+	case NFTNL_OUTPUT_XML:
+	case NFTNL_OUTPUT_JSON:
+	default:
+		break;
+	}
+	return -1;
+}
+
+static void
+nftnl_expr_jool_free(const struct nftnl_expr *e)
+{
+	struct nftnl_expr_jool *jool = nftnl_expr_data(e);
+
+	xfree(jool->instance);
+}
+
+struct expr_ops expr_ops_jool = {
+	.name		= "jool",
+	.alloc_len	= sizeof(struct nftnl_expr_jool),
+	.max_attr	= NFTA_JOOL_MAX,
+	.free		= nftnl_expr_jool_free,
+	.set		= nftnl_expr_jool_set,
+	.get		= nftnl_expr_jool_get,
+	.parse		= nftnl_expr_jool_parse,
+	.build		= nftnl_expr_jool_build,
+	.snprintf	= nftnl_expr_jool_snprintf,
+};
diff --git a/src/expr_ops.c b/src/expr_ops.c
index 3538dd6..80b9a86 100644
--- a/src/expr_ops.c
+++ b/src/expr_ops.c
@@ -38,6 +38,7 @@  extern struct expr_ops expr_ops_fib;
 extern struct expr_ops expr_ops_flow;
 extern struct expr_ops expr_ops_socket;
 extern struct expr_ops expr_ops_synproxy;
+extern struct expr_ops expr_ops_jool;
 extern struct expr_ops expr_ops_tunnel;
 extern struct expr_ops expr_ops_osf;
 extern struct expr_ops expr_ops_xfrm;
@@ -82,6 +83,7 @@  static struct expr_ops *expr_ops[] = {
 	&expr_ops_flow,
 	&expr_ops_socket,
 	&expr_ops_synproxy,
+	&expr_ops_jool,
 	&expr_ops_tunnel,
 	&expr_ops_osf,
 	&expr_ops_xfrm,