backport to fix no reply when ping6 from Subnet-Router anycast address

This commit is contained in:
eaglegai 2022-05-07 15:09:40 +08:00
parent 6cd556f971
commit 510d40f676
3 changed files with 283 additions and 1 deletions

View File

@ -0,0 +1,129 @@
From 15a5e5c7aace5a7a782ff802988e04ed4c1148a5 Mon Sep 17 00:00:00 2001
From: Petr Vorel <pvorel@suse.cz>
Date: Mon, 18 Oct 2021 15:13:44 +0200
Subject: [PATCH] ping: Print reply from Subnet-Router anycast address
by detecting Subnet-Router address for 64 bit prefix and suppress
address comparison check.
5e052ad ("ping: discard packets with wrong source address") correctly
hid replies with wrong source address to comply RFC 1122 (Section
3.2.1.3: "The IP source address in an ICMP Echo Reply MUST be the same
as the specific-destination address").
While change in 5e052ad works for broadcast and multicast addresses and
some of anycast addresses, it does not work for (at least) Subnet-Router
anycast address):
# VETH1_IPV6=fd00:dead:beef:1234::1
# VPEER1_IPV6=fd00:dead:beef:1234::2
# ip netns add ns-ipv6
# ip li add name veth1 type veth peer name vpeer1
# ip -6 addr add $VETH1_IPV6/64 dev veth1
# ip li set dev veth1 up
# ip li set dev vpeer1 netns ns-ipv6
# ip netns exec ns-ipv6 ip li set dev lo up
# ip netns exec ns-ipv6 ip -6 addr add $VPEER1_IPV6/64 dev vpeer1
# ip netns exec ns-ipv6 ip li set vpeer1 up
# ip netns exec ns-ipv6 ip -6 route add default dev vpeer1 via $VETH1_IPV6
# sysctl -w net.ipv6.conf.all.forwarding=1
$ ping -c1 ff02::1 # anycast - all nodes
PING ff02::1(ff02::1) 56 data bytes
64 bytes from fe80::9c9c:ffff:fe14:e9d2%vpeer1: icmp_seq=1 ttl=64 time=0.064 ms
$ ping -c1 ff02::2 # anycast - all routers
PING ff02::2(ff02::2) 56 data bytes
64 bytes from fe80::5496:9ff:fef5:8f01%vpeer1: icmp_seq=1 ttl=64 time=0.088 ms
$ ping -c1 -W5 fd00:dead:beef:1234:: # Subnet-Router anycast
PING fd00:dead:beef:1234::(fd00:dead:beef:1234::) 56 data bytes
Subnet-Router anycast address works for both busybox ping (without
printing the real source address) and fping:
$ busybox ping -c1 fd00:dead:beef:1234::
PING fd00:dead:beef:1234:: (fd00:dead:beef:1234::): 56 data bytes
64 bytes from fd00:dead:beef:1234::1: seq=0 ttl=64 time=0.122 ms
$ fping -c1 fd00:dead:beef:1234::
[<- fd00:dead:beef:1234::1]fd00:dead:beef:1234:: : [0], 64 bytes, 0.096 ms (0.096 avg, 0% loss)
RFC 4291 specifies Subnet-Router anycast address as [1]:
The Subnet-Router anycast address is predefined. Its format is as
follows:
| n bits | 128-n bits |
+------------------------------------------------+----------------+
| subnet prefix | 00000000000000 |
+------------------------------------------------+----------------+
The "subnet prefix" in an anycast address is the prefix that
identifies a specific link. This anycast address is syntactically
the same as a unicast address for an interface on the link with the
interface identifier set to zero.
=> to detect Subnet-Router anycast address we need to know prefix, which
we don't know, thus detect it for prefix 64 (the default IPv6 prefix).
[1] https://datatracker.ietf.org/doc/html/rfc4291#section-2.6.1
Fixes: 5e052ad ("ping: discard packets with wrong source address")
Closes: https://github.com/iputils/iputils/issues/371
Reported-by: Tim Sandquist
Signed-off-by: Petr Vorel <pvorel@suse.cz>
---
ping/ping.h | 1 +
ping/ping6_common.c | 12 +++++++++++-
2 files changed, 12 insertions(+), 1 deletion(-)
diff --git a/ping/ping.h b/ping/ping.h
index 1be4df58..ce1d719d 100644
--- a/ping/ping.h
+++ b/ping/ping.h
@@ -212,6 +212,7 @@ struct ping_rts {
#endif
/* Used only in ping6_common.c */
+ int subnet_router_anycast; /* Subnet-Router anycast (RFC 4291) */
struct sockaddr_in6 firsthop;
unsigned char cmsgbuf[4096];
size_t cmsglen;
diff --git a/ping/ping6_common.c b/ping/ping6_common.c
index 986210b6..e807070e 100644
--- a/ping/ping6_common.c
+++ b/ping/ping6_common.c
@@ -102,6 +102,7 @@ int ping6_run(struct ping_rts *rts, int argc, char **argv, struct addrinfo *ai,
struct socket_st *sock)
{
int hold, packlen;
+ size_t i;
unsigned char *packet;
char *target;
struct icmp6_filter filter;
@@ -248,6 +249,15 @@ int ping6_run(struct ping_rts *rts, int argc, char **argv, struct addrinfo *ai,
rts->pmtudisc = IPV6_PMTUDISC_DO;
}
+ /* detect Subnet-Router anycast at least for the default prefix 64 */
+ rts->subnet_router_anycast = 1;
+ for (i = 8; i < sizeof(struct in6_addr); i++) {
+ if (rts->whereto6.sin6_addr.s6_addr[i]) {
+ rts->subnet_router_anycast = 0;
+ break;
+ }
+ }
+
if (rts->pmtudisc >= 0) {
if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &rts->pmtudisc,
sizeof rts->pmtudisc) == -1)
@@ -819,7 +829,7 @@ int ping6_parse_reply(struct ping_rts *rts, socket_st *sock,
}
if (icmph->icmp6_type == ICMP6_ECHO_REPLY) {
- if (!rts->multicast &&
+ if (!rts->multicast && !rts->subnet_router_anycast &&
memcmp(&from->sin6_addr.s6_addr, &rts->whereto6.sin6_addr.s6_addr, 16))
return 1;
if (!is_ours(rts, sock, icmph->icmp6_id))

View File

@ -0,0 +1,145 @@
From 5f6bec5ab57cc8beaa78f5756a0ffbdf01f28d36 Mon Sep 17 00:00:00 2001
From: Petr Vorel <pvorel@suse.cz>
Date: Fri, 15 Oct 2021 17:38:51 +0200
Subject: [PATCH] ping: Print reply with wrong source with warning
5e052ad ("ping: discard packets with wrong source address") correctly
hid replies with wrong source address to comply RFC 1122 (Section
3.2.1.3: "The IP source address in an ICMP Echo Reply MUST be the same
as the specific-destination address").
This caused to hide reply when pinging Subnet-Router anycast address.
Although it was fixed in the previous commit, relax this to admit the
reply but print warning "DIFFERENT ADDRESS!". ping is diagnostic program,
with insisting on RFC we force people to use tcpdump to see replies.
Link: https://github.com/iputils/iputils/issues/371
Reviewed-by: Matteo Croce <mcroce@microsoft.com>
Signed-off-by: Petr Vorel <pvorel@suse.cz>
---
ping/ping.c | 10 ++++++----
ping/ping.h | 3 ++-
ping/ping6_common.c | 13 ++++++++-----
ping/ping_common.c | 6 +++++-
4 files changed, 21 insertions(+), 11 deletions(-)
diff --git a/ping/ping.c b/ping/ping.c
index 0655bf4a..81ee7c86 100644
--- a/ping/ping.c
+++ b/ping/ping.c
@@ -1504,6 +1504,7 @@ int ping4_parse_reply(struct ping_rts *rts, struct socket_st *sock,
int reply_ttl;
uint8_t *opts, *tmp_ttl;
int olen;
+ int wrong_source = 0;
/* Check the IP header */
ip = (struct iphdr *)buf;
@@ -1544,15 +1545,16 @@ int ping4_parse_reply(struct ping_rts *rts, struct socket_st *sock,
csfailed = in_cksum((unsigned short *)icp, cc, 0);
if (icp->type == ICMP_ECHOREPLY) {
- if (!rts->broadcast_pings && !rts->multicast &&
- from->sin_addr.s_addr != rts->whereto.sin_addr.s_addr)
- return 1;
if (!is_ours(rts, sock, icp->un.echo.id))
return 1; /* 'Twas not our ECHO */
+
+ if (!rts->broadcast_pings && !rts->multicast &&
+ from->sin_addr.s_addr != rts->whereto.sin_addr.s_addr)
+ wrong_source = 1;
if (gather_statistics(rts, (uint8_t *)icp, sizeof(*icp), cc,
ntohs(icp->un.echo.sequence),
reply_ttl, 0, tv, pr_addr(rts, from, sizeof *from),
- pr_echo_reply, rts->multicast)) {
+ pr_echo_reply, rts->multicast, wrong_source)) {
fflush(stdout);
return 0;
}
diff --git a/ping/ping.h b/ping/ping.h
index ce1d719d..1697c3ec 100644
--- a/ping/ping.h
+++ b/ping/ping.h
@@ -389,7 +389,8 @@ extern void common_options(int ch);
extern int gather_statistics(struct ping_rts *rts, uint8_t *icmph, int icmplen,
int cc, uint16_t seq, int hops,
int csfailed, struct timeval *tv, char *from,
- void (*pr_reply)(uint8_t *ptr, int cc), int multicast);
+ void (*pr_reply)(uint8_t *ptr, int cc), int multicast,
+ int wrong_source);
extern void print_timestamp(struct ping_rts *rts);
void fill(struct ping_rts *rts, char *patp, unsigned char *packet, size_t packet_size);
diff --git a/ping/ping6_common.c b/ping/ping6_common.c
index e807070e..fee11891 100644
--- a/ping/ping6_common.c
+++ b/ping/ping6_common.c
@@ -803,6 +803,7 @@ int ping6_parse_reply(struct ping_rts *rts, socket_st *sock,
struct cmsghdr *c;
struct icmp6_hdr *icmph;
int hops = -1;
+ int wrong_source = 0;
for (c = CMSG_FIRSTHDR(msg); c; c = CMSG_NXTHDR(msg, c)) {
if (c->cmsg_level != IPPROTO_IPV6)
@@ -829,16 +830,18 @@ int ping6_parse_reply(struct ping_rts *rts, socket_st *sock,
}
if (icmph->icmp6_type == ICMP6_ECHO_REPLY) {
- if (!rts->multicast && !rts->subnet_router_anycast &&
- memcmp(&from->sin6_addr.s6_addr, &rts->whereto6.sin6_addr.s6_addr, 16))
- return 1;
if (!is_ours(rts, sock, icmph->icmp6_id))
return 1;
+
+ if (!rts->multicast && !rts->subnet_router_anycast &&
+ memcmp(&from->sin6_addr.s6_addr, &rts->whereto6.sin6_addr.s6_addr, 16))
+ wrong_source = 1;
+
if (gather_statistics(rts, (uint8_t *)icmph, sizeof(*icmph), cc,
ntohs(icmph->icmp6_seq),
hops, 0, tv, pr_addr(rts, from, sizeof *from),
pr_echo_reply,
- rts->multicast)) {
+ rts->multicast, wrong_source)) {
fflush(stdout);
return 0;
}
@@ -851,7 +854,7 @@ int ping6_parse_reply(struct ping_rts *rts, socket_st *sock,
seq,
hops, 0, tv, pr_addr(rts, from, sizeof *from),
pr_niquery_reply,
- rts->multicast))
+ rts->multicast, 0))
return 0;
} else {
int nexthdr;
diff --git a/ping/ping_common.c b/ping/ping_common.c
index 357c39d7..03362590 100644
--- a/ping/ping_common.c
+++ b/ping/ping_common.c
@@ -711,7 +711,8 @@ int main_loop(struct ping_rts *rts, ping_func_set_st *fset, socket_st *sock,
int gather_statistics(struct ping_rts *rts, uint8_t *icmph, int icmplen,
int cc, uint16_t seq, int hops,
int csfailed, struct timeval *tv, char *from,
- void (*pr_reply)(uint8_t *icmph, int cc), int multicast)
+ void (*pr_reply)(uint8_t *icmph, int cc), int multicast,
+ int wrong_source)
{
int dupflag = 0;
long triptime = 0;
@@ -804,10 +805,13 @@ int gather_statistics(struct ping_rts *rts, uint8_t *icmph, int icmplen,
printf(_(" time=%ld.%03ld ms"), triptime / 1000,
triptime % 1000);
}
+
if (dupflag && (!multicast || rts->opt_verbose))
printf(_(" (DUP!)"));
if (csfailed)
printf(_(" (BAD CHECKSUM!)"));
+ if (wrong_source)
+ printf(_(" (DIFFERENT ADDRESS!)"));
/* check the data */
cp = ((unsigned char *)ptr) + sizeof(struct timeval);

View File

@ -1,6 +1,6 @@
Name: iputils Name: iputils
Version: 20210722 Version: 20210722
Release: 4 Release: 5
Summary: Network monitoring tools including ping Summary: Network monitoring tools including ping
License: BSD and GPLv2+ License: BSD and GPLv2+
URL: https://github.com/iputils/iputils URL: https://github.com/iputils/iputils
@ -20,6 +20,8 @@ Patch0004: backport-fix-ARP-protocol-field-for-AX.25-and-NETROM.patch
Patch0005: backport-ping-Fix-ping6-binding-to-VRF-and-address.patch Patch0005: backport-ping-Fix-ping6-binding-to-VRF-and-address.patch
Patch0006: backport-ping6-Avoid-binding-to-non-VRF.patch Patch0006: backport-ping6-Avoid-binding-to-non-VRF.patch
Patch0007: arping-Fix-exit-code-on-w-option.patch Patch0007: arping-Fix-exit-code-on-w-option.patch
Patch0008: backport-ping-Print-reply-from-Subnet-Router-anycast-address.patch
Patch0009: backport-ping-Print-reply-with-wrong-source-with-warning.patch
BuildRequires: gcc meson libidn2-devel openssl-devel libcap-devel libxslt BuildRequires: gcc meson libidn2-devel openssl-devel libcap-devel libxslt
BuildRequires: docbook5-style-xsl systemd iproute glibc-kernheaders gettext BuildRequires: docbook5-style-xsl systemd iproute glibc-kernheaders gettext
@ -118,6 +120,12 @@ install -cp ifenslave.8 ${RPM_BUILD_ROOT}%{_mandir}/man8/
%{_unitdir}/ninfod.service %{_unitdir}/ninfod.service
%changelog %changelog
* Sat May 07 2022 eaglegai <eaglegai@163.com> - 20210722-5
- Type:bugfix
- ID:NA
- SUG:NA
- DESC:backport to fix no reply when ping6 from Subnet-Router anycast address
* Fri May 06 2022 eaglegai <eaglegai@163.com> - 20210722-4 * Fri May 06 2022 eaglegai <eaglegai@163.com> - 20210722-4
- Type:bugfix - Type:bugfix
- ID:NA - ID:NA