diff --git a/backport-ping-Print-reply-from-Subnet-Router-anycast-address.patch b/backport-ping-Print-reply-from-Subnet-Router-anycast-address.patch new file mode 100644 index 0000000000000000000000000000000000000000..6089eab3660e294cf9e0efb1d120fde5990ba6b2 --- /dev/null +++ b/backport-ping-Print-reply-from-Subnet-Router-anycast-address.patch @@ -0,0 +1,129 @@ +From 15a5e5c7aace5a7a782ff802988e04ed4c1148a5 Mon Sep 17 00:00:00 2001 +From: Petr Vorel +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 +--- + 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)) diff --git a/backport-ping-Print-reply-with-wrong-source-with-warning.patch b/backport-ping-Print-reply-with-wrong-source-with-warning.patch new file mode 100644 index 0000000000000000000000000000000000000000..665b9de7afd9cf19bf0e3597cf511f5ed2c5afda --- /dev/null +++ b/backport-ping-Print-reply-with-wrong-source-with-warning.patch @@ -0,0 +1,145 @@ +From 5f6bec5ab57cc8beaa78f5756a0ffbdf01f28d36 Mon Sep 17 00:00:00 2001 +From: Petr Vorel +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 +Signed-off-by: Petr Vorel +--- + 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); diff --git a/iputils.spec b/iputils.spec index 499a5f46fd82465ca80a2c946af941b5294efee6..ba58c033206ebd4ece588722f09059fa003e8207 100644 --- a/iputils.spec +++ b/iputils.spec @@ -1,6 +1,6 @@ Name: iputils Version: 20210722 -Release: 4 +Release: 5 Summary: Network monitoring tools including ping License: BSD and GPLv2+ 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 Patch0006: backport-ping6-Avoid-binding-to-non-VRF.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: docbook5-style-xsl systemd iproute glibc-kernheaders gettext @@ -118,6 +120,12 @@ install -cp ifenslave.8 ${RPM_BUILD_ROOT}%{_mandir}/man8/ %{_unitdir}/ninfod.service %changelog +* Sat May 07 2022 eaglegai - 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 - 20210722-4 - Type:bugfix - ID:NA