From 50ab7a3e1765a15674168984d9316599d0b54416 Mon Sep 17 00:00:00 2001 From: Klemens Nanni Date: Thu, 30 Oct 2025 21:28:15 +0300 Subject: [PATCH] Do not modify --bind and --client arguments inplace Do as iperf_parse_hostname()'s comment says already: pass a copy of getopt(3)'s `optarg` aka. to avoid strtok(3) scribbling over `argv[]`. Otherwise arguments like "fe80::1%vport0" appear as "fe80::1" in the process list and cause exact matching of process name and arguments (against what was used) to fail. OpenBSD's net/iperf3 package ships a rc.subr(8) script and the service framework uses pgrep(1) to check for running processes, where this bug causes a mismatch due to the scope identifier being stripped: ``` $ rcctl get iperf3 flags -6 --bind fe80::1%vport0 $ rcctl check iperf3 iperf3(failed) $ pgrep -fl iperf3 33091 /usr/local/bin/iperf3 -s -D -6 -B fe80::1 ``` Pass a copy to avoid modification, thus fixing rcctl(8) reporting: ``` $ rcctl check iperf3 iperf3(ok) $ pgrep -fl iperf3 98863 /usr/local/bin/iperf3 -s -D -6 -B fe80::1%vport0 ``` --- src/iperf_api.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/iperf_api.c b/src/iperf_api.c index 0e7e58917..38f3e53df 100644 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -1289,7 +1289,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) } iperf_set_test_role(test, 's'); break; - case 'c': + case 'c': { if (test->role == 's') { i_errno = IESERVCLIENT; return -1; @@ -1297,18 +1297,22 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) iperf_set_test_role(test, 'c'); iperf_set_test_server_hostname(test, optarg); - if (iperf_parse_hostname(test, optarg, &p, &p1)) { + char *arg = strdup(optarg); + if (iperf_parse_hostname(test, arg, &p, &p1)) { #if defined(HAVE_SO_BINDTODEVICE) /* Get rid of the hostname we saved earlier. */ free(iperf_get_test_server_hostname(test)); iperf_set_test_server_hostname(test, p); iperf_set_test_bind_dev(test, p1); #else /* HAVE_SO_BINDTODEVICE */ + free(arg); i_errno = IEBINDDEVNOSUPPORT; return -1; #endif /* HAVE_SO_BINDTODEVICE */ } + free(arg); break; + } case 'u': set_protocol(test, Pudp); client_flag = 1; @@ -1441,21 +1445,25 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) client_flag = 1; break; - case 'B': + case 'B': { iperf_set_test_bind_address(test, optarg); - if (iperf_parse_hostname(test, optarg, &p, &p1)) { + char *arg = strdup(optarg); + if (iperf_parse_hostname(test, arg, &p, &p1)) { #if defined(HAVE_SO_BINDTODEVICE) /* Get rid of the hostname we saved earlier. */ free(iperf_get_test_bind_address(test)); iperf_set_test_bind_address(test, p); iperf_set_test_bind_dev(test, p1); #else /* HAVE_SO_BINDTODEVICE */ + free(arg); i_errno = IEBINDDEVNOSUPPORT; return -1; #endif /* HAVE_SO_BINDTODEVICE */ } + free(arg); break; + } #if defined (HAVE_SO_BINDTODEVICE) case OPT_BIND_DEV: iperf_set_test_bind_dev(test, optarg);