[nanomsg] Re: Getting rid of the old IPV4ONLY socket option semantics

  • From: Mark Martinec <Mark.Martinec+nn@xxxxxx>
  • To: nanomsg@xxxxxxxxxxxxx
  • Date: Tue, 10 Sep 2013 12:38:07 +0200

On Tuesday 10 September 2013 06:24:10 Martin Sustrik wrote:
> The intended behaviour is that if IPV4ONLY is set to 1, only IPv4 is
> used. However, if it is set to 0, both IPv4 and IPv6 are allowed.

That only applies to some (most) distributions of Linux,
but is not universally true.

> The IPV4ONLY option exists only because there were some problems seen on
> dual-stack boxes back when IPv6 support was added to ZeroMQ. Thus, if we
> are able to make it work in IPv4+IPv6 mode flawlessly, the option can go
> away entirely.

Agreed, that would be the most desirable final outcome, an application
should not need to be aware of what underlying protocol families are used.
A host name is a host name, let DNS and underlying libraries deal with
details.

> The problem was, IIRC (and I may be wrong about that), with resolving
> local interface names. The algorithm, as you've probably seen, does
> getaddrinfo query and uses the first result, dropping all the following
> results. On dual-stack box the first result may be either IPv4 or IPv6
> address. In the latter case everything works as expected -- socket bound
> to IPv6 address should be able to accept IPv4 connections as well (we
> should verify whether that's really the case!) However, in the former
> case, IPv6 connections are not allowed. So, I guess, simply picking the
> IPv6 address from the list, if there is one, should help to fix the
> problem.

There is a per-socket option IPV6_V6ONLY (RFC 3493), controlling
whether an INET6 socket is allowed to also accept an INET protocol
family or not. Its default setting comes from some global setting, e.g.
net.inet6.ip6.v6only (FreeBSD and NetBSD), net.ipv6.bindv6only (Linux),
or its default may be hard-coded on older systems.

The FreeBSD since 5.x has net.inet6.ip6.v6only turned on, i.e. an INET6
socket can only accept IPv6. On Linux the default  is typically off
(i.e. accepts both protocol families), but it has been told that on
some (newer?) Debian systems it was switched to on by default.
On OpenBSD the setting is on and cannot be turned off.


The per-socket option IPV6_V6ONLY may or may not be changed
independently of its global default. In newer FreeBSD versions it is
possible to clear or set this socket option, on older versions this was
not possible. Seems the same applies to OS X.

On Linux the socket option IPV6_V6ONLY exists and can be turned on.
There are old versions of Linux where IPV6_V6ONLY does not exist.

Some OS do not provide a IPV6_V6ONLY constant at all (some Solaris
systems like Solaris 9, old Windows before Vista). Some do provide it,
but the socket option is unsupported (setsockopt returns an error).

As far as I can tell on OpenBSD it is not possible to turn off
the IPV6_V6ONLY at all, an inet6 socket can only accept IPv6.


It seems the most widely used solution is to turn the IPV6_V6ONLY on
(or just leave it enabled), and use separate sockets for each protocol
family: apache, bind, unbound, powerdns, ntpd, postfix, ...

To be able to listen (bind) on multiple interfaces on a multihomed
host, it would be necessary to have multiple sockets and use a select()
on them anyway, regardless of their protocol family.


> Another reason for having IPV4ONLY option may be (and I am not really
> sure about this use case, does anyone have any insight?) if both the
> local and remote endpoints have IPv6 addresses, but the network
> infrastructure in-between them doesn't support IPv6. In such case
> forcing IPv4 may be the only way to establish a connection between the
> endpoints.

Yes, due to broken setups it may still be useful to allow an administrator
to force either IPv4 or IPv6. The default should be to allow both and
use whichever protocol family is supported by the host (e.g. setting the
AI_ADDRCONFIG in getaddrinfo, using AI_PASSIVE as appropriate).

  Mark

Other related posts: