diff options
Diffstat (limited to 'src/parser_json.c')
-rw-r--r-- | src/parser_json.c | 181 |
1 files changed, 123 insertions, 58 deletions
diff --git a/src/parser_json.c b/src/parser_json.c index 418d4ad7..bbe3b1c5 100644 --- a/src/parser_json.c +++ b/src/parser_json.c @@ -181,8 +181,11 @@ static int json_unpack_stmt(struct json_ctx *ctx, json_t *root, assert(value); if (json_object_size(root) != 1) { + const char *dump = json_dumps(root, 0); + json_error(ctx, "Malformed object (too many properties): '%s'.", - json_dumps(root, 0)); + dump); + free_const(dump); return 1; } @@ -1305,6 +1308,7 @@ static struct expr *json_parse_range_expr(struct json_ctx *ctx, expr_high = json_parse_primary_expr(ctx, high); if (!expr_high) { json_error(ctx, "Invalid high value in range expression."); + expr_free(expr_low); return NULL; } return range_expr_alloc(int_loc, expr_low, expr_high); @@ -1886,6 +1890,8 @@ static struct stmt *json_parse_mangle_stmt(struct json_ctx *ctx, return stmt; default: json_error(ctx, "Invalid mangle statement key expression type."); + expr_free(key); + expr_free(value); return NULL; } } @@ -2374,7 +2380,7 @@ static void json_parse_set_stmt_list(struct json_ctx *ctx, json_t *stmt_json) { struct list_head *head; - struct stmt *tmp; + struct stmt *stmt; json_t *value; size_t index; @@ -2386,9 +2392,14 @@ static void json_parse_set_stmt_list(struct json_ctx *ctx, head = stmt_list; json_array_foreach(stmt_json, index, value) { - tmp = json_parse_stmt(ctx, value); - list_add(&tmp->list, head); - head = &tmp->list; + stmt = json_parse_stmt(ctx, value); + if (!stmt) { + json_error(ctx, "Parsing set statements array at index %zd failed.", index); + stmt_list_free(stmt_list); + return; + } + list_add(&stmt->list, head); + head = &stmt->list; } } @@ -2565,9 +2576,7 @@ static struct stmt *json_parse_log_stmt(struct json_ctx *ctx, stmt = log_stmt_alloc(int_loc); if (!json_unpack(value, "{s:s}", "prefix", &tmpstr)) { - stmt->log.prefix = constant_expr_alloc(int_loc, &string_type, - BYTEORDER_HOST_ENDIAN, - (strlen(tmpstr) + 1) * BITS_PER_BYTE, tmpstr); + stmt->log.prefix = xstrdup(tmpstr); stmt->log.flags |= STMT_LOG_PREFIX; } if (!json_unpack(value, "{s:i}", "group", &tmp)) { @@ -2887,6 +2896,7 @@ static struct stmt *json_parse_optstrip_stmt(struct json_ctx *ctx, expr->etype != EXPR_EXTHDR || expr->exthdr.op != NFT_EXTHDR_OP_TCPOPT) { json_error(ctx, "Illegal TCP optstrip argument"); + expr_free(expr); return NULL; } @@ -2966,6 +2976,45 @@ static struct stmt *json_parse_stmt(struct json_ctx *ctx, json_t *root) return NULL; } +static int json_parse_table_flags(struct json_ctx *ctx, json_t *root, + enum table_flags *flags) +{ + json_t *tmp, *tmp2; + size_t index; + int flag; + + if (json_unpack(root, "{s:o}", "flags", &tmp)) + return 0; + + if (json_is_string(tmp)) { + flag = parse_table_flag(json_string_value(tmp)); + if (flag) { + *flags = flag; + return 0; + } + json_error(ctx, "Invalid table flag '%s'.", + json_string_value(tmp)); + return 1; + } + if (!json_is_array(tmp)) { + json_error(ctx, "Unexpected table flags value."); + return 1; + } + json_array_foreach(tmp, index, tmp2) { + if (json_is_string(tmp2)) { + flag = parse_table_flag(json_string_value(tmp2)); + + if (flag) { + *flags |= flag; + continue; + } + } + json_error(ctx, "Invalid table flag at index %zu.", index); + return 1; + } + return 0; +} + static struct cmd *json_parse_cmd_add_table(struct json_ctx *ctx, json_t *root, enum cmd_ops op, enum cmd_obj obj) { @@ -2974,6 +3023,7 @@ static struct cmd *json_parse_cmd_add_table(struct json_ctx *ctx, json_t *root, .table.location = *int_loc, }; struct table *table = NULL; + enum table_flags flags = 0; if (json_unpack_err(ctx, root, "{s:s}", "family", &family)) @@ -2984,6 +3034,9 @@ static struct cmd *json_parse_cmd_add_table(struct json_ctx *ctx, json_t *root, return NULL; json_unpack(root, "{s:s}", "comment", &comment); + if (json_parse_table_flags(ctx, root, &flags)) + return NULL; + } else if (op == CMD_DELETE && json_unpack(root, "{s:s}", "name", &h.table.name) && json_unpack(root, "{s:I}", "handle", &h.handle.id)) { @@ -2997,10 +3050,12 @@ static struct cmd *json_parse_cmd_add_table(struct json_ctx *ctx, json_t *root, if (h.table.name) h.table.name = xstrdup(h.table.name); - if (comment) { + if (comment || flags) { table = table_alloc(); handle_merge(&table->handle, &h); - table->comment = xstrdup(comment); + if (comment) + table->comment = xstrdup(comment); + table->flags = flags; } if (op == CMD_ADD) @@ -3118,8 +3173,7 @@ static struct cmd *json_parse_cmd_add_chain(struct json_ctx *ctx, json_t *root, chain->hook.name = chain_hookname_lookup(hookstr); if (!chain->hook.name) { json_error(ctx, "Invalid chain hook '%s'.", hookstr); - chain_free(chain); - return NULL; + goto err_free_chain; } json_unpack(root, "{s:o}", "dev", &devs); @@ -3128,8 +3182,7 @@ static struct cmd *json_parse_cmd_add_chain(struct json_ctx *ctx, json_t *root, chain->dev_expr = json_parse_devs(ctx, devs); if (!chain->dev_expr) { json_error(ctx, "Invalid chain dev."); - chain_free(chain); - return NULL; + goto err_free_chain; } } @@ -3137,8 +3190,7 @@ static struct cmd *json_parse_cmd_add_chain(struct json_ctx *ctx, json_t *root, chain->policy = parse_policy(policy); if (!chain->policy) { json_error(ctx, "Unknown policy '%s'.", policy); - chain_free(chain); - return NULL; + goto err_free_chain; } } @@ -3147,6 +3199,11 @@ static struct cmd *json_parse_cmd_add_chain(struct json_ctx *ctx, json_t *root, handle_merge(&chain->handle, &h); return cmd_alloc(op, obj, &h, int_loc, chain); + +err_free_chain: + chain_free(chain); + handle_free(&h); + return NULL; } static struct cmd *json_parse_cmd_add_rule(struct json_ctx *ctx, json_t *root, @@ -3186,6 +3243,7 @@ static struct cmd *json_parse_cmd_add_rule(struct json_ctx *ctx, json_t *root, if (!json_is_array(tmp)) { json_error(ctx, "Value of property \"expr\" must be an array."); + handle_free(&h); return NULL; } @@ -3205,16 +3263,14 @@ static struct cmd *json_parse_cmd_add_rule(struct json_ctx *ctx, json_t *root, if (!json_is_object(value)) { json_error(ctx, "Unexpected expr array element of type %s, expected object.", json_typename(value)); - rule_free(rule); - return NULL; + goto err_free_rule; } stmt = json_parse_stmt(ctx, value); if (!stmt) { json_error(ctx, "Parsing expr array at index %zd failed.", index); - rule_free(rule); - return NULL; + goto err_free_rule; } rule_stmt_append(rule, stmt); @@ -3224,6 +3280,11 @@ static struct cmd *json_parse_cmd_add_rule(struct json_ctx *ctx, json_t *root, json_object_del(root, "handle"); return cmd_alloc(op, obj, &h, int_loc, rule); + +err_free_rule: + rule_free(rule); + handle_free(&h); + return NULL; } static int string_to_nft_object(const char *str) @@ -3335,8 +3396,10 @@ static struct cmd *json_parse_cmd_add_set(struct json_ctx *ctx, json_t *root, } else if ((set->data = json_parse_dtype_expr(ctx, tmp))) { set->flags |= NFT_SET_MAP; } else { - json_error(ctx, "Invalid map type '%s'.", - json_dumps(tmp, 0)); + const char *dump = json_dumps(tmp, 0); + + json_error(ctx, "Invalid map type '%s'.", dump); + free_const(dump); set_free(set); handle_free(&h); return NULL; @@ -3602,8 +3665,7 @@ static struct cmd *json_parse_cmd_add_object(struct json_ctx *ctx, if (ret < 0 || ret >= (int)sizeof(obj->secmark.ctx)) { json_error(ctx, "Invalid secmark context '%s', max length is %zu.", tmp, sizeof(obj->secmark.ctx)); - obj_free(obj); - return NULL; + goto err_free_obj; } } break; @@ -3619,8 +3681,7 @@ static struct cmd *json_parse_cmd_add_object(struct json_ctx *ctx, ret >= (int)sizeof(obj->ct_helper.name)) { json_error(ctx, "Invalid CT helper type '%s', max length is %zu.", tmp, sizeof(obj->ct_helper.name)); - obj_free(obj); - return NULL; + goto err_free_obj; } } if (!json_unpack(root, "{s:s}", "protocol", &tmp)) { @@ -3630,15 +3691,13 @@ static struct cmd *json_parse_cmd_add_object(struct json_ctx *ctx, obj->ct_helper.l4proto = IPPROTO_UDP; } else { json_error(ctx, "Invalid ct helper protocol '%s'.", tmp); - obj_free(obj); - return NULL; + goto err_free_obj; } } if (!json_unpack(root, "{s:s}", "l3proto", &tmp) && parse_family(tmp, &l3proto)) { json_error(ctx, "Invalid ct helper l3proto '%s'.", tmp); - obj_free(obj); - return NULL; + goto err_free_obj; } obj->ct_helper.l3proto = l3proto; break; @@ -3652,23 +3711,19 @@ static struct cmd *json_parse_cmd_add_object(struct json_ctx *ctx, obj->ct_timeout.l4proto = IPPROTO_UDP; } else { json_error(ctx, "Invalid ct timeout protocol '%s'.", tmp); - obj_free(obj); - return NULL; + goto err_free_obj; } } if (!json_unpack(root, "{s:s}", "l3proto", &tmp) && parse_family(tmp, &l3proto)) { json_error(ctx, "Invalid ct timeout l3proto '%s'.", tmp); - obj_free(obj); - return NULL; + goto err_free_obj; } obj->ct_timeout.l3proto = l3proto; init_list_head(&obj->ct_timeout.timeout_list); - if (json_parse_ct_timeout_policy(ctx, root, obj)) { - obj_free(obj); - return NULL; - } + if (json_parse_ct_timeout_policy(ctx, root, obj)) + goto err_free_obj; break; case NFT_OBJECT_CT_EXPECT: cmd_obj = CMD_OBJ_CT_EXPECT; @@ -3676,8 +3731,7 @@ static struct cmd *json_parse_cmd_add_object(struct json_ctx *ctx, if (!json_unpack(root, "{s:s}", "l3proto", &tmp) && parse_family(tmp, &l3proto)) { json_error(ctx, "Invalid ct expectation l3proto '%s'.", tmp); - obj_free(obj); - return NULL; + goto err_free_obj; } obj->ct_expect.l3proto = l3proto; if (!json_unpack(root, "{s:s}", "protocol", &tmp)) { @@ -3687,8 +3741,7 @@ static struct cmd *json_parse_cmd_add_object(struct json_ctx *ctx, obj->ct_expect.l4proto = IPPROTO_UDP; } else { json_error(ctx, "Invalid ct expectation protocol '%s'.", tmp); - obj_free(obj); - return NULL; + goto err_free_obj; } } if (!json_unpack(root, "{s:i}", "dport", &i)) @@ -3702,10 +3755,9 @@ static struct cmd *json_parse_cmd_add_object(struct json_ctx *ctx, obj->type = NFT_OBJECT_LIMIT; if (json_unpack_err(ctx, root, "{s:I, s:s}", "rate", &obj->limit.rate, - "per", &tmp)) { - obj_free(obj); - return NULL; - } + "per", &tmp)) + goto err_free_obj; + json_unpack(root, "{s:s}", "rate_unit", &rate_unit); json_unpack(root, "{s:b}", "inv", &inv); json_unpack(root, "{s:i}", "burst", &obj->limit.burst); @@ -3726,20 +3778,18 @@ static struct cmd *json_parse_cmd_add_object(struct json_ctx *ctx, case CMD_OBJ_SYNPROXY: obj->type = NFT_OBJECT_SYNPROXY; if (json_unpack_err(ctx, root, "{s:i, s:i}", - "mss", &i, "wscale", &j)) { - obj_free(obj); - return NULL; - } + "mss", &i, "wscale", &j)) + goto err_free_obj; + obj->synproxy.mss = i; obj->synproxy.wscale = j; obj->synproxy.flags |= NF_SYNPROXY_OPT_MSS; obj->synproxy.flags |= NF_SYNPROXY_OPT_WSCALE; if (!json_unpack(root, "{s:o}", "flags", &jflags)) { flags = json_parse_synproxy_flags(ctx, jflags); - if (flags < 0) { - obj_free(obj); - return NULL; - } + if (flags < 0) + goto err_free_obj; + obj->synproxy.flags |= flags; } break; @@ -3751,6 +3801,11 @@ static struct cmd *json_parse_cmd_add_object(struct json_ctx *ctx, json_object_del(root, "handle"); return cmd_alloc(op, cmd_obj, &h, int_loc, obj); + +err_free_obj: + obj_free(obj); + handle_free(&h); + return NULL; } static struct cmd *json_parse_cmd_add(struct json_ctx *ctx, @@ -3865,8 +3920,7 @@ static struct cmd *json_parse_cmd_replace(struct json_ctx *ctx, if (!json_is_object(value)) { json_error(ctx, "Unexpected expr array element of type %s, expected object.", json_typename(value)); - rule_free(rule); - return NULL; + goto err_free_replace; } stmt = json_parse_stmt(ctx, value); @@ -3874,8 +3928,7 @@ static struct cmd *json_parse_cmd_replace(struct json_ctx *ctx, if (!stmt) { json_error(ctx, "Parsing expr array at index %zd failed.", index); - rule_free(rule); - return NULL; + goto err_free_replace; } rule_stmt_append(rule, stmt); @@ -3885,6 +3938,11 @@ static struct cmd *json_parse_cmd_replace(struct json_ctx *ctx, json_object_del(root, "handle"); return cmd_alloc(op, CMD_OBJ_RULE, &h, int_loc, rule); + +err_free_replace: + rule_free(rule); + handle_free(&h); + return NULL; } static struct cmd *json_parse_cmd_list_multiple(struct json_ctx *ctx, @@ -4314,6 +4372,13 @@ int nft_parse_json_filename(struct nft_ctx *nft, const char *filename, json_error_t err; int ret; + if (nft->stdin_buf) { + json_indesc.type = INDESC_STDIN; + json_indesc.name = "/dev/stdin"; + + return nft_parse_json_buffer(nft, nft->stdin_buf, msgs, cmds); + } + json_indesc.type = INDESC_FILE; json_indesc.name = filename; |