ping: Fix ping6 binding to VRF and address

Resolves: RHEL-57734
This commit is contained in:
Jan Macku 2024-09-06 14:13:23 +02:00
parent 9a14df6b95
commit fa76812bd1
3 changed files with 155 additions and 1 deletions

View File

@ -0,0 +1,95 @@
From 36580e1d539b4bb7c187d4cf9ccc63afad9edbb1 Mon Sep 17 00:00:00 2001
From: Lahav Schlesinger <lschlesinger@drivenets.com>
Date: Wed, 30 Jun 2021 13:06:13 +0300
Subject: [PATCH 1/2] ping: Fix ping6 binding to VRF and address
Since Linux kernel commit 1893ff20275b ("net/ipv6: Add l3mdev check to
ipv6_chk_addr_and_flags") from v4.17-rc1 ping fails when trying to
create IPv6 SOCK_RAW socket (e.g. if net.ipv4.ping_group_range = 1 0)
and passing both -I <vrf_interface> and -I <local_ipv6_addr>.
It works for IPv4 SOCK_RAW socket.
# ip netns add tmp_ns
# ip -n tmp_ns link add vrf_1 type vrf table 10001
# ip -n tmp_ns link add lo10 type dummy
# ip -n tmp_ns link set lo10 master vrf_1
# ip -n tmp_ns link set vrf_1 up
# ip -n tmp_ns link set lo10 up
# ip -n tmp_ns link set lo up
# ip -n tmp_ns addr add 1:2::3:4/128 dev lo10
# ip -n tmp_ns addr add 1.2.3.4/32 dev lo10
# ip netns exec tmp_ns ping -6 1:2::3:4 -I vrf_1 -I 1:2::3:4 -c 1 # IPv6 broken
ping: bind icmp socket: Cannot assign requested address
# ping 1.2.3.4 -I vrf_1 -I 1.2.3.4 -c 1 # IPv4 working
PING 1.2.3.4 (1.2.3.4) from 1.2.3.4 vrf_1: 56(84) bytes of data.
64 bytes from 1.2.3.4: icmp_seq=1 ttl=64 time=0.090 ms
--- 1.2.3.4 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.090/0.090/0.090/0.000 ms
ping fails because it doesn't actually bind to the VRF interface, while
after 1893ff20275b, binding to an IPv6 address searches only on the same
l3mdev as the device the function receives. If the socket wasn't
SO_BINDTODEVICE-ed, then the kernel will only search for devices that
are not ensalved to an l3mdev device (= in the default VRF), which will
cause the bind() to fail.
Only SOCK_RAW socket is affected. SOCK_DGRAM is not affected because
Linux kernel doesn't check the device the socket was SO_BINDTODEVICE-ed
to, but only the device from addr->sin6_scope_id (which if none is
passed, it will again only search devices in the default VRF).
NOTE: creating network namespace to reproduce the issue is needed just
on systems with net.ipv4.ping_group_range = 0 2147483647 (e.g. current
Fedora, openSUSE, Ubuntu), which causes to use SOCK_DGRAM socket.
Alternatively to force SOCK_RAW to it'd be enough just to properly set
net.ipv4.ping_group_range:
# echo "1 0" > /proc/sys/net/ipv4/ping_group_range
Closes: https://github.com/iputils/iputils/pull/344
Reviewed-by: Petr Vorel <pvorel@suse.cz>
Signed-off-by: Lahav Schlesinger <lschlesinger@drivenets.com>
[ pvorel: adjusted commit message ]
Signed-off-by: Petr Vorel <pvorel@suse.cz>
(cherry picked from commit 7c65999f98bc4a1984594b7fad1af0eaf0b9d34b)
---
ping/ping6_common.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/ping/ping6_common.c b/ping/ping6_common.c
index 4712928..98b5adb 100644
--- a/ping/ping6_common.c
+++ b/ping/ping6_common.c
@@ -223,6 +223,8 @@ int ping6_run(struct ping_rts *rts, int argc, char **argv, struct addrinfo *ai,
if (rts->device) {
struct cmsghdr *cmsg;
struct in6_pktinfo *ipi;
+ int rc;
+ int errno_save;
cmsg = (struct cmsghdr *)(rts->cmsgbuf + rts->cmsglen);
rts->cmsglen += CMSG_SPACE(sizeof(*ipi));
@@ -233,6 +235,15 @@ int ping6_run(struct ping_rts *rts, int argc, char **argv, struct addrinfo *ai,
ipi = (struct in6_pktinfo *)CMSG_DATA(cmsg);
memset(ipi, 0, sizeof(*ipi));
ipi->ipi6_ifindex = if_name2index(rts->device);
+
+ enable_capability_raw();
+ rc = setsockopt(sock->fd, SOL_SOCKET, SO_BINDTODEVICE,
+ rts->device, strlen(rts->device) + 1);
+ errno_save = errno;
+ disable_capability_raw();
+
+ if (rc == -1)
+ error(2, errno_save, "SO_BINDTODEVICE %s", rts->device);
}
if (IN6_IS_ADDR_MULTICAST(&rts->whereto6.sin6_addr)) {
--
2.46.0

View File

@ -0,0 +1,54 @@
From a2d2428c5fa6bf370486f509b18862c5c7b8b47e Mon Sep 17 00:00:00 2001
From: Petr Vorel <pvorel@suse.cz>
Date: Tue, 9 Nov 2021 02:39:56 +0100
Subject: [PATCH 2/2] ping6: Avoid binding to non-VRF
This fixes permission issue when specifying just address (without VRF)
unless having CAP_NET_ADMIN (i.e. root) permission:
$ ./builddir/ping/ping -c1 -I lo ::1
./builddir/ping/ping: SO_BINDTODEVICE lo: Operation not permitted
because setsockopt() SO_BINDTODEVICE (similar to bind()) can be only done on
opt_strictsource.
Fixes: 7c65999 ("ping: Fix ping6 binding to VRF and address")
Signed-off-by: Petr Vorel <pvorel@suse.cz>
(cherry picked from commit f52b582248f1f870e870a9973621805d969906b4)
---
ping/ping6_common.c | 18 ++++++++++--------
1 file changed, 10 insertions(+), 8 deletions(-)
diff --git a/ping/ping6_common.c b/ping/ping6_common.c
index 98b5adb..a784be0 100644
--- a/ping/ping6_common.c
+++ b/ping/ping6_common.c
@@ -236,14 +236,16 @@ int ping6_run(struct ping_rts *rts, int argc, char **argv, struct addrinfo *ai,
memset(ipi, 0, sizeof(*ipi));
ipi->ipi6_ifindex = if_name2index(rts->device);
- enable_capability_raw();
- rc = setsockopt(sock->fd, SOL_SOCKET, SO_BINDTODEVICE,
- rts->device, strlen(rts->device) + 1);
- errno_save = errno;
- disable_capability_raw();
-
- if (rc == -1)
- error(2, errno_save, "SO_BINDTODEVICE %s", rts->device);
+ if (rts->opt_strictsource) {
+ enable_capability_raw();
+ rc = setsockopt(sock->fd, SOL_SOCKET, SO_BINDTODEVICE,
+ rts->device, strlen(rts->device) + 1);
+ errno_save = errno;
+ disable_capability_raw();
+
+ if (rc == -1)
+ error(2, errno_save, "SO_BINDTODEVICE %s", rts->device);
+ }
}
if (IN6_IS_ADDR_MULTICAST(&rts->whereto6.sin6_addr)) {
--
2.46.0

View File

@ -3,7 +3,7 @@
Summary: Network monitoring tools including ping Summary: Network monitoring tools including ping
Name: iputils Name: iputils
Version: 20210202 Version: 20210202
Release: 10%{?dist} Release: 11%{?dist}
# some parts are under the original BSD (ping.c) # some parts are under the original BSD (ping.c)
# some are under GPLv2+ (tracepath.c) # some are under GPLv2+ (tracepath.c)
License: BSD and GPLv2+ License: BSD and GPLv2+
@ -29,6 +29,8 @@ Patch007: 007-ping-Move-ping_rts-multicast.patch
Patch008: 008-ping-Print-reply-from-Subnet-Router-anycast-address.patch Patch008: 008-ping-Print-reply-from-Subnet-Router-anycast-address.patch
Patch009: 009-ping-Print-reply-with-wrong-source-with-warning.patch Patch009: 009-ping-Print-reply-with-wrong-source-with-warning.patch
Patch010: 010-ping-Fix-socket-error-reporting.patch Patch010: 010-ping-Fix-socket-error-reporting.patch
Patch011: 011-ping-Fix-ping6-binding-to-VRF-and-address.patch
Patch012: 012-ping6-Avoid-binding-to-non-VRF.patch
# Downstream-only patches # Downstream-only patches
Patch100: 100-iputils-ifenslave.patch Patch100: 100-iputils-ifenslave.patch
@ -139,6 +141,9 @@ install -cp ifenslave.8 ${RPM_BUILD_ROOT}%{_mandir}/man8/
%attr(644,root,root) %{_mandir}/man8/ninfod.8.gz %attr(644,root,root) %{_mandir}/man8/ninfod.8.gz
%changelog %changelog
* Fri Sep 06 2024 Jan Macku <jamacku@redhat.com> - 20210202-11
- ping: Fix ping6 binding to VRF and address (RHEL-57734)
* Wed Aug 28 2024 Jan Macku <jamacku@redhat.com> - 20210202-10 * Wed Aug 28 2024 Jan Macku <jamacku@redhat.com> - 20210202-10
- arping: Fix 1s delay on exit for unsolicited arpings (RHEL-34110) - arping: Fix 1s delay on exit for unsolicited arpings (RHEL-34110)
- arping: exit 0 if running in deadline mode and we see replies (RHEL-27718) - arping: exit 0 if running in deadline mode and we see replies (RHEL-27718)