@@ -3,6 +3,7 @@ SUBDIRS = libnftnl linux
noinst_HEADERS = internal.h \
linux_list.h \
data_reg.h \
+ desc.h \
expr_ops.h \
obj.h \
linux_list.h \
new file mode 100644
@@ -0,0 +1,19 @@
+#ifndef _LIBNFTNL_DESC_INTERNAL_H_
+#define _LIBNFTNL_DESC_INTERNAL_H_
+
+struct nftnl_expr_desc {
+ uint32_t etype;
+ uint32_t byteorder;
+ uint32_t len;
+
+ struct expr_ops *ops;
+
+ union {
+ struct {
+ uint32_t desc_id;
+ uint32_t type;
+ } payload;
+ };
+};
+
+#endif
@@ -2,14 +2,19 @@
#define _EXPR_OPS_H_
#include <stdint.h>
+#include <libnftnl/desc.h>
#include "internal.h"
struct nlattr;
struct nlmsghdr;
struct nftnl_expr;
+struct nftnl_expr_desc;
+struct nftnl_udata;
+struct nftnl_udata_buf;
struct expr_ops {
const char *name;
+ enum nftnl_expr_desc_type type;
uint32_t alloc_len;
int max_attr;
void (*init)(const struct nftnl_expr *e);
@@ -19,9 +24,15 @@ struct expr_ops {
int (*parse)(struct nftnl_expr *e, struct nlattr *attr);
void (*build)(struct nlmsghdr *nlh, const struct nftnl_expr *e);
int (*snprintf)(char *buf, size_t len, uint32_t flags, const struct nftnl_expr *e);
+ struct {
+ int (*set)(struct nftnl_expr_desc *uexpr, uint8_t type, const void *data, uint32_t data_len);
+ int (*build)(struct nftnl_udata_buf *ud, const struct nftnl_expr_desc *uexpr);
+ int (*parse)(const struct nftnl_udata *attr, struct nftnl_expr_desc *uexpr);
+ } desc;
};
struct expr_ops *nftnl_expr_ops_lookup(const char *name);
+struct expr_ops *nftnl_expr_ops_lookup_by_type(uint32_t type);
#define nftnl_expr_data(ops) (void *)ops->data
@@ -12,5 +12,6 @@
#include "expr.h"
#include "expr_ops.h"
#include "rule.h"
+#include "desc.h"
#endif /* _LIBNFTNL_INTERNAL_H_ */
@@ -1,4 +1,5 @@
pkginclude_HEADERS = batch.h \
+ desc.h \
table.h \
trace.h \
chain.h \
new file mode 100644
@@ -0,0 +1,57 @@
+#ifndef _LIBNFTNL_DESC_H_
+#define _LIBNFTNL_DESC_H_
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* from include/expression.h in libnftables */
+enum nftnl_expr_desc_type {
+ NFTNL_EXPR_UNSPEC = 0,
+ NFTNL_EXPR_PAYLOAD = 7,
+ NFTNL_EXPR_EXTHDR,
+ NFTNL_EXPR_META,
+ NFTNL_EXPR_SOCKET,
+ NFTNL_EXPR_OSF,
+ NFTNL_EXPR_CT,
+ NFTNL_EXPR_RT = 25,
+};
+
+#define NFTNL_DESC_EXPR_BASE 16
+
+enum nftnl_expr_desc_types {
+ NFTNL_DESC_EXPR_TYPE,
+ NFTNL_DESC_EXPR_BYTEORDER,
+ NFTNL_DESC_EXPR_LEN,
+ NFTNL_DESC_EXPR_DATA = NFTNL_DESC_EXPR_BASE,
+ __NFTNL_DESC_EXPR_MAX
+};
+#define NFTNL_DESC_EXPR_MAX (__NFTNL_DESC_EXPR_MAX - 1)
+
+enum nftnl_expr_desc_payload_types {
+ NFTNL_DESC_PAYLOAD_DESC = NFTNL_DESC_EXPR_BASE,
+ NFTNL_DESC_PAYLOAD_TYPE
+};
+
+struct nftnl_expr_desc;
+struct nftnl_udata_buf;
+struct nftnl_udata;
+
+struct nftnl_expr_desc *nftnl_expr_desc_alloc(void);
+void nftnl_expr_desc_free(struct nftnl_expr_desc *dexpr);
+int nftnl_expr_desc_set(struct nftnl_expr_desc *dexpr, uint8_t type,
+ const void *data, uint32_t data_len);
+int nftnl_expr_desc_build(struct nftnl_udata_buf *udbuf,
+ const struct nftnl_expr_desc *dexpr);
+int nftnl_expr_desc_parse(const struct nftnl_udata *attr,
+ struct nftnl_expr_desc *dexpr);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* _LIBNFTNL_DESC_H_ */
@@ -7,6 +7,7 @@ libnftnl_la_LDFLAGS = -Wl,--version-script=$(srcdir)/libnftnl.map \
libnftnl_la_SOURCES = utils.c \
batch.c \
+ desc.c \
flowtable.c \
common.c \
gen.c \
new file mode 100644
@@ -0,0 +1,142 @@
+/*
+ * (C) 2022 by Pablo Neira Ayuso <pablo@netfilter.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#include "internal.h"
+
+#include <time.h>
+#include <endian.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <netinet/in.h>
+
+#include <libmnl/libmnl.h>
+#include <linux/netfilter/nfnetlink.h>
+#include <linux/netfilter/nf_tables.h>
+
+#include <libnftnl/udata.h>
+#include <libnftnl/desc.h>
+
+EXPORT_SYMBOL(nftnl_expr_desc_alloc);
+struct nftnl_expr_desc *nftnl_expr_desc_alloc(void)
+{
+ return calloc(1, sizeof(struct nftnl_expr_desc));
+}
+
+EXPORT_SYMBOL(nftnl_expr_desc_free);
+void nftnl_expr_desc_free(struct nftnl_expr_desc *dexpr)
+{
+ free(dexpr);
+}
+
+EXPORT_SYMBOL(nftnl_expr_desc_set);
+int nftnl_expr_desc_set(struct nftnl_expr_desc *dexpr, uint8_t type,
+ const void *data, uint32_t data_len)
+{
+ int err = 0;
+
+ switch (type) {
+ case NFTNL_DESC_EXPR_TYPE:
+ memcpy(&dexpr->etype, data, data_len);
+ dexpr->ops = nftnl_expr_ops_lookup_by_type(dexpr->etype);
+ break;
+ case NFTNL_DESC_EXPR_BYTEORDER:
+ memcpy(&dexpr->byteorder, data, data_len);
+ break;
+ case NFTNL_DESC_EXPR_LEN:
+ memcpy(&dexpr->len, data, data_len);
+ break;
+ case NFTNL_DESC_EXPR_DATA:
+ if (dexpr->ops && dexpr->ops->desc.set)
+ err = dexpr->ops->desc.set(dexpr, type, data, data_len);
+ break;
+ default:
+ err = -1;
+ break;
+ }
+
+ return err;
+}
+
+#define NFTNL_UDATA_EXPR_TYPE 0
+#define NFTNL_UDATA_EXPR_BYTEORDER 1
+#define NFTNL_UDATA_EXPR_LEN 2
+#define NFTNL_UDATA_EXPR_DATA 3
+#define NFTNL_UDATA_EXPR_MAX 4
+
+EXPORT_SYMBOL(nftnl_expr_desc_build);
+int nftnl_expr_desc_build(struct nftnl_udata_buf *udbuf,
+ const struct nftnl_expr_desc *dexpr)
+{
+ struct nftnl_udata *nest;
+ int err = 0;
+
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_EXPR_TYPE, dexpr->etype);
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_EXPR_BYTEORDER, dexpr->byteorder);
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_EXPR_LEN, dexpr->len);
+ if (dexpr->ops && dexpr->ops->desc.build) {
+ nest = nftnl_udata_nest_start(udbuf, NFTNL_UDATA_EXPR_DATA);
+ err = dexpr->ops->desc.build(udbuf, dexpr);
+ nftnl_udata_nest_end(udbuf, nest);
+ }
+
+ return err;
+}
+
+static int nftnl_expr_desc_parse_nested(const struct nftnl_udata *attr, void *data)
+{
+ const struct nftnl_udata **ud = data;
+ uint8_t type = nftnl_udata_type(attr);
+ uint8_t len = nftnl_udata_len(attr);
+
+ switch (type) {
+ case NFTNL_UDATA_EXPR_TYPE:
+ case NFTNL_UDATA_EXPR_BYTEORDER:
+ case NFTNL_UDATA_EXPR_LEN:
+ if (len != sizeof(uint32_t))
+ return -1;
+ break;
+ case NFTNL_UDATA_EXPR_DATA:
+ break;
+ default:
+ return 0;
+ }
+
+ ud[type] = attr;
+ return 0;
+}
+
+EXPORT_SYMBOL(nftnl_expr_desc_parse);
+int nftnl_expr_desc_parse(const struct nftnl_udata *attr,
+ struct nftnl_expr_desc *dexpr)
+{
+ const struct nftnl_udata *ud[NFTNL_UDATA_EXPR_MAX + 1] = {};
+ int err;
+
+ err = nftnl_udata_parse(nftnl_udata_get(attr), nftnl_udata_len(attr),
+ nftnl_expr_desc_parse_nested, ud);
+ if (err < 0)
+ return -1;
+
+ err = 0;
+ if (ud[NFTNL_UDATA_EXPR_TYPE]) {
+ dexpr->etype = nftnl_udata_get_u32(ud[NFTNL_UDATA_EXPR_TYPE]);
+ dexpr->ops = nftnl_expr_ops_lookup_by_type(dexpr->etype);
+ }
+ if (ud[NFTNL_UDATA_EXPR_BYTEORDER])
+ dexpr->byteorder = nftnl_udata_get_u32(ud[NFTNL_UDATA_EXPR_BYTEORDER]);
+ if (ud[NFTNL_UDATA_EXPR_LEN])
+ dexpr->len = nftnl_udata_get_u32(ud[NFTNL_UDATA_EXPR_LEN]);
+ if (ud[NFTNL_UDATA_EXPR_DATA]) {
+ if (dexpr->ops && dexpr->ops->desc.parse)
+ err = dexpr->ops->desc.parse(ud[NFTNL_UDATA_EXPR_DATA], dexpr);
+ }
+
+ return err;
+}
@@ -23,6 +23,7 @@
#include <libnftnl/expr.h>
#include <libnftnl/rule.h>
+#include <libnftnl/udata.h>
struct nftnl_expr_payload {
enum nft_registers sreg;
@@ -251,8 +252,83 @@ nftnl_expr_payload_snprintf(char *buf, size_t len,
payload->offset, payload->dreg);
}
+static int nftnl_expr_payload_desc_set(struct nftnl_expr_desc *dexpr,
+ uint8_t type, const void *data,
+ uint32_t data_len)
+{
+ switch (type) {
+ case NFTNL_DESC_PAYLOAD_DESC:
+ memcpy(&dexpr->payload.desc_id, data, sizeof(dexpr->payload.desc_id));
+ break;
+ case NFTNL_DESC_PAYLOAD_TYPE:
+ memcpy(&dexpr->payload.type, data, sizeof(dexpr->payload.type));
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+#define NFTNL_UDATA_PAYLOAD_DESC 0
+#define NFTNL_UDATA_PAYLOAD_TYPE 1
+#define NFTNL_UDATA_PAYLOAD_MAX 2
+
+static int nftnl_expr_payload_desc_build(struct nftnl_udata_buf *udbuf,
+ const struct nftnl_expr_desc *dexpr)
+{
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_PAYLOAD_DESC,
+ dexpr->payload.desc_id);
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_PAYLOAD_TYPE,
+ dexpr->payload.type);
+
+ return 0;
+}
+
+static int payload_parse_udata(const struct nftnl_udata *attr, void *data)
+{
+ const struct nftnl_udata **ud = data;
+ uint8_t type = nftnl_udata_type(attr);
+ uint8_t len = nftnl_udata_len(attr);
+
+ switch (type) {
+ case NFTNL_UDATA_PAYLOAD_DESC:
+ case NFTNL_UDATA_PAYLOAD_TYPE:
+ if (len != sizeof(uint32_t))
+ return -1;
+ break;
+ default:
+ return 0;
+ }
+
+ ud[type] = attr;
+ return 0;
+}
+
+static int nftnl_expr_payload_desc_parse(const struct nftnl_udata *attr,
+ struct nftnl_expr_desc *dexpr)
+{
+ const struct nftnl_udata *ud[NFTNL_UDATA_PAYLOAD_MAX + 1] = {};
+ int err;
+
+ err = nftnl_udata_parse(nftnl_udata_get(attr), nftnl_udata_len(attr),
+ payload_parse_udata, ud);
+ if (err < 0)
+ return -1;
+
+ if (!ud[NFTNL_UDATA_PAYLOAD_DESC] ||
+ !ud[NFTNL_UDATA_PAYLOAD_TYPE])
+ return -1;
+
+ dexpr->payload.desc_id = nftnl_udata_get_u32(ud[NFTNL_UDATA_PAYLOAD_DESC]);
+ dexpr->payload.type = nftnl_udata_get_u32(ud[NFTNL_UDATA_PAYLOAD_TYPE]);
+
+ return 0;
+}
+
struct expr_ops expr_ops_payload = {
.name = "payload",
+ .type = NFTNL_EXPR_PAYLOAD,
.alloc_len = sizeof(struct nftnl_expr_payload),
.max_attr = NFTA_PAYLOAD_MAX,
.set = nftnl_expr_payload_set,
@@ -260,4 +336,9 @@ struct expr_ops expr_ops_payload = {
.parse = nftnl_expr_payload_parse,
.build = nftnl_expr_payload_build,
.snprintf = nftnl_expr_payload_snprintf,
+ .desc = {
+ .set = nftnl_expr_payload_desc_set,
+ .build = nftnl_expr_payload_desc_build,
+ .parse = nftnl_expr_payload_desc_parse,
+ },
};
@@ -102,3 +102,16 @@ struct expr_ops *nftnl_expr_ops_lookup(const char *name)
}
return NULL;
}
+
+struct expr_ops *nftnl_expr_ops_lookup_by_type(uint32_t type)
+{
+ int i = 0;
+
+ while (expr_ops[i] != NULL) {
+ if (expr_ops[i]->type == type)
+ return expr_ops[i];
+
+ i++;
+ }
+ return NULL;
+}
Add a new object to describe an expression. This allows to describe the set key when typeof is used to define the set. Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org> --- include/Makefile.am | 1 + include/desc.h | 19 +++++ include/expr_ops.h | 11 +++ include/internal.h | 1 + include/libnftnl/Makefile.am | 1 + include/libnftnl/desc.h | 57 ++++++++++++++ src/Makefile.am | 1 + src/desc.c | 142 +++++++++++++++++++++++++++++++++++ src/expr/payload.c | 81 ++++++++++++++++++++ src/expr_ops.c | 13 ++++ 10 files changed, 327 insertions(+) create mode 100644 include/desc.h create mode 100644 include/libnftnl/desc.h create mode 100644 src/desc.c