summaryrefslogtreecommitdiffstats
path: root/src/parser_json.c
diff options
context:
space:
mode:
authorFernando Fernandez Mancera <fmancera@suse.de>2025-08-21 11:13:01 +0200
committerPablo Neira Ayuso <pablo@netfilter.org>2025-08-27 23:51:12 +0200
commit3a957f8f1ff1e111c4d7121749a400dfcac685b7 (patch)
tree7c712b3274b1608b75edaf9bbf7045e9fa4a113f /src/parser_json.c
parent59f03bf14835fe5764b016491ce50715df5711c2 (diff)
tunnel: add tunnel object and statement json support
Signed-off-by: Fernando Fernandez Mancera <fmancera@suse.de> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'src/parser_json.c')
-rw-r--r--src/parser_json.c236
1 files changed, 233 insertions, 3 deletions
diff --git a/src/parser_json.c b/src/parser_json.c
index ebb96d79..8bca6a59 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -439,6 +439,23 @@ static struct expr *json_parse_meta_expr(struct json_ctx *ctx,
return meta_expr_alloc(int_loc, key);
}
+static struct expr *json_parse_tunnel_expr(struct json_ctx *ctx,
+ const char *type, json_t *root)
+{
+ struct error_record *erec;
+ unsigned int key;
+ const char *name;
+
+ if (json_unpack_err(ctx, root, "{s:s}", "key", &name))
+ return NULL;
+ erec = tunnel_key_parse(int_loc, name, &key);
+ if (erec) {
+ erec_queue(erec, ctx->msgs);
+ return NULL;
+ }
+ return tunnel_expr_alloc(int_loc, key);
+}
+
static struct expr *json_parse_osf_expr(struct json_ctx *ctx,
const char *type, json_t *root)
{
@@ -1642,6 +1659,7 @@ static struct expr *json_parse_expr(struct json_ctx *ctx, json_t *root)
{ "rt", json_parse_rt_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
{ "ct", json_parse_ct_expr, CTX_F_RHS | CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
{ "numgen", json_parse_numgen_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { "tunnel", json_parse_tunnel_expr, CTX_F_RHS | CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SES | CTX_F_MAP },
/* below two are hash expr */
{ "jhash", json_parse_hash_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
{ "symhash", json_parse_hash_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
@@ -2202,6 +2220,23 @@ static struct stmt *json_parse_secmark_stmt(struct json_ctx *ctx,
return stmt;
}
+static struct stmt *json_parse_tunnel_stmt(struct json_ctx *ctx,
+ const char *key, json_t *value)
+{
+ struct stmt *stmt;
+
+ stmt = objref_stmt_alloc(int_loc);
+ stmt->objref.type = NFT_OBJECT_TUNNEL;
+ stmt->objref.expr = json_parse_stmt_expr(ctx, value);
+ if (!stmt->objref.expr) {
+ json_error(ctx, "Invalid tunnel reference.");
+ stmt_free(stmt);
+ return NULL;
+ }
+
+ return stmt;
+}
+
static unsigned int json_parse_nat_flag(const char *flag)
{
const struct {
@@ -2870,6 +2905,7 @@ static struct stmt *json_parse_stmt(struct json_ctx *ctx, json_t *root)
{ "synproxy", json_parse_synproxy_stmt },
{ "reset", json_parse_optstrip_stmt },
{ "secmark", json_parse_secmark_stmt },
+ { "tunnel", json_parse_tunnel_stmt },
};
const char *type;
unsigned int i;
@@ -3518,14 +3554,139 @@ static int json_parse_ct_timeout_policy(struct json_ctx *ctx,
return 0;
}
+static int json_parse_tunnel_erspan(struct json_ctx *ctx,
+ json_t *root, struct obj *obj)
+{
+ const char *dir;
+ json_t *tmp;
+ int i;
+
+ if (json_unpack_err(ctx, root, "{s:o}", "tunnel", &tmp))
+ return 1;
+
+ if (json_unpack_err(ctx, tmp, "{s:i}", "version", &obj->tunnel.erspan.version))
+ return 1;
+
+ switch (obj->tunnel.erspan.version) {
+ case 1:
+ if (json_unpack_err(ctx, tmp, "{s:i}",
+ "index", &obj->tunnel.erspan.v1.index))
+ return 1;
+ break;
+ case 2:
+ if (json_unpack_err(ctx, tmp, "{s:s, s:i}",
+ "dir", &dir,
+ "hwid", &i))
+ return 1;
+ obj->tunnel.erspan.v2.hwid = i;
+
+ if (!strcmp(dir, "ingress")) {
+ obj->tunnel.erspan.v2.direction = 0;
+ } else if (!strcmp(dir, "egress")) {
+ obj->tunnel.erspan.v2.direction = 1;
+ } else {
+ json_error(ctx, "Invalid direction '%s'.", dir);
+ return 1;
+ }
+ break;
+ default:
+ json_error(ctx, "Invalid erspan version %u" , obj->tunnel.erspan.version);
+ return 1;
+ }
+
+ return 0;
+}
+
+static enum tunnel_type json_parse_tunnel_type(struct json_ctx *ctx,
+ const char *type)
+{
+ const struct {
+ const char *type;
+ int val;
+ } type_tbl[] = {
+ { "erspan", TUNNEL_ERSPAN },
+ { "vxlan", TUNNEL_VXLAN },
+ { "geneve", TUNNEL_GENEVE },
+ };
+ unsigned int i;
+
+ if (!type)
+ return TUNNEL_UNSPEC;
+
+ for (i = 0; i < array_size(type_tbl); i++) {
+ if (!strcmp(type, type_tbl[i].type))
+ return type_tbl[i].val;
+ }
+
+ return TUNNEL_UNSPEC;
+}
+
+static int json_parse_tunnel_src_and_dst(struct json_ctx *ctx,
+ json_t *root,
+ struct obj *obj)
+{
+ bool is_ipv4 = false, src_set = false, dst_set = false;
+ struct expr *expr;
+ json_t *tmp;
+
+ if (!json_unpack(root, "{s:o}", "src-ipv4", &tmp)) {
+ is_ipv4 = true;
+ src_set = true;
+ expr = json_parse_expr(ctx, tmp);
+ if (!expr)
+ return -1;
+ datatype_set(expr, &ipaddr_type);
+ obj->tunnel.src = expr;
+ }
+
+ if (!json_unpack(root, "{s:o}", "src-ipv6", &tmp)) {
+ if (is_ipv4 || src_set)
+ return -1;
+ src_set = true;
+ expr = json_parse_expr(ctx, tmp);
+ if (!expr)
+ return -1;
+ datatype_set(expr, &ip6addr_type);
+ obj->tunnel.src = expr;
+ }
+
+ if (!json_unpack(root, "{s:o}", "dst-ipv4", &tmp)) {
+ dst_set = true;
+ if (!is_ipv4)
+ return -1;
+ expr = json_parse_expr(ctx, tmp);
+ if (!expr)
+ return -1;
+ datatype_set(expr, &ipaddr_type);
+ obj->tunnel.dst = expr;
+ }
+
+ if (!json_unpack(root, "{s:o}", "dst-ipv6", &tmp)) {
+ if (is_ipv4 || dst_set)
+ return -1;
+ dst_set = true;
+ expr = json_parse_expr(ctx, tmp);
+ if (!expr)
+ return -1;
+ datatype_set(expr, &ip6addr_type);
+ obj->tunnel.dst = expr;
+ }
+
+ if (!dst_set || !src_set)
+ return -1;
+
+ return 0;
+}
+
static struct cmd *json_parse_cmd_add_object(struct json_ctx *ctx,
json_t *root, enum cmd_ops op,
enum cmd_obj cmd_obj)
{
- const char *family, *tmp, *rate_unit = "packets", *burst_unit = "bytes";
+ const char *family, *tmp = NULL, *rate_unit = "packets", *burst_unit = "bytes";
uint32_t l3proto = NFPROTO_UNSPEC;
int inv = 0, flags = 0, i, j;
struct handle h = { 0 };
+ json_t *tmp_json;
struct obj *obj;
if (json_unpack_err(ctx, root, "{s:s, s:s}",
@@ -3713,8 +3874,77 @@ static struct cmd *json_parse_cmd_add_object(struct json_ctx *ctx,
obj->synproxy.flags |= flags;
break;
- case CMD_OBJ_TUNNEL:
- /* TODO */
+ case NFT_OBJECT_TUNNEL:
+ cmd_obj = CMD_OBJ_TUNNEL;
+ obj->type = NFT_OBJECT_TUNNEL;
+
+ if (json_parse_tunnel_src_and_dst(ctx, root, obj))
+ goto err_free_obj;
+
+ json_unpack(root, "{s:i}", "id", &obj->tunnel.id);
+ json_unpack(root, "{s:i}", "sport", &i);
+ obj->tunnel.sport = i;
+ json_unpack(root, "{s:i}", "dport", &i);
+ obj->tunnel.sport = i;
+ json_unpack(root, "{s:i}", "ttl", &i);
+ obj->tunnel.ttl = i;
+ json_unpack(root, "{s:i}", "tos", &i);
+ obj->tunnel.tos = i;
+ json_unpack(root, "{s:s}", "type", &tmp);
+
+ obj->tunnel.type = json_parse_tunnel_type(ctx, tmp);
+ switch (obj->tunnel.type) {
+ case TUNNEL_UNSPEC:
+ break;
+ case TUNNEL_ERSPAN:
+ if (json_parse_tunnel_erspan(ctx, root, obj))
+ goto err_free_obj;
+ break;
+ case TUNNEL_VXLAN:
+ if (json_unpack_err(ctx, root,
+ "{s:o}", "tunnel", &tmp_json))
+ goto err_free_obj;
+
+ json_unpack(tmp_json, "{s:i}",
+ "gbp", &obj->tunnel.vxlan.gbp);
+ break;
+ case TUNNEL_GENEVE:
+ json_t *value;
+ size_t index;
+
+ if (json_unpack_err(ctx, root,
+ "{s:o}", "tunnel", &tmp_json))
+ goto err_free_obj;
+
+ json_array_foreach(tmp_json, index, value) {
+ struct tunnel_geneve *geneve = xmalloc(sizeof(struct tunnel_geneve));
+ if (!geneve)
+ memory_allocation_error();
+
+ if (json_unpack_err(ctx, value, "{s:i, s:i, s:s}",
+ "class", &i,
+ "opt-type", &j,
+ "data", &tmp)) {
+ free(geneve);
+ goto err_free_obj;
+ }
+ geneve->geneve_class = i;
+ geneve->type = j;
+
+ if (tunnel_geneve_data_str2array(tmp,
+ geneve->data,
+ &geneve->data_len)) {
+ free(geneve);
+ goto err_free_obj;
+ }
+
+ if (index == 0)
+ init_list_head(&obj->tunnel.geneve_opts);
+
+ list_add_tail(&geneve->list, &obj->tunnel.geneve_opts);
+ }
+ break;
+ }
break;
default:
BUG("Invalid CMD '%d'", cmd_obj);