paho.mqtt.c icon indicating copy to clipboard operation
paho.mqtt.c copied to clipboard

IPV4 preferred ???

Open willem4ever opened this issue 4 years ago • 14 comments

I'm using debian stretch using IPV6 whenever I can, home made tools use IPV6 as well as e.g. 'mosquitto_sub'. However this library seems to like IPv4 and I cannot get it to work with IPV6 ... Can any one point me in the right direction or did I hit a bug ??

willem4ever avatar Jan 01 '21 18:01 willem4ever

I'm guessing it's to do with the selection from multiple addresses returned from the DNS resolution (without further information). I tested with IPv6 a long time ago and it worked then as I remember, but it doesn't seem to be used very much. I'm not sure I even have access to a setup capable of IPv6 any more.

icraggs avatar Jan 02 '21 12:01 icraggs

A library trace, at the protocol or minimum level might give some more information.

icraggs avatar Jan 02 '21 12:01 icraggs

Found it, it is indeed preferring IPV4 ..... in Socket.c I introduced a define, but I suppose it should be the default to prefer IPv6 over IPv4 and have it as an option for preferring IPv4 ...

742:#if defined(PREFER_IPV4)
743-		while (res)
744-		{	/* prefer ip4 addresses */
745-			if (res->ai_family == AF_INET || res->ai_next == NULL)
746-				break;
747-			res = res->ai_next;
748-		}
749-
750-		if (res == NULL)
751-			rc = -1;
752-		else
753-#endif
754-#if defined(AF_INET6)
755-		if (res->ai_family == AF_INET6)
756-		{
757-			address6.sin6_port = htons(port);
758-			address6.sin6_family = family = AF_INET6;
759-			memcpy(&address6.sin6_addr, &((struct sockaddr_in6*)(res->ai_addr))->sin6_addr, sizeof(address6.sin6_addr));
760-		}
761-		else
762-#endif

willem4ever avatar Jan 02 '21 15:01 willem4ever

Adding below to top CMakeLists.txt makes it selectable by adding -DPREFER_IPV4=ON

IF (PREFER_IPV4) ADD_DEFINITIONS(-DPREFER_IPV4=1) MESSAGE(STATUS "Prefering IPv4") ELSE() MESSAGE(STATUS "Using and prefering IPv6") ENDIF()

willem4ever avatar Jan 04 '21 11:01 willem4ever

It doesn't seem like a flexible approach to make this a compile option and require rebuilding. How does other software address this situation - an option to choose? If both IP4 and 6 addresses exist, then is there a logic to choose one over another? It will use the v6 address if that's the only one returned.

You can choose the IP address yourself and send that into the client library instead of the hostname.

icraggs avatar Jan 04 '21 13:01 icraggs

Agreed, when I look at the setup it was initially build to follow standards and selects an IPv6 address when available. However for some reason the 'prefer ipv4 address' while loop was introduced ... my option is to give the user the possibility to keep that behaviour or switch to the standard behaviour to use IPv6 when it is available, so building without explicitly saying to prefer IPv4 it would follow the hints (AF_UNSPEC) i.e. IPV6 and when the IPv6 address cannot be resolved it will automatically switch to IPv4 anyway. I guess the forced IPv4 was introduced to deal with wrongly configured OS's, which have an active IPv6 stack, but are not actually IPv6 connected ....

note: resolving 'myself' and using IPv6 address when available is not the way forward in my opinion.

willem4ever avatar Jan 04 '21 13:01 willem4ever

"follow standards" - what standard(s) are you referring to? What does other software do?

"note: resolving 'myself' and using IPv6 address when available is not the way forward in my opinion." - well it would work.

There could be a connect option to prefer ipv6, or a callback for the application to choose, for instance, rather than a build option. The callback is probably overkill if all we're doing is choosing between ipv4 and 6.

icraggs avatar Jan 04 '21 14:01 icraggs

"follow standards" - what standard(s) are you referring to? What does other software do? When I use my favourite browser and connect to a website it prefers IPv6 when IPv6 resolves … when I use SSH without using an option it prefers IPv6 when it resolves and so on …

"note: resolving 'myself' and using IPv6 address when available is not the way forward in my opinion." - well it would work. Yes it would work, but I prefer not use ip addresses, and having to change multiple clients when I have to change an IP address

We should leave the IP preference to the OS (supported by Linux and Windows) and not hardwire it to IPv4 …

willem4ever avatar Jan 04 '21 14:01 willem4ever

i did some more research in both windows (registry) and linux (gai.conf) you can set the precedence of ipv6 before ipv4 or ipv6 before ipv4 when DNS resolution returns both an AAAA and A record. So in my humble opinion you can remove the code which prefers IPv4 in your code ...

willem4ever avatar Jan 04 '21 17:01 willem4ever

Well that would be a change from a previous implementation which might affect existing applications. Maybe there aren't any applications that would suffer, but making that change would be one way of finding out, not perhaps in a good way. I'm going to solicit some other views.

icraggs avatar Jan 07 '21 15:01 icraggs

That is why I suggested compile time options, one way would be with default options is to keep the current behaviour, if you like the behaviour I’m after you could make that optional with a new compile time option ….

On 7 Jan 2021, at 16:22, Ian Craggs [email protected] wrote:

Well that would be a change from a previous implementation which might affect existing applications. Maybe there aren't any applications that would suffer, but making that change would be one way of finding out, not perhaps in a good way. I'm going to solicit some other views.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/eclipse/paho.mqtt.c/issues/1030#issuecomment-756182436, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAF667JFDBH3BM6BB4OQFFTSYXGU5ANCNFSM4VQOJT2A.

willem4ever avatar Jan 07 '21 15:01 willem4ever

A build option means yet more build variants. Harder to use and support. The runtime option is better in my opinion.

icraggs avatar Jan 09 '21 13:01 icraggs

I've added a callback to allow this choice as part of the ability to select the device interface.

icraggs avatar Nov 27 '22 17:11 icraggs

We have the same problem.

We have a local MQTT broker which is only accessible via IPv6 link local, where the name resolution happens via mDNS/Avavi.

I debugged into the Socket_new() function and found that getaddrinfo() returns both an IPv4 and an IPv6 entry. The "prefer ip4 addresses" section ensures that only IPv4 is tried, which fails completely. No connection possible.

Basically the same I see on an IPv6-only host, which also gets an IPv4 address during name resolution. The "prefer ip4 addresses" section again ensures that no connection is possible.

Other tools like mosquitto_pub or libcurl work fine in these environments.

From libcurl I know that it uses a "happy eyeballs" implementation: https://en.wikipedia.org/wiki/Happy_Eyeballs I.e. parallel connects with IPv4 and IPv6 ...

I think the manual preselection of IPv6 via a callback is not useful, because the client does not know when to preselect IPv6. In my opinion we should try to realize a "happy eyeballs" implementation. Or at least try all getaddrinfo() entries one after the other. Then at least a connection would be established at some point.

Assuming you would do the name resolution outside of the Paho library, and only pass an IP. Is it possible to pass an additional host name for the SSL check?

When is the release of version 1.4.0 with the IPv6 prefix callback planned?

matthiasklein avatar Aug 18 '23 15:08 matthiasklein