Signed-off-by: Florian Westphal <fw@xxxxxxxxx> --- include/json.h | 2 + src/json.c | 26 +++++++++++++ src/parser_json.c | 43 ++++++++++++++++++++ src/statement.c | 1 + tests/py/inet/tproxy.t.json | 91 +++++++++++++++++++++++++++++++++++++++++++ tests/py/ip/tproxy.t.json | 95 +++++++++++++++++++++++++++++++++++++++++++++ tests/py/ip6/tproxy.t.json | 90 ++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 348 insertions(+) create mode 100644 tests/py/inet/tproxy.t.json create mode 100644 tests/py/ip/tproxy.t.json create mode 100644 tests/py/ip6/tproxy.t.json diff --git a/include/json.h b/include/json.h index 78c026a7a7f6..e64151de66c0 100644 --- a/include/json.h +++ b/include/json.h @@ -76,6 +76,7 @@ json_t *meter_stmt_json(const struct stmt *stmt, struct output_ctx *octx); json_t *queue_stmt_json(const struct stmt *stmt, struct output_ctx *octx); json_t *verdict_stmt_json(const struct stmt *stmt, struct output_ctx *octx); json_t *connlimit_stmt_json(const struct stmt *stmt, struct output_ctx *octx); +json_t *tproxy_stmt_json(const struct stmt *stmt, struct output_ctx *octx); int do_command_list_json(struct netlink_ctx *ctx, struct cmd *cmd); @@ -153,6 +154,7 @@ STMT_PRINT_STUB(meter) STMT_PRINT_STUB(queue) STMT_PRINT_STUB(verdict) STMT_PRINT_STUB(connlimit) +STMT_PRINT_STUB(tproxy) #undef STMT_PRINT_STUB #undef EXPR_PRINT_STUB diff --git a/src/json.c b/src/json.c index 6112cf563125..6d9ddc151c07 100644 --- a/src/json.c +++ b/src/json.c @@ -1300,6 +1300,32 @@ json_t *connlimit_stmt_json(const struct stmt *stmt, struct output_ctx *octx) return json_pack("{s:o}", "ct count", root); } +json_t *tproxy_stmt_json(const struct stmt *stmt, struct output_ctx *octx) +{ + json_t *root = json_object(); + + if (stmt->tproxy.addr) { + int family; + json_t *tmp; + + family = stmt->tproxy.table_family; + if (family == NFPROTO_INET) + family = stmt->tproxy.family; + + tmp = json_string(family2str(family)); + json_object_set_new(root, "family", tmp); + + tmp = expr_print_json(stmt->tproxy.addr, octx); + json_object_set_new(root, "addr", tmp); + } + + if (stmt->tproxy.port) + json_object_set_new(root, "port", + expr_print_json(stmt->tproxy.port, octx)); + + return json_pack("{s:o}", "tproxy", root); +} + static json_t *table_print_json_full(struct netlink_ctx *ctx, struct table *table) { diff --git a/src/parser_json.c b/src/parser_json.c index 6d8cda975ff9..3d96000b6066 100644 --- a/src/parser_json.c +++ b/src/parser_json.c @@ -1796,6 +1796,48 @@ static struct stmt *json_parse_nat_stmt(struct json_ctx *ctx, return stmt; } +static struct stmt *json_parse_tproxy_stmt(struct json_ctx *ctx, + const char *key, json_t *value) +{ + json_t *jaddr, *tmp; + const char *family; + struct stmt *stmt; + int familyval; + + stmt = tproxy_stmt_alloc(int_loc); + + if (json_unpack(value, "{s:s, s:o}", + "family", &family, "addr", &jaddr)) + goto try_port; + + familyval = parse_family(family); + if (familyval != NFPROTO_IPV4 && + familyval != NFPROTO_IPV6) { + json_error(ctx, "Invalid family '%s'.", family); + goto out_free; + } + stmt->tproxy.family = familyval; + + stmt->tproxy.addr = json_parse_stmt_expr(ctx, jaddr); + if (!stmt->tproxy.addr) { + json_error(ctx, "Invalid addr."); + goto out_free; + } +try_port: + if (!json_unpack(value, "{s:o}", "port", &tmp)) { + stmt->tproxy.port = json_parse_stmt_expr(ctx, tmp); + if (!stmt->tproxy.port) { + json_error(ctx, "Invalid port."); + goto out_free; + } + } + return stmt; + +out_free: + stmt_free(stmt); + return NULL; +} + static struct stmt *json_parse_reject_stmt(struct json_ctx *ctx, const char *key, json_t *value) { @@ -2150,6 +2192,7 @@ static struct stmt *json_parse_stmt(struct json_ctx *ctx, json_t *root) { "meter", json_parse_meter_stmt }, { "queue", json_parse_queue_stmt }, { "ct count", json_parse_connlimit_stmt }, + { "tproxy", json_parse_tproxy_stmt }, }; const char *type; unsigned int i; diff --git a/src/statement.c b/src/statement.c index 3040476fdfa1..2019f2b3ed10 100644 --- a/src/statement.c +++ b/src/statement.c @@ -797,6 +797,7 @@ static const struct stmt_ops tproxy_stmt_ops = { .type = STMT_TPROXY, .name = "tproxy", .print = tproxy_stmt_print, + .json = tproxy_stmt_json, .destroy = tproxy_stmt_destroy, }; diff --git a/tests/py/inet/tproxy.t.json b/tests/py/inet/tproxy.t.json new file mode 100644 index 000000000000..6c9f57d4c4c4 --- /dev/null +++ b/tests/py/inet/tproxy.t.json @@ -0,0 +1,91 @@ +# meta l4proto 17 tproxy ip to 192.0.2.1 +[ + { + "match": { + "left": { + "meta": "l4proto" + }, + "right": 17 + } + }, + { + "tproxy": { + "addr": "192.0.2.1", + "family": "ip" + } + } +] + +# meta l4proto 6 tproxy ip to 192.0.2.1:50080 +[ + { + "match": { + "left": { + "meta": "l4proto" + }, + "right": 6 + } + }, + { + "tproxy": { + "addr": "192.0.2.1", + "family": "ip", + "port": 50080 + } + } +] + +# meta l4proto 6 tproxy ip6 to [2001:db8::1] +[ + { + "match": { + "left": { + "meta": "l4proto" + }, + "right": 6 + } + }, + { + "tproxy": { + "addr": "2001:db8::1", + "family": "ip6" + } + } +] + +# meta l4proto 17 tproxy ip6 to [2001:db8::1]:50080 +[ + { + "match": { + "left": { + "meta": "l4proto" + }, + "right": 17 + } + }, + { + "tproxy": { + "addr": "2001:db8::1", + "family": "ip6", + "port": 50080 + } + } +] + +# meta l4proto 17 tproxy to :50080 +[ + { + "match": { + "left": { + "meta": "l4proto" + }, + "right": 17 + } + }, + { + "tproxy": { + "port": 50080 + } + } +] + diff --git a/tests/py/ip/tproxy.t.json b/tests/py/ip/tproxy.t.json new file mode 100644 index 000000000000..630285bf3f0b --- /dev/null +++ b/tests/py/ip/tproxy.t.json @@ -0,0 +1,95 @@ +# meta l4proto 17 tproxy to 192.0.2.1 +[ + { + "match": { + "left": { + "meta": "l4proto" + }, + "right": 17 + } + }, + { + "tproxy": { + "addr": "192.0.2.1", + "family": "ip" + } + } +] + +# meta l4proto 6 tproxy to 192.0.2.1:50080 +[ + { + "match": { + "left": { + "meta": "l4proto" + }, + "right": 6 + } + }, + { + "tproxy": { + "addr": "192.0.2.1", + "family": "ip", + "port": 50080 + } + } +] + +# ip protocol 6 tproxy to :50080 +[ + { + "match": { + "left": { + "payload": { + "field": "protocol", + "name": "ip" + } + }, + "right": 6 + } + }, + { + "tproxy": { + "port": 50080 + } + } +] + +# meta l4proto 17 tproxy ip to 192.0.2.1 +[ + { + "match": { + "left": { + "meta": "l4proto" + }, + "right": 17 + } + }, + { + "tproxy": { + "addr": "192.0.2.1", + "family": "ip" + } + } +] + +# meta l4proto 6 tproxy ip to 192.0.2.1:50080 +[ + { + "match": { + "left": { + "meta": "l4proto" + }, + "right": 6 + } + }, + { + "tproxy": { + "addr": "192.0.2.1", + "family": "ip", + "port": 50080 + } + } +] + + diff --git a/tests/py/ip6/tproxy.t.json b/tests/py/ip6/tproxy.t.json new file mode 100644 index 000000000000..b627b20efc1c --- /dev/null +++ b/tests/py/ip6/tproxy.t.json @@ -0,0 +1,90 @@ +# meta l4proto 6 tproxy to [2001:db8::1] +[ + { + "match": { + "left": { + "meta": "l4proto" + }, + "right": 6 + } + }, + { + "tproxy": { + "addr": "2001:db8::1", + "family": "ip6" + } + } +] + +# meta l4proto 17 tproxy to [2001:db8::1]:50080 +[ + { + "match": { + "left": { + "meta": "l4proto" + }, + "right": 17 + } + }, + { + "tproxy": { + "addr": "2001:db8::1", + "family": "ip6", + "port": 50080 + } + } +] + +# meta l4proto 6 tproxy to :50080 +[ + { + "match": { + "left": { + "meta": "l4proto" + }, + "right": 6 + } + }, + { + "tproxy": { + "port": 50080 + } + } +] + +# meta l4proto 6 tproxy ip6 to [2001:db8::1] +[ + { + "match": { + "left": { + "meta": "l4proto" + }, + "right": 6 + } + }, + { + "tproxy": { + "addr": "2001:db8::1", + "family": "ip6" + } + } +] + +# meta l4proto 17 tproxy ip6 to [2001:db8::1]:50080 +[ + { + "match": { + "left": { + "meta": "l4proto" + }, + "right": 17 + } + }, + { + "tproxy": { + "addr": "2001:db8::1", + "family": "ip6", + "port": 50080 + } + } +] -- 2.16.4