Openwall GNU/*/Linux - a small security-enhanced Linux distro for servers
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date: Mon, 9 Jul 2018 20:11:48 -0400
From: Christopher Friedt <>
Subject: Re: getaddrinfo(3) / AI_ADDRCONFIG

On Mon, Jul 9, 2018 at 6:38 PM Rich Felker <> wrote:
> POSIX does not clearly specify how "only if an IPv6 address is
> configured on the local system" is determined, but the glibc behavior
> of ignoring ::1 on lo seems clearly non-conforming. My assumption a
> the time was that ::1 would always be configured and available unless
> IPv6 support was omitted from the kernel, so that any test involving
> iteration of interfaces would be meaningless; at most probing ::1, or
> probably just trying socket(AF_INET6,...) would suffice to determine
> what to do.
> It's unclear to me (and I think to everyone) what an application
> actually wants when it uses AI_ADDRCONFIG. Neither knowing whether

You did point out that glibc is non-conforming, and I assumed that
musl would prefer to be more conforming as well. The patch I provided
*is* conforming in that it does not assume AI_ADDRCONFIG is present
when hints are NULL.

Your assumption actually missed the mark a bit though. If IPv6 is
initially configured for an interface, even if no routable address is
assigned, it will get a link-local address (which is not a loopback
address, and so is not skipped by getaddrinfo). So it will not be ::1
that comes back by default but something in the fe80::/10 range.

The description of AI_ADDRCONFIG below is also fairly straightforward,
and tackles the exact problem I encountered (see the last sentence of
the paragraph below).

If hints.ai_flags includes the AI_ADDRCONFIG flag, then IPv4
       addresses are returned in the list pointed to by res only if the
       local system has at least one IPv4 address configured, and IPv6
       addresses are returned only if the local system has at least one IPv6
       address configured.  The loopback address is not considered for this
       case as valid as a configured address.  This flag is useful on, for
       example, IPv4-only systems, to ensure that getaddrinfo() does not
       return IPv6 socket addresses that would always fail in connect(2) or

At least 4 majorly (ubuquitously?) adopted libc's have implemented
AI_ADDRCONFIG this way (glibc, uclibc, Apple libc, BSD libc). My
suggestion would be to do what everyone else does until there is
better clarification rather than try and be a snowflake.

> IPv6 is supported at all on the host, nor whether there happens to be
> *some* interface or non-lo interface with an IPv6 address (think: it
> might just be a private-network VPN), tells you anything about whether
> the IPv6 addresses for the particular hostname you're looking up with

IPv6 support does not imply that a network interface needs to be
configured with an IPv6 address.

The point you are trying to make seems to be addressing glibc's
non-conformance as opposed to AI_ADDRCONFIG's intended functionality.
Since the patch does not introduce non-conformance, and actually does
not negatively alter musl's behaviour.

> getaddrinfo is routable. The more likely thing an application might
> want is to request whichever result is routable


> want is to request whichever result is routable, but THAT ALREADY
> HAPPENS without AI_ADDRCONFIG: the results are sorted such that

In fact IT DOES NOT ALREADY HAPPEN. Musl's getaddrinfo does not
provide a routable socket at all in the example I provided. In fact,
there are exactly zero network interfaces with an IPv6 address in this
case, but somehow musl comes back with "::1" for localhost, which is
more damaging than useful in this use case. You could almost say that
musl is currently also non-conformant in that sense.

> routable ones come before non-routable ones, so if you try them in
> order, you'll never hit a non-routable address family unless all the
> results for the other family fail to be reachable.

Want proof? Download the tarball I provided here:

Using a default Docker installation, run it with "docker build -t foo
." (where . is the directory with the Dockerfile).

The C++ / c_glib unit tests will work in this case (with the fix) (the
python unit tests are currently not compiling).

Then, comment-out the line that applies the patch to musl in the Dockerfile.
# RUN patch -p1 < musl-1.1.19-getaddrinfo-ai-addrconfig.patch

The C++ / c_glib unit tests will break in this case. You can
step-through the code yourself, or just trust the instrumentation I've
already done detailed at

So there you have it. A use case with a demonstrated bug and fix that
is 100% reproducible.

> So at this point my leaning is somewhere between:
> 1. Saying it's 2018 and having a system without IPv6 support (at least
>    ::1) is an unsupported configuration.

That's a slippery-slope argument. Just because a system supports IPv6
does not imply that a network interface needs to be configured with an
IPv6 address. As an example, my lame cable ISP does not route IPv6
traffic nor does it provide an IPv6 prefix. They are IPv4-only (you
may think I live in the dark ages). Therefore, it does not even make
sense for the average customer to configure IPv6 on their LAN. Does my
OS support IPv6? Of course. ... Did I bypass them with a 6in4 tunnel -
you can be damn sure ;-) But many people wouldn't bother with that.

> 2. Implementing AI_ADDRCONFIG as detection for the case where IPv6 has
>    been completely disabled at the kernel or container level.

That's not at all the case here.

3. Where a user's OS supports IPv6 but they have simply opted not to
assign an IPv6 address to their network interface or use a link-local

> I'm not sure what option 2 entails if IPv6 is disabled at the
> container level but socket(AF_INET6,...) still succeeds, so we should
> perhaps look into that if you or other users feel strongly that
> AI_ADDRCONFIG should do something here. But it shouldn't involve any
> O(n) iteration of interfaces, allocation, or pulling in other heavy
> code.

My only emphasis would be to support it to the end that it does what
is expected when passed in, and to not make it a default. Review the
patch, because AI_ADDRCONFIG is not a default flag.

It's O(n) in the worst case. In the best case, it's O(1). In the
average case (probabilistically speaking, where network interfaces
each have v4 and v6 addresses), it's still O(1). In the default case,
the only overhead is the time it takes to perform a mask and compare.


Powered by blists - more mailing lists

Your e-mail address:

Powered by Openwall GNU/*/Linux - Powered by OpenVZ