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