Re: [Exim] Linux USAGI and the default bind/listen behaviour

Top Pagina
Delete this message
Reply to this message
Auteur: Philip Hazel
Datum:  
Aan: Lionel Elie Mamane
CC: exim-users
Onderwerp: Re: [Exim] Linux USAGI and the default bind/listen behaviour
On Fri, 31 Jan 2003, Lionel Elie Mamane wrote:

> > I'm not surprised. Many changes have been made in that area in Exim
> > 4. Exim 3 is pretty obsolete now. I suggest you upgrade.
>
> I tried exim4, it exhibits the same behaviour.


Interesting. There is an extensive comment in the Exim 4 code,
containing this:

/* Otherwise we set up things to listen on all interfaces. In an IPv4 world,
this is just a single, empty address. On systems with IPv6, several different
implementation approaches have been taken. This code is now supposed to work
with all of them. The point of difference is whether an IPv6 socket that is
listening on all interfaces will receive incoming IPv4 calls or not.

  . On Solaris, an IPv6 socket will accept IPv4 calls, and give them as mapped
    addresses. However, if an IPv4 socket is also listening on all interfaces,
    calls are directed to the appropriate socket.


  . On (some versions of) Linux, an IPv6 socket will accept IPv4 calls, and
    give them as mapped addresses, but an attempt also to listen on an IPv4
    socket on all interfaces causes an error.


  . On OpenBSD, an IPv6 socket will not accept IPv4 calls. You have to set up
    two sockets if you want to accept both kinds of call.


  . FreeBSD is like OpenBSD, but it has the IPV6_V6ONLY socket option, which
    can be turned off, to make it behave like the versions of Linux described
    above.


  . I heard a report that the USAGI IPv6 stack for Linux has implemented
    IPV6_V6ONLY.


So, what we do is as follows:

(1) At this point we set up two addresses, one containing ":" to indicate
an IPv6 wildcard address, and an empty one to indicate an IPv4 wildcard
address.

(2) Later, when we create the IPv6 socket, we set IPV6_V6ONLY if that option
is defined.

(3) We listen on the v6 socket first. If that fails, there is a serious
error.

(4) We listen on the v4 socket second. If that fails with the error
EADDRINUSE, assume we are in the situation where just a single socket is
permitted, and ignore the error. */

So it is supposed to do exactly what you said:

> EADDRINUSE. The following works, though:
>
> - bind(IPv6 any address)
> - listen(IPv6 any address)
> - bind(IPv4 any address), failure because EADDRINUSE -> goto end
> - listen(IPv4 any address)
> - :end:
>
> The bind(ipv4) will fail with EADDRINUSE.


Obviously, something is different on the system you are using, that is
making the logic not work. Ah! The difference is that the bind() is
failing, not the listen(). The code expects the bind() to succeed and
the listen() to fail, because that's what was experienced before. Yet
another variation. Sigh.

I will put in a check for EADDRINUSE on the bind(). And hope it works -
because I can't test this.

Thanks for the report.

Philip

--
Philip Hazel            University of Cambridge Computing Service,
ph10@???      Cambridge, England. Phone: +44 1223 334714.