#980858 iputils-ping: ping handles link-local addresses in a too smart way

Package:
iputils-ping
Source:
iputils
Description:
Tools to test the reachability of network hosts
Submitter:
Marc SCHAEFER
Date:
2021-01-25 17:33:02 UTC
Severity:
wishlist
#980858#5
Date:
2021-01-23 09:27:24 UTC
From:
To:
Dear Maintainer,

This is puzzling:

  $ telnet fe80::1
   Trying fe80::1...
   telnet: Unable to connect to remote host: Invalid argument
   [ normal behaviour with link-local addresses ]

   schaefer@reliand:~$ telnet -6 fe80::1%eth1
   Trying fe80::1%eth1...
   [also ok: no error, NDP requests sent]

but:

   $ ping6 fe80::1
   PING fe80::1(fe80::1) 56 data bytes
   From fe80::9e8e:99ff:fe3c:5523%eth0: icmp_seq=1 Destination unreachable: Address unreachable

Link-local addresses are ambiguous: they lack the scope ID, unless you specify
the scope with a postfix %iface_name or %iface_id. So why does ping try to
guess which interface is used?

That's the only way it should work:

   $ ping6 fe80::1%eth1
   PING fe80::1%eth0(fe80::1%eth1) 56 data bytes

(or with the -I option).

The manpage says:
       -I 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. NOTE: For IPv6, when doing ping
           to a link-local scope address, link specification (by the
           '%'-notation in destination, or by this option) can be used but it
           is *no longer* required.

And yes, that wrong behaviour is new in buster (correct behaviour in stretch or
jessie).  Maybe that changes was upstream and not intentional (could be linked
to other types of non routed v6 addresses), but it is still puzzling.

There is a lot of of code in ping6_common.c that, if device is unset and
getaddrinfo(3) returns a zero scope ID, tries to probe a scope ID. I do not see
why ping should do that.

#980858#10
Date:
2021-01-23 18:04:00 UTC
From:
To:
This was done upstream here:

https://github.com/iputils/iputils/pull/100

I agree that this is the normal way of fully specifying a link-local
address.  However, rfc 4291 does not prohibit inferring the scope based
on routing tables, as far as I can tell, so I'm not sure that ping's
behavior is outright wrong.

If you can find text in the standards that indicates that ping is
actually behaving incorrectly, then I'm very happy to raise this issue
with upstream, as I don't particularly like the current behavior either.
I just haven't been able to convince myself that it's actually
incorrect.

noah

#980858#15
Date:
2021-01-25 12:19:48 UTC
From:
To:
Interesting. They interpret the fact that link-local works as expected as
`broken', and fixed it.

It is incompatible with telnet and all other utilities I tried, which means
that debugging with ping now is moot.

Reading RFC-4291 [1], 2.5.6 (link-local addresses) and RFC-4007 [2] 6,
Zones Indices:

   Because the same non-global address may be in use in more than one
   zone of the same scope (e.g., the use of link-local address fe80::1
   in two separate physical links) and a node may have interfaces
   attached to different zones of the same scope (e.g., a router
   normally has multiple interfaces attached to different links), a node
   *requires* an internal means to identify to which zone a non-global
   address belongs.  This is accomplished by assigning, within the node,
   a distinct "zone index" to each zone of the same scope to which that
   node is attached, and by allowing all internal uses of an address to
   be qualified by a zone index.

#980858#20
Date:
2021-01-25 16:51:32 UTC
From:
To:
It does not invalidate ping's usefulness for debugging.  When you
specify a scope explicitly, it is respected.  This is exactly the
behavior you need when debugging.

Right.  A scope is required in order to fully specify the address.
That's clear enough.  However, there's nothing in there that forbids a
client from choosing a scope based on routing rules or some other
mechanism when a scope isn't explicitly provided by the user.

noah

#980858#25
Date:
2021-01-25 17:11:47 UTC
From:
To:
I meant:

you configure some service to access [fe80::1]:80

it does not work

you debug with ping fe80::1

it works.

Ok, you ponder. Hmm.  Maybe you think to use

   telnet fe80::1 80

and then you see it does not work and you pat yourself and add %eth1

With pre-buster behaviour, you immediately see the problem with ping.

getaddrinfo(3) does not: it returns a zero scope id, most programs use
getaddrinfo(3) without any additional setting of the scope ID, unlike
ping.

Anyway, if you don't think this is a bug, no matter for me. I know now that
ping does not work like most programs with addresses that requires a
scope ID.

And it is now documented on bugs.debian.org if it needs to be.

#980858#30
Date:
2021-01-25 17:31:14 UTC
From:
To:
For what it's worth, I just checked on NetBSD to see how their ping
behaves, and it also accepts link-local IPv6 addresses without a scope
ID.  Similar to iputils, if a scope ID is unspecified, it chooses one
based on the routing configuration.

This doesn't make the behavior "correct", of course, but it's at least
consistent across implementations, which counts for something.

noah