[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: glibc's getaddrinfo() sort order



Anthony Towns writes ("Re: glibc's getaddrinfo() sort order"):
> I'm not familiar with how getaddrinfo() has been implemented in the
> past

I think this is an important point.  If you're not familiar with the
history then perhaps I can help explain.


hostname-to-address lookups have up to recently generally been done
with gethostbyname.

The addresses from gethostbyname are ordered as they were returned by
the nameserver (unless special configuration is made locally to
override this, which is rarely done).  When multiple addresses are
available for a single lookup, special code in all widely-deployed
nameservers arranges to "rotate" or "round-robin" the returned
addresses: each enquirer gets a new ordering.  This is so that a
single service name can be made to refer to a number of physical
network interfaces (perhaps on different hosts) and the load shared
across them.  This is known as "DNS based load balancing".  If the
protocol is one like mail, where callers can be expected to try
multiple addreses if the first doesn't work, this gives you a failover
as well.

So far so good.  (For clarify, it is the above round-robin
functionality that I am arguing ought to be preserved.)


gethostbyname can theoretically support IPv6 but it can only return
one address type per call.  While there is a way to embed an IPv4
address in an IPv6 address, for circumstances like these, there is no
clear way to tell gethostbyname that the calling application (and the
rest of the stack on which the application relies) will cope with
getting a pile of AF_INET6 back rather than AF_INET.

Therefore for IPv6, a new interface was needed.  The interface
(defined in RFC3493 s6.1 and its predecessors) is getaddrinfo.  It has
several new features most of which aren't relevant here.  The
critical new feature is this:

getaddrinfo allows the application to specify whether it wants to get
only IPv4 addresses or IPv6 addresses as well, and if getting mixed
addresses, whether to encode then as AF_INET or as `v6-mapped'
AF_INET6 (ie, the 32 bits of IPv4 address padded with a specific
prefix to make up an IPv6 address, where the prefix means "no actually
this is not an IPv6 address but an IPv4 address and should be used
with IPv4).

Combined with various other new facilities, this makes it reasonably
straightforward to convert an IPv4-only application to be
IPv6-capable.

So, in summary: getaddrinfo is intended to replace gethostbyname.


However, additionally, it was realised that if getaddrinfo can return
a mixture of IPv4 and v6 addresses it was necessary to specify in what
order they ought to be returned.

When RFC3484 was written its authors evidently felt that the best way
to do this was to define a comparison function over all addresses,
which would define which address was to be preferred.

Heedless of the effect on the DNS round-robin functionality I describe
above, the authors of RFC3484 specified (s6 rule 9) that all addresses
should be sorted by "proximity" to the host making the choice - where
"proximity" is defined as the length of the common initial address
prefix.

This may have been a disputed but arguable definition of real network
proximity for IPv6 in at the time 3484 was written.  But it is clear
now that it is not such a measure in the real IPv6 internet, and it
has never been such a measure in the IPv4 internet.

So RFC3484 s6 rule 9 is just wrong, because the reasons behind it do
not apply any more if they ever did.


However, it's worse than that: rule 9 is trying to change the
behaviour of existing systems.  If we agree with rule 9 it ought to
apply just as well to applications using gethostbyname.

All existing applications using gethostbyname are not in compliance
with rule 9.  It would perhaps be possible to modify gethostbyname to
sort addresses according to RFC3484 s5 and s6.

But would it be a good idea ?  No, obviously not.  It would change the
behaviour of all of the applications which currently use
gethostbyname.

Currently such applications pick addresses "at random" (according to
the DNS round robin).  Rule 9 would have applications pick them
according to longest-common-prefix.  This would destroy the DNS based
load balancing arrangements.


What about getaddrinfo ?  Well, there is no reason why a change in API
(to add additional richness needed for new functionality) should so
radically change the behaviour.

And indeed, we see that indeed the DNS load balancing of our own
servers has been broken by this change !

That is, applications are changed from using non-rule-9 gethostbyname
to rule-9 getaddrinfo, and the servers experience wildly unbalanced
load and break.



> The RFC tries to make getaddrinfo return a predictable ordering in the
> face of random orderings from DNS. That seems a perfectly reasonable
> way to define a function in the abstract; though certainly the ordering
> it comes up with can be criticised.

It is not reasonable for the RFC to attempt to specify that the
addresses be returned in a predictable ordering when the established
behaviour, relied on throughout the internet for decades, has been
that the addresses are _not_ returned in a predictable order.

The unpredictability here is not accidental.  Before the advent of DNS
round robin, addresses were always returned in the order specified by
the DNS zone administrator.

Special code was added (decades ago) to namervers to "randomise" the
order.  getaddrinfo shouldn't undo it.


> I'd say it's more important that getaddrinfo() on Debian behave "the same"
> as on other operating systems, than that it behave in the same way as
> other functions. I can only take the RFC's assertion as to getaddrinfo()'s
> proper behaviour though; I don't have a more direct idea how getaddrinfo()
> behaves in previous versions of Debian, other Linux distros, other libcs,
> Windows, etc.

This argument is an argument for accepting any crap that comes out of
glibc upstream.

As I have demonstrated above, the RFC is wrong, inconsistent with
existing practice, and the proposed way of complying with it causes us
to have two similar interfaces (gethostbyname and getaddrinfo) which
have inconsistent behaviour.


> What getaddrinfo() should and shouldn't do is defined by the standard,
> not by what would be most useful. :-/

The document which defines getaddrinfo is RFC3493 which doesn't refer
to RFC3484.  It doesn't mention ordering at all.

Note that RFC3484 is NOT A STANDARD.  It is a `proposed standard' -
the earliest possible IETF standards track document status.


> FWIW, if the standard should be changed, it seems to me that it'd carry
> more weight having the Debian tech ctte put that recommendation in than
> a random DD.

Absolutely.  We should recommend that RFC3484 rule 9 should be
deprecated, and should be abolished (definitely for IPv4 and probably
for IPv6 as well).


Ian.



Reply to: