tech-net archive

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

Re: lib/42405: libc: getaddrinfo() should perform T_A lookups before T_AAAA lookups, was: Resolver problems

    Date:        Sat, 5 Dec 2009 09:10:07 +0000 (UTC)
    From: (Michael van Elst)
    Message-ID:  <hfd813$7m4$>

  | With the same argument you could say that a 'nslookup' or 'dig'
  | should fail to query AAAA records when your kernel cannot handle
  | IPv6.

Not quite - no-one would argue that if you asked for a particular addr type
that getaddrinfo() should do anything different than what it was asked (not 
that dig (etc) use getaddrinfo() anyway), but if you say "just give me
something I can use" without caring what protocol, I don't think it would
be unreasonable for getaddrinfo() to simply return only addresses that
have at least the potential to work - and I don't think applications should
need to set some flag to tell getaddrinfo() not to return useless trash,
if anything, for the one in a hundred application that isn't a diagnostic
tool (which wouldn't be using getaddrinfo()), doesn't care what address type,
but wants everything available, even if it cannot possibly work, a flag to
indicate that would make more sense (you'd really have to hunt to find an
application that you'd need to modify to set it).

  | getaddrinfo() is only used by programs that can handle IPv6

Typically yes, but not necessarily, it is really just a newer, cleaner,
interface to the resolver low level routines, and ought to be used by
anything new (or just being overhauled) these days, of course, such things
should be able to handle IPv6. but even if they can't, getaddrinfo() is a
much nicer interface than gethostbyname().

  | It is a problem for people with a broken IPv6 setup. I.e. the machine
  | is configured for an IPv6 network but the network doesn't function
  | because of things like unstable tunnels or unreliable ipv6 providers.

Yes, it is (or should be) a real problem only in those cases, but it is
a waste of network resources in others - just asking for a v6 address
you're never going to use is a packet out, a packet back, and the back
end resolver being made to do (and then cache) data that's useless.
It shouldn't be a problem, but it is pretty stupid and unnecessary.

And of course the same is true for v4 for (future) systems where v4
doesn't work.

  | I don't think that such a workaround should depend on the kernel
  | because the need for the workaround has little to do with the kernel
  | and the functionality that needs to be adjusted is embedded in
  | libc.

Yes, it is libc that should act differently here.

  | So please, add a knob to control libc behaviour.

For this, I'd do that, but I'd also not query for addresses that we
can tell cannot possibly be useful, if the application hasn't expressly
asked for that address type (either by name, which is an interface that
already exists, or by explicitly asking for useless answers, using some
new interface, if one gets invented).

  | - sysctl is out of the question. It controls kernel behaviour and
  |   the kernel shouldn't be a storage for configuration data.

If you mean a sysctl whose purpose was to config libc, then certainly
that would be absurd.   But that doesn't mean that libc cannot look at
a sysctl that has some other purpose, to determine whether a protocol is
supported or not (or something.)   Not that I'd do that that way either,
it's cheaper and easier just to (try to) create a socket of the
appropriate type, if that succeeds, then return addresses of that type,
if it fails, don't (by default).   That also works on any kernel.

  | - an environment variable would be sufficient for me but there
  |   are issues to make this a system wide setting. There are always
  |   other parties that tweak the environment and break such a setup.

Agreed, env vars should be reserved for users to start personal
preferences, not for system settings.

  | - resolv.conf is not my first choice, because this is used by
  |   the resolver code, not the high level functions like getaddrinfo().

Here I disagree (mildly at least) - I consider getaddrinfo() (and
gethostbyname()) to just be the programmer friendly interfaces to the
resolver - they're part of it.   So, config in resolv.conf is not
at all unreasonable (and the relevant function already accesses the
resolver state, so using that just means moving a function call a
little earlier).

  |   But since there already is a bit that controls the resolver library
  |   in a similar way, this might be an option. The particular bit
  |   (RES_USE_INET6) however, has a completely different meaning
  |   because it is supposed to return IPv4 adresses as IPv6 adresses
  |   to simplify application code.

That's not the right bit to use (even though I couldn't find any place
NetBSD's code actually uses it - in libc anyway) but the analogy is a
reasonable one.    And we have practice of other systems.

  | - nsswitch.conf would be a natural choice if it allowed to pass
  |   options to the backends (e.g. hosts: files dns[v4only]). But
  |   who dares to touch nsswitch code? :)

Well, maybe, I guess we could allow dns4only and dns6only as alternatives
to dns in there, but that looks to be a bit of a stretch.

  | - a new file/symlink like /etc/malloc.conf (which BTW is the system
  |   wide configuration for something controlled by an environment
  |   variable).

If we didn't already have resolv.conf, that would be my choice.

  | This would help with the broken DNS server only when you also
  | create a kernel without IPv6 (so far we cannot disable IPv6
  | link local addresses).

Ingolf already did the former, and it didn't help - but not sending
a query for v6 addresses would have helped, regardless of whether his
kernel had v6 support in it or not.   And since there seemed to be at
least some support, and no opposition, I'll dig out the CD I have somewhere
with the "disable protocol" code on it, and make it fit current as it
is now, and send in a change request PR (probably for the simple version
that just makes the selected protocol vanish to new users of it, rather
than all the extra that allows existing connections to be affected as well).

For most expected requirements, it does what is desired, you set the
sysctl in /etc/sysctl.conf and from the next boot, there is almost no
difference visible between running a system with the disabled protocol,
and running a kernel with the protocol compiled out (except that you
can "undisable" (yes, I know correct English is "enable" but that
doesn't quite give the same impression) the protocol any time.)

  | So I propose /etc/addrinfo.conf with an associated environment
  | variable ADDRINFO_CONF. And please paint it in pink.

I think resolv.conf is better, it is where resolver config goes, it
already has the ability to specify options, and is a reasonable home
for this kind of config.

I also don't think we need an env var at all, most applications already
have options that say whether they should use v4 or v6 (defaulting to whatever
works usually) and complicating that by adding yet another way wouldn't
help, just make everything messier, after all, what is telnet (or anything)
to do if you say "telnet -4 ..." when your ADDRINFO_CONF says "v6 only"
(or vice versa).   Just leave that config to command line options - if an
application doesn't provide a way, then its author didn't intend his users
to be able to control this behaviour.


Home | Main Index | Thread Index | Old Index