From fcb7f2eae546ff14c9717ddbc22b08d09ab3f08a Mon Sep 17 00:00:00 2001 From: fassl Date: Sat, 11 Sep 2021 13:10:28 +0200 Subject: [PATCH] handle protocol version in api: #253 #259 Signed-off-by: fassl --- Makefile.am | 2 +- api.c | 166 +++++++++++++++++------------ tests/test-slirp4netns-hostfwd.sh | 62 +++++++++++ tests/test-slirp4netns-hostfwd4.sh | 90 ++++++++++++++++ tests/test-slirp4netns-hostfwd6.sh | 91 ++++++++++++++++ 5 files changed, 343 insertions(+), 68 deletions(-) create mode 100755 tests/test-slirp4netns-hostfwd.sh create mode 100755 tests/test-slirp4netns-hostfwd4.sh create mode 100755 tests/test-slirp4netns-hostfwd6.sh diff --git a/Makefile.am b/Makefile.am index 41b9ea7..eb95e5e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5,7 +5,7 @@ AM_CFLAGS = @GLIB_CFLAGS@ @SLIRP_CFLAGS@ @LIBCAP_CFLAGS@ @LIBSECCOMP_CFLAGS@ noinst_LIBRARIES = libparson.a AM_TESTS_ENVIRONMENT = PATH="$(abs_top_builddir):$(PATH)" -TESTS = tests/test-slirp4netns.sh tests/test-slirp4netns-configure.sh tests/test-slirp4netns-exit-fd.sh tests/test-slirp4netns-ready-fd.sh tests/test-slirp4netns-api-socket.sh tests/test-slirp4netns-disable-host-loopback.sh tests/test-slirp4netns-cidr.sh tests/test-slirp4netns-outbound-addr.sh tests/test-slirp4netns-disable-dns.sh tests/test-slirp4netns-seccomp.sh tests/test-slirp4netns-macaddress.sh tests/test-slirp4netns-ipv6.sh +TESTS = tests/test-slirp4netns.sh tests/test-slirp4netns-configure.sh tests/test-slirp4netns-exit-fd.sh tests/test-slirp4netns-ready-fd.sh tests/test-slirp4netns-api-socket.sh tests/test-slirp4netns-disable-host-loopback.sh tests/test-slirp4netns-cidr.sh tests/test-slirp4netns-outbound-addr.sh tests/test-slirp4netns-disable-dns.sh tests/test-slirp4netns-seccomp.sh tests/test-slirp4netns-macaddress.sh tests/test-slirp4netns-ipv6.sh tests/test-slirp4netns-hostfwd4.sh tests/test-slirp4netns-hostfwd6.sh tests/test-slirp4netns-hostfwd.sh EXTRA_DIST = \ slirp4netns.1.md \ diff --git a/api.c b/api.c index 16b306f..9a98c8a 100644 --- a/api.c +++ b/api.c @@ -43,11 +43,11 @@ struct api_hostfwd { int is_udp; int is_ipv4; int is_ipv6; - struct in_addr host_addr; - struct in6_addr host_addr6; + struct sockaddr_in host; + struct sockaddr_in guest; + struct sockaddr_in6 host6; + struct sockaddr_in6 guest6; int host_port; - struct in_addr guest_addr; - struct in6_addr guest_addr6; int guest_port; }; @@ -103,10 +103,8 @@ static int api_handle_req_add_hostfwd(Slirp *slirp, int fd, struct api_ctx *ctx, const char *proto_s = json_object_dotget_string(jo, "arguments.proto"); const char *host_addr_s = json_object_dotget_string(jo, "arguments.host_addr"); - char *host_addr6_s = NULL; const char *guest_addr_s = json_object_dotget_string(jo, "arguments.guest_addr"); - char *guest_addr6_s = NULL; struct api_hostfwd *fwd = g_malloc0(sizeof(*fwd)); if (fwd == NULL) { perror("fatal: malloc"); @@ -127,10 +125,46 @@ static int api_handle_req_add_hostfwd(Slirp *slirp, int fd, struct api_ctx *ctx, } int flags = (fwd->is_udp ? SLIRP_HOSTFWD_UDP : 0); + if (host_addr_s == NULL || host_addr_s[0] == '\0') { + host_addr_s = "0.0.0.0"; + } + if (strcmp("0.0.0.0", host_addr_s) == 0 || + strcmp("::", host_addr_s) == 0 || + strcmp("::0", host_addr_s) == 0) { + fwd->is_ipv4 = 1; + fwd->is_ipv6 = ctx->cfg->enable_ipv6; + host_addr_s = "0.0.0.0"; + } else { + if (strchr(host_addr_s, '.')) { + fwd->is_ipv4 = 1; + } + else if (strchr(host_addr_s, ':')) { + if (!ctx->cfg->enable_ipv6) { + const char *err = + "{\"error\":{\"desc\":\"bad request: add_hostfwd: " + "bad arguments.host_addr\"}}"; + wrc = write(fd, err, strlen(err)); + free(fwd); + goto finish; + } + fwd->is_ipv6 = 1; + } + } + if (strlen(proto_s) == 4) { if (proto_s[3] == '4') { fwd->is_ipv4 = 1; + fwd->is_ipv6 = 0; } else if (proto_s[3] == '6') { + if (!ctx->cfg->enable_ipv6) { + const char *err = + "{\"error\":{\"desc\":\"bad request: add_hostfwd: " + "bad arguments.proto\"}}"; + wrc = write(fd, err, strlen(err)); + free(fwd); + goto finish; + } + fwd->is_ipv4 = 0; fwd->is_ipv6 = 1; } else { const char *err = @@ -140,9 +174,6 @@ static int api_handle_req_add_hostfwd(Slirp *slirp, int fd, struct api_ctx *ctx, free(fwd); goto finish; } - } else { - fwd->is_ipv4 = 1; - fwd->is_ipv6 = 1; } fwd->host_port = (int)json_object_dotget_number(jo, "arguments.host_port"); @@ -164,19 +195,20 @@ static int api_handle_req_add_hostfwd(Slirp *slirp, int fd, struct api_ctx *ctx, } if (fwd->is_ipv4) { + fwd->host.sin_family = AF_INET; + fwd->guest.sin_family = AF_INET; + fwd->host.sin_port = htons(fwd->host_port); + fwd->guest.sin_port = htons(fwd->guest_port); if (guest_addr_s == NULL || guest_addr_s[0] == '\0') { - fwd->guest_addr = ctx->cfg->recommended_vguest; - } else if (inet_pton(AF_INET, guest_addr_s, &fwd->guest_addr) != 1) { + fwd->guest.sin_addr = ctx->cfg->recommended_vguest; + } else if (inet_pton(AF_INET, guest_addr_s, &fwd->guest.sin_addr) != 1) { const char *err = "{\"error\":{\"desc\":\"bad request: add_hostfwd: " "bad arguments.guest_addr\"}}"; wrc = write(fd, err, strlen(err)); free(fwd); goto finish; } - if (host_addr_s == NULL || host_addr_s[0] == '\0') { - host_addr_s = "0.0.0.0"; - } - if (inet_pton(AF_INET, host_addr_s, &fwd->host_addr) != 1) { + if (inet_pton(AF_INET, host_addr_s, &fwd->host.sin_addr) != 1) { const char *err = "{\"error\":{\"desc\":\"bad request: add_hostfwd: " "bad arguments.host_addr\"}}"; @@ -184,19 +216,9 @@ static int api_handle_req_add_hostfwd(Slirp *slirp, int fd, struct api_ctx *ctx, free(fwd); goto finish; } - struct sockaddr_in host; - memset(&host, 0, sizeof(host)); - host.sin_family = AF_INET; - host.sin_addr.s_addr = fwd->host_addr.s_addr; - host.sin_port = htons(fwd->host_port); - struct sockaddr_in guest; - memset(&guest, 0, sizeof(guest)); - guest.sin_family = AF_INET; - guest.sin_addr.s_addr = fwd->guest_addr.s_addr; - guest.sin_port = htons(fwd->guest_port); if (slirp_add_hostxfwd(slirp, - (const struct sockaddr*)&host, sizeof(host), - (const struct sockaddr*)&guest, sizeof(guest), flags) < 0) { + (const struct sockaddr*)&fwd->host, sizeof(fwd->host), + (const struct sockaddr*)&fwd->guest, sizeof(fwd->guest), flags) < 0) { const char *err = "{\"error\":{\"desc\":\"bad request: add_hostfwd: " "slirp_add_hostxfwd failed\"}}"; @@ -205,21 +227,25 @@ static int api_handle_req_add_hostfwd(Slirp *slirp, int fd, struct api_ctx *ctx, goto finish; } } + if (fwd->is_ipv6) { + fwd->host6.sin6_family = AF_INET6; + fwd->guest6.sin6_family = AF_INET6; + fwd->host6.sin6_port = htons(fwd->host_port); + fwd->guest6.sin6_port = htons(fwd->guest_port); if (guest_addr_s == NULL || guest_addr_s[0] == '\0') { - fwd->guest_addr6 = ctx->cfg->recommended_vguest6; - } else if (inet_pton(AF_INET6, guest_addr_s, &fwd->guest_addr6) != 1) { + fwd->guest6.sin6_addr = ctx->cfg->recommended_vguest6; + } else if (inet_pton(AF_INET6, guest_addr_s, &fwd->guest6.sin6_addr) != 1) { const char *err = "{\"error\":{\"desc\":\"bad request: add_hostfwd: " "bad arguments.guest_addr\"}}"; wrc = write(fd, err, strlen(err)); free(fwd); goto finish; } - if (host_addr_s == NULL || host_addr_s[0] == '\0' || - strcmp(host_addr_s, "0.0.0.0") == 0) { + if (strcmp(host_addr_s, "0.0.0.0") == 0) { host_addr_s = "::"; } - if (inet_pton(AF_INET6, host_addr_s, &fwd->host_addr6) != 1) { + if (inet_pton(AF_INET6, host_addr_s, &fwd->host6.sin6_addr) != 1) { const char *err = "{\"error\":{\"desc\":\"bad request: add_hostfwd: " "bad arguments.host_addr\"}}"; @@ -227,22 +253,13 @@ static int api_handle_req_add_hostfwd(Slirp *slirp, int fd, struct api_ctx *ctx, free(fwd); goto finish; } - struct sockaddr_in6 host; - memset(&host, 0, sizeof(host)); - host.sin6_family = AF_INET6; - host.sin6_addr = fwd->host_addr6; - host.sin6_port = htons(fwd->host_port); - struct sockaddr_in6 guest; - memset(&guest, 0, sizeof(guest)); - guest.sin6_family = AF_INET6; - guest.sin6_addr = fwd->guest_addr6; - guest.sin6_port = htons(fwd->guest_port); + flags |= SLIRP_HOSTFWD_V6ONLY; if (slirp_add_hostxfwd(slirp, - (const struct sockaddr*)&host, sizeof(host), - (const struct sockaddr*)&guest, sizeof(guest), flags) < 0) { + (const struct sockaddr*)&fwd->host6, sizeof(fwd->host6), + (const struct sockaddr*)&fwd->guest6, sizeof(fwd->guest6), flags) < 0) { const char *err = "{\"error\":{\"desc\":\"bad request: add_hostfwd: " - "slirp_add_hostfwd failed\"}}"; + "slirp_add_hostxfwd failed\"}}"; wrc = write(fd, err, strlen(err)); free(fwd); goto finish; @@ -270,23 +287,25 @@ static void api_handle_req_list_hostfwd_foreach(gpointer data, JSON_Object *entry_object = json_value_get_object(entry_value); char host_addr[INET_ADDRSTRLEN], guest_addr[INET_ADDRSTRLEN]; char host_addr6[INET6_ADDRSTRLEN], guest_addr6[INET6_ADDRSTRLEN]; - if (inet_ntop(AF_INET, &fwd->host_addr, host_addr, sizeof(host_addr)) == - NULL) { - perror("fatal: inet_ntop"); - exit(EXIT_FAILURE); - } - if (inet_ntop(AF_INET, &fwd->guest_addr, guest_addr, sizeof(guest_addr)) == - NULL) { - perror("fatal: inet_ntop"); - exit(EXIT_FAILURE); + if (fwd->is_ipv4) { + if (inet_ntop(AF_INET, &fwd->host.sin_addr, host_addr, sizeof(host_addr)) == + NULL) { + perror("fatal: inet_ntop"); + exit(EXIT_FAILURE); + } + if (inet_ntop(AF_INET, &fwd->guest.sin_addr, guest_addr, sizeof(guest_addr)) == + NULL) { + perror("fatal: inet_ntop"); + exit(EXIT_FAILURE); + } } if (fwd->is_ipv6) { - if (inet_ntop(AF_INET6, &fwd->host_addr6, host_addr6, sizeof(host_addr6)) == + if (inet_ntop(AF_INET6, &fwd->host6.sin6_addr, host_addr6, sizeof(host_addr6)) == NULL) { perror("fatal: inet_ntop"); exit(EXIT_FAILURE); } - if (inet_ntop(AF_INET6, &fwd->guest_addr6, guest_addr6, sizeof(guest_addr6)) == + if (inet_ntop(AF_INET6, &fwd->guest6.sin6_addr, guest_addr6, sizeof(guest_addr6)) == NULL) { perror("fatal: inet_ntop"); exit(EXIT_FAILURE); @@ -294,12 +313,16 @@ static void api_handle_req_list_hostfwd_foreach(gpointer data, } json_object_set_number(entry_object, "id", fwd->id); json_object_set_string(entry_object, "proto", fwd->is_udp ? "udp" : "tcp"); - json_object_set_string(entry_object, "host_addr", host_addr); + if (fwd->is_ipv4) { + json_object_set_string(entry_object, "host_addr", host_addr); + } if (fwd->is_ipv6) { json_object_set_string(entry_object, "host_addr6", host_addr6); } json_object_set_number(entry_object, "host_port", fwd->host_port); - json_object_set_string(entry_object, "guest_addr", guest_addr); + if (fwd->is_ipv4) { + json_object_set_string(entry_object, "guest_addr", guest_addr); + } if (fwd->is_ipv6) { json_object_set_string(entry_object, "guest_addr6", guest_addr6); } @@ -360,16 +383,25 @@ static int api_handle_req_remove_hostfwd(Slirp *slirp, int fd, } else { struct api_hostfwd *fwd = found->data; const char *api_ok = "{\"return\":{}}"; - if (slirp_remove_hostfwd(slirp, fwd->is_udp, fwd->host_addr, - fwd->host_port) < 0) { - const char *err = "{\"error\":{\"desc\":\"bad request: " - "remove_hostfwd: slirp_remove_hostfwd failed\"}}"; - wrc = write(fd, err, strlen(err)); - } else { - ctx->hostfwds = g_list_remove(ctx->hostfwds, fwd); - g_free(fwd); - wrc = write(fd, api_ok, strlen(api_ok)); + if (fwd->is_ipv4) { + if (slirp_remove_hostxfwd(slirp, + (const struct sockaddr*)&fwd->host, sizeof(fwd->host), 0) < 0) { + const char *err = "{\"error\":{\"desc\":\"bad request: " + "remove_hostfwd: slirp_remove_hostxfwd failed\"}}"; + return write(fd, err, strlen(err)); + } + } + if (fwd->is_ipv6) { + if (slirp_remove_hostxfwd(slirp, + (const struct sockaddr*)&fwd->host6, sizeof(fwd->host6), 0) < 0) { + const char *err = "{\"error\":{\"desc\":\"bad request: " + "remove_hostfwd: slirp_remove_hostxfwd failed\"}}"; + return write(fd, err, strlen(err)); + } } + ctx->hostfwds = g_list_remove(ctx->hostfwds, fwd); + g_free(fwd); + wrc = write(fd, api_ok, strlen(api_ok)); } return wrc; } diff --git a/tests/test-slirp4netns-hostfwd.sh b/tests/test-slirp4netns-hostfwd.sh new file mode 100755 index 0000000..20302d2 --- /dev/null +++ b/tests/test-slirp4netns-hostfwd.sh @@ -0,0 +1,62 @@ +#!/bin/bash +set -xeuo pipefail + +. $(dirname $0)/common.sh + +host_port=8080 +guest_port=1080 +cidr=fd00:a1e1:1724:1a + +unshare -r -n socat tcp6-listen:$guest_port,reuseaddr,fork exec:cat,nofork & +child=$! + +#nsenter -a -t $child socat tcp-listen:$guest_port,reuseaddr,fork exec:cat,nofork & + +wait_for_network_namespace $child + +tmpdir=$(mktemp -d /tmp/slirp4netns-bench.XXXXXXXXXX) +apisocket=${tmpdir}/slirp4netns.sock + +slirp4netns -c $child --enable-ipv6 --cidr6=$cidr::/64 --api-socket $apisocket tun11 & +slirp_pid=$! + +wait_for_network_device $child tun11 + +function cleanup() { + kill -9 $child $slirp_pid + rm -rf $tmpdir +} +trap cleanup EXIT + +set +e +result=$(cat /dev/zero | ncat -U $apisocket || true) +set set -e +echo $result | jq .error.desc | grep "bad request: too large message" + +set -e +result=$(echo '{"execute": "add_hostfwd", "arguments":{"proto": "tcp","host_port":'$host_port',"guest_port":'$guest_port'}}' | ncat -U $apisocket) +[[ $(echo $result | jq .error) == null ]] +id=$(echo $result | jq .return.id) +[[ $id == 1 ]] + +result=$(echo '{"execute": "list_hostfwd"}' | ncat -U $apisocket) +[[ $(echo $result | jq .error) == null ]] +[[ $(echo $result | jq .entries[0].id) == $id ]] +[[ $(echo $result | jq .entries[0].proto) == '"tcp"' ]] +[[ $(echo $result | jq .entries[0].host_addr) == '"0.0.0.0"' ]] +[[ $(echo $result | jq .entries[0].host_addr6) == '"::"' ]] +[[ $(echo $result | jq .entries[0].host_port) == $host_port ]] +[[ $(echo $result | jq .entries[0].guest_addr) == '"10.0.2.100"' ]] +[[ $(echo $result | jq .entries[0].guest_addr6) == '"'$cidr'::100"' ]] +[[ $(echo $result | jq .entries[0].guest_port) == $guest_port ]] + +result=$(echo works | nc -w 10 localhost6 $host_port) +[[ "$result" == "works" ]] + +result=$(echo works | nc -w 10 localhost $host_port) +[[ "$result" == "works" ]] + +result=$(echo '{"execute": "remove_hostfwd", "arguments":{"id": 1}}' | ncat -U $apisocket) +[[ $(echo $result | jq .error) == null ]] + +# see also: benchmarks/benchmark-iperf3-reverse.sh diff --git a/tests/test-slirp4netns-hostfwd4.sh b/tests/test-slirp4netns-hostfwd4.sh new file mode 100755 index 0000000..86504f2 --- /dev/null +++ b/tests/test-slirp4netns-hostfwd4.sh @@ -0,0 +1,90 @@ +#!/bin/bash +set -xeuo pipefail + +. $(dirname $0)/common.sh + +host_port=8080 +guest_port=1080 + +unshare -r -n socat tcp-listen:$guest_port,reuseaddr,fork exec:cat,nofork & +child=$! + +wait_for_network_namespace $child + +tmpdir=$(mktemp -d /tmp/slirp4netns-bench.XXXXXXXXXX) +apisocket=${tmpdir}/slirp4netns.sock + +slirp4netns -c $child --api-socket $apisocket tun11 & +slirp_pid=$! + +wait_for_network_device $child tun11 + +function cleanup() { + kill -9 $child $slirp_pid + rm -rf $tmpdir +} +trap cleanup EXIT + +set +e +result=$(cat /dev/zero | ncat -U $apisocket || true) +set set -e +echo $result | jq .error.desc | grep "bad request: too large message" + +set -e +result=$(echo '{"execute": "add_hostfwd", "arguments":{"proto": "tcp","host_port":'$host_port',"guest_port":'$guest_port'}}' | ncat -U $apisocket) +[[ $(echo $result | jq .error) == null ]] +id=$(echo $result | jq .return.id) +[[ $id == 1 ]] + +result=$(echo '{"execute": "list_hostfwd"}' | ncat -U $apisocket) +[[ $(echo $result | jq .error) == null ]] +[[ $(echo $result | jq .entries[0].id) == $id ]] +[[ $(echo $result | jq .entries[0].proto) == '"tcp"' ]] +[[ $(echo $result | jq .entries[0].host_addr) == '"0.0.0.0"' ]] +[[ $(echo $result | jq .entries[0].host_addr6) == null ]] +[[ $(echo $result | jq .entries[0].host_port) == $host_port ]] +[[ $(echo $result | jq .entries[0].guest_addr) == '"10.0.2.100"' ]] +[[ $(echo $result | jq .entries[0].guest_addr6) == null ]] +[[ $(echo $result | jq .entries[0].guest_port) == $guest_port ]] + +result=$(echo works | nc -w 10 localhost $host_port) +[[ "$result" == "works" ]] + +result=$(echo works | nc -w 10 localhost6 $host_port || true) +[[ "$result" != "works" ]] + +result=$(echo '{"execute": "remove_hostfwd", "arguments":{"id": 1}}' | ncat -U $apisocket) +[[ $(echo $result | jq .error) == null ]] + +result=$(echo '{"execute": "add_hostfwd", "arguments":{"proto": "tcp","host_addr":"127.0.0.1","host_port":'$host_port',"guest_port":'$guest_port'}}' | ncat -U $apisocket) +[[ $(echo $result | jq .error) == null ]] +id=$(echo $result | jq .return.id) +[[ $id == 2 ]] + +result=$(echo '{"execute": "list_hostfwd"}' | ncat -U $apisocket) +[[ $(echo $result | jq .error) == null ]] +[[ $(echo $result | jq .entries[0].id) == $id ]] +[[ $(echo $result | jq .entries[0].proto) == '"tcp"' ]] +[[ $(echo $result | jq .entries[0].host_addr) == '"127.0.0.1"' ]] +[[ $(echo $result | jq .entries[0].host_addr6) == null ]] +[[ $(echo $result | jq .entries[0].host_port) == $host_port ]] +[[ $(echo $result | jq .entries[0].guest_addr) == '"10.0.2.100"' ]] +[[ $(echo $result | jq .entries[0].guest_addr6) == null ]] +[[ $(echo $result | jq .entries[0].guest_port) == $guest_port ]] + +result=$(echo works | nc -w 10 localhost $host_port) +[[ "$result" == "works" ]] + +result=$(echo works | nc -w 10 localhost6 $host_port || true) +[[ "$result" != "works" ]] + +result=$(echo '{"execute": "remove_hostfwd", "arguments":{"id": 2}}' | ncat -U $apisocket) +[[ $(echo $result | jq .error) == null ]] + +result=$(echo '{"execute": "add_hostfwd", "arguments":{"proto": "tcp6","host_port":'$host_port',"guest_port":'$guest_port'}}' | ncat -U $apisocket || true) +echo $result | jq .error.desc | grep "bad arguments.proto" + +result=$(echo '{"execute": "add_hostfwd", "arguments":{"proto": "tcp","host_addr":"::1","host_port":'$host_port',"guest_port":'$guest_port'}}' | ncat -U $apisocket || true) +echo $result | jq .error.desc | grep "bad arguments.host_addr" + +# see also: benchmarks/benchmark-iperf3-reverse.sh diff --git a/tests/test-slirp4netns-hostfwd6.sh b/tests/test-slirp4netns-hostfwd6.sh new file mode 100755 index 0000000..f5b86b4 --- /dev/null +++ b/tests/test-slirp4netns-hostfwd6.sh @@ -0,0 +1,91 @@ +#!/bin/bash +set -xeuo pipefail + +. $(dirname $0)/common.sh + +host_port=8080 +guest_port=1080 +cidr=fd00:a1e1:1724:1a + +unshare -r -n socat tcp6-listen:$guest_port,reuseaddr,fork exec:cat,nofork & +child=$! + +wait_for_network_namespace $child + +tmpdir=$(mktemp -d /tmp/slirp4netns-bench.XXXXXXXXXX) +apisocket=${tmpdir}/slirp4netns.sock + +slirp4netns -c $child --enable-ipv6 --cidr6=$cidr::/64 --api-socket $apisocket tun11 & +slirp_pid=$! + +wait_for_network_device $child tun11 + +function cleanup() { + kill -9 $child $slirp_pid + rm -rf $tmpdir +} +trap cleanup EXIT + +set +e +result=$(cat /dev/zero | ncat -U $apisocket || true) +set set -e +echo $result | jq .error.desc | grep "bad request: too large message" + +set -e +result=$(echo '{"execute": "add_hostfwd", "arguments":{"proto": "tcp6","host_port":'$host_port',"guest_port":'$guest_port'}}' | ncat -U $apisocket) +[[ $(echo $result | jq .error) == null ]] +id=$(echo $result | jq .return.id) +[[ $id == 1 ]] + +result=$(echo '{"execute": "list_hostfwd"}' | ncat -U $apisocket) +[[ $(echo $result | jq .error) == null ]] +[[ $(echo $result | jq .entries[0].id) == $id ]] +[[ $(echo $result | jq .entries[0].proto) == '"tcp"' ]] +[[ $(echo $result | jq .entries[0].host_addr) == null ]] +[[ $(echo $result | jq .entries[0].host_addr6) == '"::"' ]] +[[ $(echo $result | jq .entries[0].host_port) == $host_port ]] +[[ $(echo $result | jq .entries[0].guest_addr) == null ]] +[[ $(echo $result | jq .entries[0].guest_addr6) == '"'$cidr'::100"' ]] +[[ $(echo $result | jq .entries[0].guest_port) == $guest_port ]] + +result=$(echo works | nc -w 10 localhost6 $host_port) +[[ "$result" == "works" ]] + +result=$(echo works | nc -w 10 localhost $host_port || true) +[[ "$result" != "works" ]] + +result=$(echo '{"execute": "remove_hostfwd", "arguments":{"id": 1}}' | ncat -U $apisocket) +[[ $(echo $result | jq .error) == null ]] + +result=$(echo '{"execute": "add_hostfwd", "arguments":{"proto": "tcp6","host_addr":"::1","host_port":'$host_port',"guest_port":'$guest_port'}}' | ncat -U $apisocket) +[[ $(echo $result | jq .error) == null ]] +id=$(echo $result | jq .return.id) +[[ $id == 2 ]] + +result=$(echo '{"execute": "list_hostfwd"}' | ncat -U $apisocket) +[[ $(echo $result | jq .error) == null ]] +[[ $(echo $result | jq .entries[0].id) == $id ]] +[[ $(echo $result | jq .entries[0].proto) == '"tcp"' ]] +[[ $(echo $result | jq .entries[0].host_addr) == null ]] +[[ $(echo $result | jq .entries[0].host_addr6) == '"::1"' ]] +[[ $(echo $result | jq .entries[0].host_port) == $host_port ]] +[[ $(echo $result | jq .entries[0].guest_addr) == null ]] +[[ $(echo $result | jq .entries[0].guest_addr6) == '"'$cidr'::100"' ]] +[[ $(echo $result | jq .entries[0].guest_port) == $guest_port ]] + +result=$(echo works | nc -w 10 localhost6 $host_port) +[[ "$result" == "works" ]] + +result=$(echo works | nc -w 10 localhost $host_port || true) +[[ "$result" != "works" ]] + +result=$(echo '{"execute": "remove_hostfwd", "arguments":{"id": 2}}' | ncat -U $apisocket) +[[ $(echo $result | jq .error) == null ]] + +result=$(echo '{"execute": "add_hostfwd", "arguments":{"proto": "tcp4","host_addr":"::1","host_port":'$host_port',"guest_port":'$guest_port'}}' | ncat -U $apisocket || true) +echo $result | jq .error.desc | grep "bad arguments.host_addr" + +result=$(echo '{"execute": "add_hostfwd", "arguments":{"proto": "tcp6","host_addr":"127.0.0.1","host_port":'$host_port',"guest_port":'$guest_port'}}' | ncat -U $apisocket || true) +echo $result | jq .error.desc | grep "bad arguments.host_addr" + +# see also: benchmarks/benchmark-iperf3-reverse.sh