diff --git a/Makefile.in b/Makefile.in index 3c56ac5b6..d8be67fea 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.16.2 from Makefile.am. +# Makefile.in generated by automake 1.16.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2020 Free Software Foundation, Inc. @@ -204,6 +204,8 @@ am__relativize = \ DIST_ARCHIVES = $(distdir).tar.gz GZIP_ENV = --best DIST_TARGETS = dist-gzip +# Exists only to be overridden by the user if desired. +AM_DISTCHECK_DVI_TARGET = dvi distuninstallcheck_listfiles = find . -type f -print am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' @@ -629,7 +631,7 @@ distcheck: dist $(DISTCHECK_CONFIGURE_FLAGS) \ --srcdir=../.. --prefix="$$dc_install_base" \ && $(MAKE) $(AM_MAKEFLAGS) \ - && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) $(AM_DISTCHECK_DVI_TARGET) \ && $(MAKE) $(AM_MAKEFLAGS) check \ && $(MAKE) $(AM_MAKEFLAGS) install \ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ diff --git a/aclocal.m4 b/aclocal.m4 index df70996bd..0b6f3d443 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -1,4 +1,4 @@ -# generated automatically by aclocal 1.16.2 -*- Autoconf -*- +# generated automatically by aclocal 1.16.3 -*- Autoconf -*- # Copyright (C) 1996-2020 Free Software Foundation, Inc. @@ -9059,7 +9059,7 @@ AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.16' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. -m4_if([$1], [1.16.2], [], +m4_if([$1], [1.16.3], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) @@ -9075,7 +9075,7 @@ m4_define([_AM_AUTOCONF_VERSION], []) # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], -[AM_AUTOMAKE_VERSION([1.16.2])dnl +[AM_AUTOMAKE_VERSION([1.16.3])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) @@ -9763,12 +9763,7 @@ AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([missing])dnl if test x"${MISSING+set}" != xset; then - case $am_aux_dir in - *\ * | *\ *) - MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; - *) - MISSING="\${SHELL} $am_aux_dir/missing" ;; - esac + MISSING="\${SHELL} '$am_aux_dir/missing'" fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then diff --git a/configure b/configure index 72e0113c0..098bce198 100755 --- a/configure +++ b/configure @@ -2531,12 +2531,7 @@ program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` am_aux_dir=`cd "$ac_aux_dir" && pwd` if test x"${MISSING+set}" != xset; then - case $am_aux_dir in - *\ * | *\ *) - MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; - *) - MISSING="\${SHELL} $am_aux_dir/missing" ;; - esac + MISSING="\${SHELL} '$am_aux_dir/missing'" fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then @@ -13950,6 +13945,37 @@ $as_echo "#define HAVE_SO_MAX_PACING_RATE 1" >>confdefs.h fi +# Check for SO_BINDTODEVICE sockopt (believed to be Linux only) +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking SO_BINDTODEVICE socket option" >&5 +$as_echo_n "checking SO_BINDTODEVICE socket option... " >&6; } +if ${iperf3_cv_header_so_bindtodevice+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#ifdef SO_BINDTODEVICE + yes +#endif + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "yes" >/dev/null 2>&1; then : + iperf3_cv_header_so_bindtodevice=yes +else + iperf3_cv_header_so_bindtodevice=no +fi +rm -f conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $iperf3_cv_header_so_bindtodevice" >&5 +$as_echo "$iperf3_cv_header_so_bindtodevice" >&6; } +if test "x$iperf3_cv_header_so_bindtodevice" = "xyes"; then + +$as_echo "#define HAVE_SO_BINDTODEVICE 1" >>confdefs.h + +fi + # Check if we need -lrt for clock_gettime { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing clock_gettime" >&5 $as_echo_n "checking for library containing clock_gettime... " >&6; } diff --git a/configure.ac b/configure.ac index aa6ccd9ee..7e2b62fbb 100644 --- a/configure.ac +++ b/configure.ac @@ -224,6 +224,19 @@ if test "x$iperf3_cv_header_so_max_pacing_rate" = "xyes"; then AC_DEFINE([HAVE_SO_MAX_PACING_RATE], [1], [Have SO_MAX_PACING_RATE sockopt.]) fi +# Check for SO_BINDTODEVICE sockopt (believed to be Linux only) +AC_CACHE_CHECK([SO_BINDTODEVICE socket option], +[iperf3_cv_header_so_bindtodevice], +AC_EGREP_CPP(yes, +[#include +#ifdef SO_BINDTODEVICE + yes +#endif +],iperf3_cv_header_so_bindtodevice=yes,iperf3_cv_header_so_bindtodevice=no)) +if test "x$iperf3_cv_header_so_bindtodevice" = "xyes"; then + AC_DEFINE([HAVE_SO_BINDTODEVICE], [1], [Have SO_BINDTODEVICE sockopt.]) +fi + # Check if we need -lrt for clock_gettime AC_SEARCH_LIBS(clock_gettime, [rt posix4]) # Check for clock_gettime support diff --git a/examples/Makefile.in b/examples/Makefile.in index a74833f54..74d3a9543 100644 --- a/examples/Makefile.in +++ b/examples/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.16.2 from Makefile.am. +# Makefile.in generated by automake 1.16.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2020 Free Software Foundation, Inc. diff --git a/src/Makefile.in b/src/Makefile.in index 271ef6cc5..801f327a9 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.16.2 from Makefile.am. +# Makefile.in generated by automake 1.16.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2020 Free Software Foundation, Inc. @@ -479,6 +479,7 @@ am__set_TESTS_bases = \ bases='$(TEST_LOGS)'; \ bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \ bases=`echo $$bases` +AM_TESTSUITE_SUMMARY_HEADER = ' for $(PACKAGE_STRING)' RECHECK_LOGS = $(TEST_LOGS) AM_RECURSIVE_TARGETS = check recheck TEST_SUITE_LOG = test-suite.log @@ -1565,7 +1566,7 @@ $(TEST_SUITE_LOG): $(TEST_LOGS) test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \ fi; \ echo "$${col}$$br$${std}"; \ - echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}"; \ + echo "$${col}Testsuite summary"$(AM_TESTSUITE_SUMMARY_HEADER)"$${std}"; \ echo "$${col}$$br$${std}"; \ create_testsuite_report --maybe-color; \ echo "$$col$$br$$std"; \ diff --git a/src/iperf.h b/src/iperf.h index a614b4d33..c6354617d 100644 --- a/src/iperf.h +++ b/src/iperf.h @@ -40,6 +40,7 @@ # define _GNU_SOURCE #endif #include +#include // for IFNAMSIZ #if defined(HAVE_CPUSET_SETAFFINITY) #include @@ -258,6 +259,7 @@ struct iperf_test char *server_hostname; /* -c option */ char *tmp_template; char *bind_address; /* first -B option */ + char *bind_dev; /* bind to network device */ TAILQ_HEAD(xbind_addrhead, xbind_entry) xbind_addrs; /* all -X opts */ int bind_port; /* --cport option */ int server_port; diff --git a/src/iperf3.1 b/src/iperf3.1 index 879a2c13f..1c3308059 100644 --- a/src/iperf3.1 +++ b/src/iperf3.1 @@ -139,6 +139,10 @@ CPUs). .TP .BR -B ", " --bind " \fIhost\fR" bind to the specific interface associated with address \fIhost\fR. +.BR --bind-dev " \fIdev\R" +bind to the specified network interface. +This option uses SO_BINDTODEVICE, and may require root permissions. +(Available on Linux and possibly other systems.) .TP .BR -V ", " --verbose " " give more detailed output diff --git a/src/iperf_api.c b/src/iperf_api.c index d6997b69e..a4f58b4fd 100644 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -339,6 +339,12 @@ iperf_get_test_bind_address(struct iperf_test *ipt) return ipt->bind_address; } +char * +iperf_get_test_bind_dev(struct iperf_test *ipt) +{ + return ipt->bind_dev; +} + int iperf_get_test_udp_counters_64bit(struct iperf_test *ipt) { @@ -661,6 +667,12 @@ iperf_set_test_bind_address(struct iperf_test *ipt, const char *bnd_address) ipt->bind_address = strdup(bnd_address); } +void +iperf_set_test_bind_dev(struct iperf_test *ipt, char *bnd_dev) +{ + ipt->bind_dev = strdup(bnd_dev); +} + void iperf_set_test_udp_counters_64bit(struct iperf_test *ipt, int udp_counters_64bit) { @@ -894,6 +906,9 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) {"bidir", no_argument, NULL, OPT_BIDIRECTIONAL}, {"window", required_argument, NULL, 'w'}, {"bind", required_argument, NULL, 'B'}, +#if defined(HAVE_SO_BINDTODEVICE) + {"bind-dev", required_argument, NULL, OPT_BIND_DEV}, +#endif /* HAVE_SO_BINDTODEVICE */ {"cport", required_argument, NULL, OPT_CLIENT_PORT}, {"set-mss", required_argument, NULL, 'M'}, {"no-delay", no_argument, NULL, 'N'}, @@ -1147,6 +1162,11 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) case 'B': test->bind_address = strdup(optarg); break; +#if defined (HAVE_SO_BINDTODEVICE) + case OPT_BIND_DEV: + test->bind_dev = strdup(optarg); + break; +#endif /* HAVE_SO_BINDTODEVICE */ case OPT_CLIENT_PORT: portno = atoi(optarg); if (portno < 1 || portno > 65535) { @@ -2635,6 +2655,8 @@ iperf_free_test(struct iperf_test *test) free(test->tmp_template); if (test->bind_address) free(test->bind_address); + if (test->bind_dev) + free(test->bind_dev); if (!TAILQ_EMPTY(&test->xbind_addrs)) { struct xbind_entry *xbe; diff --git a/src/iperf_api.h b/src/iperf_api.h index 5d71e7983..905568e2f 100644 --- a/src/iperf_api.h +++ b/src/iperf_api.h @@ -80,6 +80,7 @@ typedef uint64_t iperf_size_t; #define OPT_SERVER_BITRATE_LIMIT 21 #define OPT_TIMESTAMPS 22 #define OPT_SERVER_SKEW_THRESHOLD 23 +#define OPT_BIND_DEV 24 /* states */ #define TEST_START 1 @@ -408,6 +409,7 @@ enum { IESETPACING= 140, // Unable to set socket pacing rate IESETBUF2= 141, // Socket buffer size incorrect (written value != read value) IEAUTHTEST = 142, // Test authorization failed + IEBINDDEV = 143, // Unable to bind-to-device (check perror, maybe permissions?) /* 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_client_api.c b/src/iperf_client_api.c index efd4a41d1..273901be9 100644 --- a/src/iperf_client_api.c +++ b/src/iperf_client_api.c @@ -351,7 +351,7 @@ iperf_connect(struct iperf_test *test) /* Create and connect the control channel */ if (test->ctrl_sck < 0) // Create the control channel using an ephemeral port - test->ctrl_sck = netdial(test->settings->domain, Ptcp, test->bind_address, 0, test->server_hostname, test->server_port, test->settings->connect_timeout); + test->ctrl_sck = netdial(test->settings->domain, Ptcp, test->bind_address, test->bind_dev, 0, test->server_hostname, test->server_port, test->settings->connect_timeout); if (test->ctrl_sck < 0) { i_errno = IECONNECT; return -1; diff --git a/src/iperf_config.h.in b/src/iperf_config.h.in index 1a7cbecef..a8aec642a 100644 --- a/src/iperf_config.h.in +++ b/src/iperf_config.h.in @@ -48,6 +48,9 @@ /* Define to 1 if you have the `SetProcessAffinityMask' function. */ #undef HAVE_SETPROCESSAFFINITYMASK +/* Have SO_BINDTODEVICE sockopt. */ +#undef HAVE_SO_BINDTODEVICE + /* Have SO_MAX_PACING_RATE sockopt. */ #undef HAVE_SO_MAX_PACING_RATE diff --git a/src/iperf_locale.c b/src/iperf_locale.c index 60f1b9cd5..58c827937 100644 --- a/src/iperf_locale.c +++ b/src/iperf_locale.c @@ -105,6 +105,9 @@ const char usage_longstr[] = "Usage: iperf3 [-s|-c host] [options]\n" " -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" +#endif /* HAVE_SO_BINDTODEVICE */ " -V, --verbose more detailed output\n" " -J, --json output in JSON format\n" " --logfile f send output to a log file\n" @@ -233,6 +236,9 @@ const char client_port[] = const char bind_address[] = "Binding to local address %s\n"; +const char bind_dev[] = +"Binding to local network device %s\n"; + const char bind_port[] = "Binding to local port %s\n"; diff --git a/src/iperf_locale.h b/src/iperf_locale.h index 15bdcdb0b..47cf416ae 100644 --- a/src/iperf_locale.h +++ b/src/iperf_locale.h @@ -36,6 +36,7 @@ extern const char seperator_line[]; extern const char server_port[] ; extern const char client_port[] ; extern const char bind_address[] ; +extern const char bind_dev[] ; extern const char multicast_ttl[] ; extern const char join_multicast[] ; extern const char client_datagram_size[] ; diff --git a/src/iperf_sctp.c b/src/iperf_sctp.c index e0c1ec111..0686fd954 100644 --- a/src/iperf_sctp.c +++ b/src/iperf_sctp.c @@ -211,6 +211,21 @@ iperf_sctp_listen(struct iperf_test *test) } } + if (test->bind_dev) { +#if defined(SO_BINDTODEVICE) + if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, + test->bind_dev, IFNAMSIZ) < 0) +#endif // SO_BINDTODEVICE + { + saved_errno = errno; + close(s); + freeaddrinfo(res); + i_errno = IEBINDDEV; + errno = saved_errno; + return -1; + } + } + #if defined(IPV6_V6ONLY) && !defined(__OpenBSD__) if (res->ai_family == AF_INET6 && (test->settings->domain == AF_UNSPEC || test->settings->domain == AF_INET6)) { @@ -284,7 +299,7 @@ iperf_sctp_connect(struct iperf_test *test) #if defined(HAVE_SCTP_H) int s, opt, saved_errno; char portstr[6]; - struct addrinfo hints, *local_res, *server_res; + struct addrinfo hints, *local_res = NULL, *server_res = NULL; if (test->bind_address) { memset(&hints, 0, sizeof(hints)); @@ -309,8 +324,7 @@ iperf_sctp_connect(struct iperf_test *test) s = socket(server_res->ai_family, SOCK_STREAM, IPPROTO_SCTP); if (s < 0) { - if (test->bind_address) - freeaddrinfo(local_res); + freeaddrinfo(local_res); freeaddrinfo(server_res); i_errno = IESTREAMCONNECT; return -1; @@ -336,6 +350,22 @@ iperf_sctp_connect(struct iperf_test *test) } } + if (test->bind_dev) { +#if defined(SO_BINDTODEVICE) + if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, + test->bind_dev, IFNAMSIZ) < 0) +#endif // SO_BINDTODEVICE + { + saved_errno = errno; + close(s); + freeaddrinfo(local_res); + freeaddrinfo(server_res); + i_errno = IEBINDDEV; + errno = saved_errno; + return -1; + } + } + /* * Various ways to bind the local end of the connection. * 1. --bind (with or without --cport). diff --git a/src/iperf_server_api.c b/src/iperf_server_api.c index da91ee250..34662f4e7 100644 --- a/src/iperf_server_api.c +++ b/src/iperf_server_api.c @@ -70,7 +70,7 @@ int iperf_server_listen(struct iperf_test *test) { retry: - if((test->listener = netannounce(test->settings->domain, Ptcp, test->bind_address, test->server_port)) < 0) { + if((test->listener = netannounce(test->settings->domain, Ptcp, test->bind_address, test->bind_dev, test->server_port)) < 0) { if (errno == EAFNOSUPPORT && (test->settings->domain == AF_INET6 || test->settings->domain == AF_UNSPEC)) { /* If we get "Address family not supported by protocol", that ** probably means we were compiled with IPv6 but the running @@ -609,7 +609,7 @@ iperf_run_server(struct iperf_test *test) FD_CLR(test->listener, &test->read_set); close(test->listener); test->listener = 0; - if ((s = netannounce(test->settings->domain, Ptcp, test->bind_address, test->server_port)) < 0) { + if ((s = netannounce(test->settings->domain, Ptcp, test->bind_address, test->bind_dev, test->server_port)) < 0) { cleanup_server(test); i_errno = IELISTEN; return -1; diff --git a/src/iperf_udp.c b/src/iperf_udp.c index 2fd7bf5de..126cd639f 100644 --- a/src/iperf_udp.c +++ b/src/iperf_udp.c @@ -440,7 +440,7 @@ iperf_udp_accept(struct iperf_test *test) /* * Create a new "listening" socket to replace the one we were using before. */ - test->prot_listener = netannounce(test->settings->domain, Pudp, test->bind_address, test->server_port); + test->prot_listener = netannounce(test->settings->domain, Pudp, test->bind_address, test->bind_dev, test->server_port); if (test->prot_listener < 0) { i_errno = IESTREAMLISTEN; return -1; @@ -472,7 +472,7 @@ iperf_udp_listen(struct iperf_test *test) { int s; - if ((s = netannounce(test->settings->domain, Pudp, test->bind_address, test->server_port)) < 0) { + if ((s = netannounce(test->settings->domain, Pudp, test->bind_address, test->bind_dev, test->server_port)) < 0) { i_errno = IESTREAMLISTEN; return -1; } @@ -499,7 +499,7 @@ iperf_udp_connect(struct iperf_test *test) int rc; /* Create and bind our local socket. */ - if ((s = netdial(test->settings->domain, Pudp, test->bind_address, test->bind_port, test->server_hostname, test->server_port, -1)) < 0) { + if ((s = netdial(test->settings->domain, Pudp, test->bind_address, test->bind_dev, test->bind_port, test->server_hostname, test->server_port, -1)) < 0) { i_errno = IESTREAMCONNECT; return -1; } diff --git a/src/iperf_util.c b/src/iperf_util.c index 9ca1eecd2..d54cdf284 100644 --- a/src/iperf_util.c +++ b/src/iperf_util.c @@ -317,6 +317,16 @@ get_optional_features(void) numfeatures++; #endif /* HAVE_SSL */ +#if defined(HAVE_SO_BINDTODEVICE) + if (numfeatures > 0) { + strncat(features, ", ", + sizeof(features) - strlen(features) - 1); + } + strncat(features, "bind to device", + sizeof(features) - strlen(features) - 1); + numfeatures++; +#endif /* HAVE_SO_BINDTODEVICE */ + if (numfeatures == 0) { strncat(features, "None", sizeof(features) - strlen(features) - 1); diff --git a/src/libiperf.3 b/src/libiperf.3 index e88516d86..a91e882c7 100644 --- a/src/libiperf.3 +++ b/src/libiperf.3 @@ -25,6 +25,7 @@ Setting test parameters: .nf void iperf_set_test_role( struct iperf_test *pt, char role ); void iperf_set_test_bind_address( struct iperf_test *t, char *bind_address ); + void iperf_set_test_bind_dev( struct iperf_test *t, char *bind_dev ); void iperf_set_test_server_hostname( struct iperf_test *t, char *server_host ); void iperf_set_test_server_port( struct iperf_test *t, int server_port ); void iperf_set_test_duration( struct iperf_test *t, int duration ); diff --git a/src/net.c b/src/net.c index 8fde9c38d..bc44aee4a 100644 --- a/src/net.c +++ b/src/net.c @@ -61,6 +61,7 @@ #include #endif /* HAVE_POLL_H */ +#include "iperf.h" #include "iperf_util.h" #include "net.h" #include "timer.h" @@ -121,9 +122,9 @@ timeout_connect(int s, const struct sockaddr *name, socklen_t namelen, /* make connection to server */ int -netdial(int domain, int proto, const char *local, int local_port, const char *server, int port, int timeout) +netdial(int domain, int proto, const char *local, const char *bind_dev, int local_port, const char *server, int port, int timeout) { - struct addrinfo hints, *local_res, *server_res; + struct addrinfo hints, *local_res = NULL, *server_res = NULL; int s, saved_errno; if (local) { @@ -148,6 +149,21 @@ netdial(int domain, int proto, const char *local, int local_port, const char *se return -1; } + if (bind_dev) { +#if defined(HAVE_SO_BINDTODEVICE) + if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, + bind_dev, IFNAMSIZ) < 0) +#endif // HAVE_SO_BINDTODEVICE + { + saved_errno = errno; + close(s); + freeaddrinfo(local_res); + freeaddrinfo(server_res); + errno = saved_errno; + return -1; + } + } + /* Bind the local address if given a name (with or without --cport) */ if (local) { if (local_port) { @@ -218,7 +234,7 @@ netdial(int domain, int proto, const char *local, int local_port, const char *se /***************************************************************/ int -netannounce(int domain, int proto, const char *local, int port) +netannounce(int domain, int proto, const char *local, const char *bind_dev, int port) { struct addrinfo hints, *res; char portstr[6]; @@ -255,6 +271,20 @@ netannounce(int domain, int proto, const char *local, int port) return -1; } + if (bind_dev) { +#if defined(HAVE_SO_BINDTODEVICE) + if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, + bind_dev, IFNAMSIZ) < 0) +#endif // HAVE_SO_BINDTODEVICE + { + saved_errno = errno; + close(s); + freeaddrinfo(res); + errno = saved_errno; + return -1; + } + } + opt = 1; if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &opt, sizeof(opt)) < 0) { diff --git a/src/net.h b/src/net.h index 80a2161b6..44c0d7efe 100644 --- a/src/net.h +++ b/src/net.h @@ -28,8 +28,8 @@ #define __NET_H int timeout_connect(int s, const struct sockaddr *name, socklen_t namelen, int timeout); -int netdial(int domain, int proto, const char *local, int local_port, const char *server, int port, int timeout); -int netannounce(int domain, int proto, const char *local, int port); +int netdial(int domain, int proto, const char *local, const char *bind_dev, int local_port, const char *server, int port, int timeout); +int netannounce(int domain, int proto, const char *local, const char *bind_dev, int port); int Nread(int fd, char *buf, size_t count, int prot); int Nwrite(int fd, const char *buf, size_t count, int prot) /* __attribute__((hot)) */; int has_sendfile(void);