On Fri, Feb 18, 2022 at 04:03:28PM +0100, Florian Obser wrote:
> On 2022-02-18 12:17 +10, Jonathan Matthew <[email protected]> wrote:
> > The only thing ping uses to determine whether a received icmp echo reply
> > packet is a
> > response to one of its requests is the 16 bit icmp ident field. If you
> > ping enough
> > stuff at the same time, eventually you'll have two concurrent pings using
> > the same ident,
> > and they will both see each other's replies. Since we do tricky MAC stuff
> > on the ping
> > payload, this results in signature mismatches that look like this:
> >
> > PING 172.23.94.210 (172.23.94.210): 56 data bytes
> > 64 bytes from 172.23.94.210: icmp_seq=0 ttl=253 time=0.820 ms
> > 64 bytes from 172.23.94.210: icmp_seq=1 ttl=253 time=0.419 ms
> > 64 bytes from 172.23.94.210: icmp_seq=2 ttl=253 time=0.369 ms
> > signature mismatch!
> > 64 bytes from 172.23.94.210: icmp_seq=3 ttl=253 time=0.273 ms
> >
> > --- 172.23.94.210 ping statistics ---
> > 4 packets transmitted, 5 packets received, -- somebody's duplicating
> > packets!
> > round-trip min/avg/max/std-dev = 0.273/0.376/0.820/0.265 ms
> >
> > ping is counting the packet with the signature mismatch as a reply it
> > received, and it
> > prints a misleading message about duplicated packets because it got more
> > replies than
> > the number of requests it sent.
> >
> > I think it would be more helpful not to count signature mismatch packets as
> > replies.
> > If you're actually getting corrupted replies, I'd say that's more like
> > packet loss
> > than normal operation. If you're getting extra replies due to ident
> > collisions, this
> > will result in ping sending and receiving the expected number of packets.
> >
> > Printing the source address and sequence number on signature mismatches
> > would also help.
> > I would have figured this out much quicker had ping told me the mismatch
> > packets were
> > from a completely different source. For example:
> >
> > PING 172.23.94.210 (172.23.94.210): 56 data bytes
> > 64 bytes from 172.23.94.210: icmp_seq=0 ttl=253 time=2.645 ms
> > 64 bytes from 172.23.94.210: icmp_seq=1 ttl=253 time=1.360 ms
> > 64 bytes from 172.23.94.210: icmp_seq=2 ttl=253 time=0.506 ms
> > 64 bytes from 172.23.94.210: icmp_seq=3 ttl=253 time=0.615 ms
> > signature mismatch from 10.138.79.45: icmp_seq=0
> > 64 bytes from 172.23.94.210: icmp_seq=4 ttl=253 time=0.431 ms
> >
> > --- 172.23.94.210 ping statistics ---
> > 5 packets transmitted, 5 packets received, 0.0% packet loss
> > round-trip min/avg/max/std-dev = 0.431/1.111/2.645/0.835 ms
> >
> > ok?
>
> OK florian
>
> I think we can go further and also check the from address in the echo
> reply case, like this.
>
> If something on the path is so confused as to answer to our pings with
> the wrong source address I think it's tcpdump time...
>
> Feel free to put this in at the same time if you agree.
I considered doing this, but I think I'd rather have ping print out
anything it sees with the same ident, as long as it doesn't get confused
and mess up its statistics.
>
> diff --git sbin/ping/ping.c sbin/ping/ping.c
> index 6fa634bca3e..e47baa8912c 100644
> --- sbin/ping/ping.c
> +++ sbin/ping/ping.c
> @@ -181,6 +181,9 @@ char *hostname;
> int ident; /* random number to identify our packets */
> int v6flag; /* are we ping6? */
>
> +struct sockaddr_in dst4;
> +struct sockaddr_in6 dst6;
> +
> /* counters */
> int64_t npackets; /* max packets to transmit */
> int64_t nreceived; /* # of packets we got back */
> @@ -243,8 +246,8 @@ main(int argc, char *argv[])
> struct addrinfo hints, *res;
> struct itimerval itimer;
> struct sockaddr *from, *dst;
> - struct sockaddr_in from4, dst4;
> - struct sockaddr_in6 from6, dst6;
> + struct sockaddr_in from4;
> + struct sockaddr_in6 from6;
> struct cmsghdr *scmsg = NULL;
> struct in6_pktinfo *pktinfo = NULL;
> struct icmp6_filter filt;
> @@ -1285,6 +1288,13 @@ pr_pack(u_char *buf, int cc, struct msghdr *mhdr)
> }
>
> if (echo_reply) {
> + if (v6flag) {
> + if (memcmp(&dst6, from, sizeof(dst6)) != 0)
> + return; /* 'Twas not our ECHO */
> + } else {
> + if (memcmp(&dst4, from, sizeof(dst4)) != 0)
> + return; /* 'Twas not our ECHO */
> + }
> ++nreceived;
> if (cc >= ECHOLEN + ECHOTMLEN) {
> SIPHASH_CTX ctx;
> @@ -1302,7 +1312,10 @@ pr_pack(u_char *buf, int cc, struct msghdr *mhdr)
>
> if (timingsafe_memcmp(mac, &payload.mac,
> sizeof(mac)) != 0) {
> - printf("signature mismatch!\n");
> + printf("signature mismatch from %s: "
> + "icmp_seq=%u\n", pr_addr(from, fromlen),
> + ntohs(seq));
> + --nreceived;
> return;
> }
> timinginfo=1;
>
>
> >
> > Index: ping.c
> > ===================================================================
> > RCS file: /cvs/src/sbin/ping/ping.c,v
> > retrieving revision 1.245
> > diff -u -p -r1.245 ping.c
> > --- ping.c 12 Jul 2021 15:09:19 -0000 1.245
> > +++ ping.c 18 Feb 2022 01:52:22 -0000
> > @@ -1302,7 +1302,10 @@ pr_pack(u_char *buf, int cc, struct msgh
> >
> > if (timingsafe_memcmp(mac, &payload.mac,
> > sizeof(mac)) != 0) {
> > - printf("signature mismatch!\n");
> > + printf("signature mismatch from %s: "
> > + "icmp_seq=%u\n", pr_addr(from, fromlen),
> > + ntohs(seq));
> > + --nreceived;
> > return;
> > }
> > timinginfo=1;
> >
>
> --
> I'm not entirely sure you are real.