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

  • From: Martin Sustrik <sustrik@xxxxxxxxxx>
  • To: nanomsg@xxxxxxxxxxxxx
  • Date: Tue, 10 Sep 2013 06:24:10 +0200

Hi Mark,

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.

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.

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.

Would you like to write a patch for that?

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.

Martin

On 09/09/13 19:41, Mark Martinec wrote:
If I'm parsing the nanomsg source code correctly, it is still dragging along
the IPV4ONLY socket option from ZeroMQ, and having decisions on what
address family to use (in getaddrinfo calls and socket creation) based on
this setting. In particular, if IPV4ONLY is off, the PF_INET6 protocol
family is assumed, instead of PF_UNSPEC.

This has an unfortunate consequence in that an application code needs
to be able to parse the nanomsg socket specification and even have to do
its own DNS resolving, just in order to be able to set the IPV4ONLY socket
option accordingly.

For example, if an application uses an admin-settable configuration
which specifies that the program should listen on tcp://lo0;:1234
then the application code needs to determine whether it is running on
an IPv6-only or IPv4-only or a dual-stack host, and set/clear the
IPV4ONLY socket option accordingly.

Similarly, with a specification like: tcp://localhost:1234
the application code needs to do its own getaddrinfo call to
find out whether the 'localhost' resolves to 127.0.0.1 or to ::1
or to both, and set/clear the IPV4ONLY socket option accordingly.
Same goes for connecting to remote host names ... not to mention
that it all fails when a DNS resolvers provides multiple IP addresses.

I have such kludges scattered all over the place in my amavisd code
and its utilities (still using ZeroMQ), e.g.:

   my $sock_ipv4only = 1;  # a ZMQ default
   if (defined &ZMQ_IPV4ONLY && $sockspec =~ /:[0-9a-f]*:/i) {
     zmq_setsockopt($sock, ZMQ_IPV4ONLY(), 0) != -1
       or die "Error turning off ZMQ_IPV4ONLY on a ZMQ socket: $!";
     $sock_ipv4only = 0;
   }
   zmq_connect($sock, $sockspec) == 0
     or die "Error connecting ZMQ socket to $sockspec: $!";


Considering that one of the aims of nanobsd is to avoid some of the pitfalls
of its predecessors, it would be very nice if the following would work
transparently to the application:

- a bind to  tcp://lo0;:port  or to  tcp://hostname:port  should
be able to listen on all protocol families associated with the named
interface or provided by getaddrinfo, filtered by available protocol
families on a host (option AI_ADDRCONFIG);

- a connect to tcp://hostname:port should be able to choose a protocol
family available on a host and offered by resolving the specified hostname;

- if a DNS resolver provides multiple addresses, the effect is debatable,
but in my view it should not fail outright. Either choose one of the
provided addresses randomly, or perhaps try them in turns until one
succeeds.

- supply the complementary socket option ipv6only, and if neither
of them is set, just do-the-right-thing.


   Mark



Other related posts: