From 0a3629be6682d1bf2b6aa19938ede35a10c64393 Mon Sep 17 00:00:00 2001 From: Jan Macku Date: Thu, 8 Jun 2023 14:46:29 +0200 Subject: [PATCH] add support for VRF with ping command Resolves: #2208409 --- ...ow-user-to-specify-VRF-and-source-IP.patch | 131 ++++++++++++++++++ iputils.spec | 9 +- 2 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 0007-ping-allow-user-to-specify-VRF-and-source-IP.patch diff --git a/0007-ping-allow-user-to-specify-VRF-and-source-IP.patch b/0007-ping-allow-user-to-specify-VRF-and-source-IP.patch new file mode 100644 index 0000000..e44f57b --- /dev/null +++ b/0007-ping-allow-user-to-specify-VRF-and-source-IP.patch @@ -0,0 +1,131 @@ +From 2cc34ea408602f84fe102598ca258126531736c9 Mon Sep 17 00:00:00 2001 +From: Jon Harrison +Date: Tue, 9 Jul 2019 16:48:07 +0100 +Subject: [PATCH] ping: allow user to specify VRF and source IP +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Without this, the options for sending a ping in the context of a VRF are +limited. + +We can send a ping with a specific source IP address. For example: + + ping 10.1.1.3 -I 10.1.1.2 + +We can send a ping in the context of a Linux VRF. For example: + + ping 10.1.1.3 -I vrf_red + +However, when pinging in the context of a VRF, Linux does not always choose +a sensible source IP address – the source IP might not belong to the VRF. +As a result, the ping won’t get a response. As a result, we want to be able +to specify both a VRF and a source IP address when initiating a ping. For +example: + + ping 10.1.1.3 -I vrf_red -I 10.1.1.2 + +Ping reads in the command line parameters fine and sets up the 'source' and +'device' variables, but currently ignores the device if the source IP +address is non-zero. This commit adds a branch to ping.c that does the +socket bind to the device even in the case where the source IP is non-zero. +This branch is based on the existing case where source IP is zero, but +simplified a bit because we've already got a source IP address to use. + +(cherry picked from commit 9e08707d743b29e853df81bd7def1729e3afe55d) +--- + doc/ping.xml | 15 ++++++++++----- + ping.c | 44 +++++++++++++++++++++++++++++++++++++++++--- + 2 files changed, 51 insertions(+), 8 deletions(-) + +diff --git a/doc/ping.xml b/doc/ping.xml +index bdf07b3..034e40c 100644 +--- a/doc/ping.xml ++++ b/doc/ping.xml +@@ -158,11 +158,16 @@ to values less than 0.2 seconds. + + interface + +-interface is either an address, or an interface name. +-If interface is an address, it sets source address +-to specified interface address. +-If interface in an interface name, it sets +-source interface to specified interface. ++interface is either an ++address, an interface name or a VRF name. If ++interface is an address, it ++sets source address to specified interface address. If ++interface is an interface ++name, it sets source interface to specified interface. ++If interface is a VRF ++name, each packet is routed using the corresponding ++routing table; in this case, the option ++can be repeated to specify a source address. + NOTE: For IPv6, when doing ping to a link-local scope + address, link specification (by the '%'-notation in + destination, or by this option) +diff --git a/ping.c b/ping.c +index c870390..0f87723 100644 +--- a/ping.c ++++ b/ping.c +@@ -705,7 +705,43 @@ int ping4_run(int argc, char **argv, struct addrinfo *ai, socket_st *sock) + } + #endif + close(probe_fd); +- } while (0); ++ ++ } else if (device) { ++ struct sockaddr_in dst = whereto; ++ struct ifreq ifr; ++ int fd = sock->fd; ++ int rc; ++ int errno_save; ++ ++ memset(&ifr, 0, sizeof(ifr)); ++ strncpy(ifr.ifr_name, device, IFNAMSIZ - 1); ++ ++ enable_capability_raw(); ++ rc = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, device, strlen(device) + 1); ++ errno_save = errno; ++ disable_capability_raw(); ++ ++ if (rc == -1) { ++ if (IN_MULTICAST(ntohl(dst.sin_addr.s_addr))) { ++ struct ip_mreqn imr; ++ ++ if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0) { ++ fprintf(stderr, "ping: %s: %s\n", "(\"unknown interface\")", device); ++ exit(2); ++ } ++ memset(&imr, 0, sizeof(imr)); ++ imr.imr_ifindex = ifr.ifr_ifindex; ++ if (setsockopt(fd, SOL_IP, IP_MULTICAST_IF, ++ &imr, sizeof(imr)) == -1) { ++ fprintf(stderr, "ping: IP_MULTICAST_IF: %s\n", strerror(errno)); ++ exit(2); ++ } ++ } else { ++ fprintf(stderr, "ping: SO_BINDTODEVICE %s: %s\n", device, strerror(errno_save)); ++ exit(2); ++ } ++ } ++ } + + if (whereto.sin_addr.s_addr == 0) + whereto.sin_addr.s_addr = source.sin_addr.s_addr; +@@ -957,8 +993,10 @@ int ping4_receive_error_msg(socket_st *sock) + (1 << ICMP_REDIRECT) | + (1 << ICMP_ECHOREPLY)); + if (setsockopt(sock->fd, SOL_RAW, ICMP_FILTER, (const void *)&filt, +- sizeof(filt)) == -1) +- error(2, errno, "setsockopt(ICMP_FILTER)"); ++ sizeof(filt)) == -1) { ++ fprintf(stderr, "ping: setsockopt(ICMP_FILTER): %s\n", strerror(errno)); ++ exit(2); ++ } + } + net_errors++; + nerrors++; +-- +2.40.1 + diff --git a/iputils.spec b/iputils.spec index 97c9291..69eff1e 100644 --- a/iputils.spec +++ b/iputils.spec @@ -3,7 +3,7 @@ Summary: Network monitoring tools including ping Name: iputils Version: 20180629 -Release: 10%{?dist} +Release: 11%{?dist} # some parts are under the original BSD (ping.c) # some are under GPLv2+ (tracepath.c) License: BSD and GPLv2+ @@ -26,6 +26,9 @@ Patch4: 0004-tracepath-fix-copying-input-ipv6-address.patch Patch5: 0005-ninfod-change-variable-name-to-avoid-colliding-with-function-name.patch Patch6: 0006-ping-Fix-unwanted-bell-on-unreachable-address.patch +# bz2208409 - [RFE] support VRF with ping command +Patch7: 0007-ping-allow-user-to-specify-VRF-and-source-IP.patch + %if ! 0%{?_module_build} BuildRequires: docbook-utils perl-SGMLSpm %endif @@ -70,6 +73,7 @@ cp %{SOURCE4} %{SOURCE5} . %patch4 -p1 %patch5 -p1 %patch6 -p1 +%patch7 -p1 %build %ifarch s390 s390x @@ -173,6 +177,9 @@ install -m 644 %SOURCE3 ${RPM_BUILD_ROOT}/%{_unitdir} %endif %changelog +* Thu Jun 08 2023 Jan Macku - 20180629-11 +- Add support for VRF with ping command (#2208409) + * Tue Mar 22 2022 Jan Macku - 20180629-10 - Fix regression of output when pinging unreachable IPv6 host (#2057570)