From 966b989ddfddf4327fff89a0dfdc5f723367228d Mon Sep 17 00:00:00 2001 From: meijian Date: Fri, 14 Mar 2025 17:23:30 +0800 Subject: [PATCH 1/2] ping: add -I for bind device Add -I option to specify the network device to use for sending ICMP echo requests. This allows users to explicitly bind ping to a specific network interface, which is particularly useful in multi-homed systems with multiple network interfaces. Signed-off-by: meijian --- include/netutils/icmp_ping.h | 4 ++++ include/netutils/icmpv6_ping.h | 4 ++++ netutils/ping/icmp_ping.c | 14 ++++++++++++++ netutils/ping/icmpv6_ping.c | 14 ++++++++++++++ system/ping/ping.c | 17 ++++++++++++++++- system/ping6/ping6.c | 17 ++++++++++++++++- 6 files changed, 68 insertions(+), 2 deletions(-) diff --git a/include/netutils/icmp_ping.h b/include/netutils/icmp_ping.h index eec500de965..3f8d6c29d86 100644 --- a/include/netutils/icmp_ping.h +++ b/include/netutils/icmp_ping.h @@ -50,6 +50,7 @@ #define ICMP_E_POLL -11 /* extra: error code */ #define ICMP_E_RECVFROM -13 /* extra: error code */ #define ICMP_E_RECVSMALL -15 /* extra: recv bytes */ +#define ICMP_E_BINDDEV -17 /* extra: error bind */ /* Negative even number represent warning(recoverable) */ @@ -70,6 +71,9 @@ struct ping_result_s; struct ping_info_s { FAR const char *hostname; /* Host name to ping */ +#ifdef CONFIG_NET_BINDTODEVICE + FAR const char *devname; /* Device name to bind */ +#endif uint16_t count; /* Number of pings requested */ uint16_t datalen; /* Number of bytes to be sent */ uint16_t delay; /* Deciseconds to delay between pings */ diff --git a/include/netutils/icmpv6_ping.h b/include/netutils/icmpv6_ping.h index 3f793f74166..33db0fc6f61 100644 --- a/include/netutils/icmpv6_ping.h +++ b/include/netutils/icmpv6_ping.h @@ -50,6 +50,7 @@ #define ICMPv6_E_POLL -11 /* extra: error code */ #define ICMPv6_E_RECVFROM -13 /* extra: error code */ #define ICMPv6_E_RECVSMALL -15 /* extra: recv bytes */ +#define ICMPV6_E_BINDDEV -17 /* extra: error bind */ /* Negative even number represent warning(recoverable) */ @@ -70,6 +71,9 @@ struct ping6_result_s; struct ping6_info_s { FAR const char *hostname; /* Host name to ping */ +#ifdef CONFIG_NET_BINDTODEVICE + FAR const char *devname; /* Device name to bind */ +#endif uint16_t count; /* Number of pings requested */ uint16_t datalen; /* Number of bytes to be sent */ uint16_t delay; /* Deciseconds to delay between pings */ diff --git a/netutils/ping/icmp_ping.c b/netutils/ping/icmp_ping.c index efbc8a61a78..7aa1d397390 100644 --- a/netutils/ping/icmp_ping.c +++ b/netutils/ping/icmp_ping.c @@ -232,6 +232,20 @@ void icmp_ping(FAR const struct ping_info_s *info) return; } +#ifdef CONFIG_NET_BINDTODEVICE + if (info->devname) + { + ret = setsockopt(priv->sockfd, SOL_SOCKET, SO_BINDTODEVICE, + info->devname, strlen(info->devname)); + if (ret < 0) + { + icmp_callback(&result, ICMP_E_BINDDEV, errno); + free(priv); + return; + } + } +#endif + priv->kickoff = clock(); memset(&priv->destaddr, 0, sizeof(struct sockaddr_in)); diff --git a/netutils/ping/icmpv6_ping.c b/netutils/ping/icmpv6_ping.c index 74cd59ee975..e6a93fc986e 100644 --- a/netutils/ping/icmpv6_ping.c +++ b/netutils/ping/icmpv6_ping.c @@ -218,6 +218,20 @@ void icmp6_ping(FAR const struct ping6_info_s *info) return; } +#ifdef CONFIG_NET_BINDTODEVICE + if (info->devname) + { + ret = setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, + info->devname, strlen(info->devname)); + if (ret < 0) + { + icmp6_callback(&result, ICMPV6_E_BINDDEV, errno); + free(iobuffer); + return; + } + } +#endif + kickoff = clock(); memset(&destaddr, 0, sizeof(struct sockaddr_in6)); diff --git a/system/ping/ping.c b/system/ping/ping.c index 804522112b7..1abee622a83 100644 --- a/system/ping/ping.c +++ b/system/ping/ping.c @@ -100,6 +100,7 @@ static void show_usage(FAR const char *progname, int exitcode) printf(" -s specifies the number of data bytes to be sent. " "Default %u.\n", ICMP_PING_DATALEN); + printf(" -I is the bind device for traffic\n"); printf(" -h shows this text and exits.\n"); exit(exitcode); } @@ -172,6 +173,12 @@ static void ping_result(FAR const struct ping_result_s *result) fprintf(stderr, "ERROR: short ICMP packet: %ld\n", result->extra); break; +#ifdef CONFIG_NET_BINDTODEVICE + case ICMP_E_BINDDEV: + fprintf(stderr, "ERROR: setsockopt error: %ld\n", result->extra); + break; +#endif + case ICMP_W_IDDIFF: fprintf(stderr, "WARNING: Ignoring ICMP reply with ID %ld. " @@ -300,7 +307,7 @@ int main(int argc, FAR char *argv[]) exitcode = EXIT_FAILURE; - while ((option = getopt(argc, argv, ":c:i:W:s:h")) != ERROR) + while ((option = getopt(argc, argv, ":c:i:W:s:I:h")) != ERROR) { switch (option) { @@ -360,6 +367,14 @@ int main(int argc, FAR char *argv[]) } break; + case 'I': +#ifdef CONFIG_NET_BINDTODEVICE + info.devname = optarg; +#else + fprintf(stderr, "ERROR: Bind to device not supported\n"); +#endif + break; + case 'h': exitcode = EXIT_SUCCESS; goto errout_with_usage; diff --git a/system/ping6/ping6.c b/system/ping6/ping6.c index 5d18637b832..409f3db0eec 100644 --- a/system/ping6/ping6.c +++ b/system/ping6/ping6.c @@ -100,6 +100,7 @@ static void show_usage(FAR const char *progname, int exitcode) printf(" -s specifies the number of data bytes to be sent. " " Default %u.\n", ICMPv6_PING6_DATALEN); + printf(" -I is the bind device for traffic\n"); printf(" -h shows this text and exits.\n"); exit(exitcode); } @@ -176,6 +177,12 @@ static void ping6_result(FAR const struct ping6_result_s *result) result->extra, result->id); break; +#ifdef CONFIG_NET_BINDTODEVICE + case ICMPV6_E_BINDDEV: + fprintf(stderr, "ERROR: setsockopt error: %ld\n", result->extra); + break; +#endif + case ICMPv6_W_SEQNOBIG: fprintf(stderr, "WARNING: Ignoring ICMP reply to sequence %ld. " @@ -295,7 +302,7 @@ int main(int argc, FAR char *argv[]) exitcode = EXIT_FAILURE; - while ((option = getopt(argc, argv, ":c:i:W:s:h")) != ERROR) + while ((option = getopt(argc, argv, ":c:i:W:s:I:h")) != ERROR) { switch (option) { @@ -355,6 +362,14 @@ int main(int argc, FAR char *argv[]) } break; + case 'I': +#ifdef CONFIG_NET_BINDTODEVICE + info.devname = optarg; +#else + fprintf(stderr, "ERROR: Bind to device not supported\n"); +#endif + break; + case 'h': exitcode = EXIT_SUCCESS; goto errout_with_usage; From 9b730b237e21e27b95a274bde82dbc38614ed625 Mon Sep 17 00:00:00 2001 From: wangchen Date: Tue, 25 Mar 2025 10:28:05 +0800 Subject: [PATCH 2/2] ping: Initialize info.devname to NULL Initialize info.devname to NULL to solve the problem of the SO-BINDTODEVICE property being set incorrectly in the icmp_ping function Signed-off-by: wangchen --- system/ping/ping.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/system/ping/ping.c b/system/ping/ping.c index 1abee622a83..f294983a105 100644 --- a/system/ping/ping.c +++ b/system/ping/ping.c @@ -296,6 +296,9 @@ int main(int argc, FAR char *argv[]) info.delay = ICMP_POLL_DELAY; info.timeout = ICMP_POLL_DELAY; info.callback = ping_result; +#ifdef CONFIG_NET_BINDTODEVICE + info.devname = NULL; +#endif info.priv = &priv; priv.code = ICMP_I_OK; priv.tmin = LONG_MAX;