diff --git a/src/iperf_api.c b/src/iperf_api.c index 075c973..fd0fa07 100644 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -1019,6 +1019,8 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) char* comma; #endif /* HAVE_CPU_AFFINITY */ char* slash; + char *p, *p1; + struct in6_addr ipv6_addr; struct xbind_entry *xbe; double farg; int rcv_timeout_in = 0; @@ -1101,6 +1103,26 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) } iperf_set_test_role(test, 'c'); iperf_set_test_server_hostname(test, optarg); + // hostname should be extended with `%` for IPv6 link-local addresses + if ((p = strtok(optarg, "%")) != NULL) { + p1 = strtok(NULL, "%"); + if (inet_pton(AF_INET6, p, &ipv6_addr) == 1) { + if (IN6_IS_ADDR_LINKLOCAL(&ipv6_addr)) { + if (!p1) { + i_errno = IEHOSTDEV; + } + } else if (p1) { + i_errno = IEHOSTDEV; + } + } else { //IPv4 + if (p1) { + i_errno = IEHOSTDEV; + } + } + if (i_errno == IEHOSTDEV) { + return -1; + } + } break; case 'u': set_protocol(test, Pudp); @@ -1213,7 +1235,20 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) client_flag = 1; break; case 'B': - test->bind_address = strdup(optarg); + // IP ddress format is [%] + if ((p = strtok(optarg, "%")) == NULL) + test->bind_address = strdup(optarg); + else { + test->bind_address = strdup(p); + if ((p = strtok(NULL, "%")) != NULL) { +#if defined (HAVE_SO_BINDTODEVICE) + test->bind_dev = strdup(p); +#else /* HAVE_SO_BINDTODEVICE */ + i_errno = IEBINDDEVNOSUPPORT; + return -1; +#endif /* HAVE_SO_BINDTODEVICE */ + } + } break; #if defined (HAVE_SO_BINDTODEVICE) case OPT_BIND_DEV: diff --git a/src/iperf_api.h b/src/iperf_api.h index cb4a86d..50ae6ed 100644 --- a/src/iperf_api.h +++ b/src/iperf_api.h @@ -425,7 +425,9 @@ enum { IEAUTHTEST = 142, // Test authorization failed IEBINDDEV = 143, // Unable to bind-to-device (check perror, maybe permissions?) IENOMSG = 144, // No message was received for NO_MSG_RCVD_TIMEOUT time period - IESETDONTFRAGMENT = 145, // Unable to set IP Do-Not-Fragment + IESETDONTFRAGMENT = 145, // Unable to set IP Do-Not-Fragment + IEBINDDEVNOSUPPORT = 146, // `ip%%dev` is not supported as system does not support bind to device + IEHOSTDEV = 147, // host device name (ip%%) is supported (and required) only for IPv6 link-local address /* Stream errors */ IECREATESTREAM = 200, // Unable to create a new stream (check herror/perror) IEINITSTREAM = 201, // Unable to initialize stream (check herror/perror) diff --git a/src/iperf_error.c b/src/iperf_error.c index 1bcf8a8..d14770b 100644 --- a/src/iperf_error.c +++ b/src/iperf_error.c @@ -438,6 +438,15 @@ iperf_strerror(int int_errno) case IEIDLETIMEOUT: snprintf(errstr, len, "idle timeout parameter is not positive or larget then allowed limit"); break; + case IEBINDDEV: + snprintf(errstr, len, "Unable to bind-to-device (check perror, maybe permissions?)"); + break; + case IEBINDDEVNOSUPPORT: + snprintf(errstr, len, "`%%` is not supported as system does not support bind to device"); + break; + case IEHOSTDEV: + snprintf(errstr, len, "host device name (ip%%) is supported (and required) only for IPv6 link-local address"); + break; case IENOMSG: snprintf(errstr, len, "idle timeout for receiving data"); break; diff --git a/src/iperf_locale.c b/src/iperf_locale.c index e1e9dc5..c9c6ce7 100644 --- a/src/iperf_locale.c +++ b/src/iperf_locale.c @@ -105,9 +105,12 @@ const char usage_longstr[] = "Usage: iperf3 [-s|-c host] [options]\n" #if defined(HAVE_CPU_AFFINITY) " -A, --affinity n/n,m set CPU affinity\n" #endif /* HAVE_CPU_AFFINITY */ - " -B, --bind bind to the interface associated with the address \n" #if defined(HAVE_SO_BINDTODEVICE) - " --bind-dev bind to the network interface with SO_BINDTODEVICE\n" + " -B, --bind [%] bind to the interface associated with the address \n" + " (optional equivalent to `--bind-dev `)\n" + " --bind-dev bind to the network interface with SO_BINDTODEVICE\n" +#else /* HAVE_SO_BINDTODEVICE */ + " -B, --bind bind to the interface associated with the address \n" #endif /* HAVE_SO_BINDTODEVICE */ " -V, --verbose more detailed output\n" " -J, --json output in JSON format\n" @@ -139,7 +142,8 @@ const char usage_longstr[] = "Usage: iperf3 [-s|-c host] [options]\n" " and client during the authentication process\n" #endif //HAVE_SSL "Client specific:\n" - " -c, --client run in client mode, connecting to \n" + " -c, --client [%] run in client mode, connecting to \n" + " % is supported and required when is IPv6 Link-local\n" #if defined(HAVE_SCTP_H) " --sctp use SCTP rather than TCP\n" " -X, --xbind bind SCTP association to links\n"