+1 vote
by (130 points)

The Rebex SSH client prefers IPv4 over IPv6. For example, if a connection is configured with a hostname that contains an A record and a AAAA record, Rebex ignores the AAAA record connects via IPv4. This is wrong, so very very wrong.

According to RFC3484 the client should prefer IPv6 and fall back to IPv4 if IPv6 is unavailable.

Can you please fix this bug?

by (130 points)
I'm confused, does this bug have to receive a certain amount of votes before it'll get fixed?
by (148k points)
Bug reports and feature requests are evaluated and ranked based on their severity and other criteria including user feedback. Then they are assigned a suitable priority and in are usually fixed as fast as possible or reasonable.

1 Answer

0 votes
by (148k points)

You are right that our method of determining the suitable IP address is not ideal. However, RFC 3484 does not actually say that client should just prefer IPv6 to IPv4 either. RFC 3484 states that "a simple policy to always prefer IPv6 or always prefer IPv4 can produce poor behavior". However, it does not prohibit this behavior, even though it advises against it. This is what it states:

As a consequence, we intend that implementations of getaddrinfo()
will use the destination address selection algorithm specified here
to sort the list of IPv6 and IPv4 addresses that they return.

And:

Well-behaved applications SHOULD iterate through the list of
addresses returned from getaddrinfo() until they find a working
address.

We differ here because we use the poor behavior instead (and simply preferring IPv6 would be equally poor). But we would not call this a bug because the meaning of "SHOULD" is defined by RFC 2119 as follows:

3. SHOULD  This word, or the adjective "RECOMMENDED", mean that there
may exist valid reasons in particular circumstances to ignore a
particular item, but the full implications must be understood and
carefully weighed before choosing a different course.

(Wording of RFC 6724, which obsoleted RFC 3484, is slightly different, but the core of its meaning is the same.)

So how have we ended with the poor behavior? When we first added support for IPv6 more than 10 years ago, we found out that the recommended approach very often produced undesirable results (comparable to this). In the end, after carefully weighting pros and cons, we decided to use the poor behavior because it turned out to produce better results in practice, as far as our customers were concerned. We were not happy about this decision, but we don't regret it because we have not received any complaints (until now)

Of course, that decision was made in 2007. Now, it would almost certainly be better to use the recommended approach. However, that would involve changing an existing behavior, which might potentially break applications based on Rebex libraries. That is undesirable as well and lot of our clients would not like that.

So instead, we are now considering the following approach:

  1. Adding an option to Rebex libraries that will enable the behavior recommended by RFC 3484 / RFC 6724.

  2. Using the recommended behavior by default in the forthcoming binaries for new platforms.

This is a high-priority issue and we will address it soon. If you would like to get a link to a hotfix when it's ready, please let us know.

Also, thanks for bringing this to or attention.

by (130 points)
Thanks for the prompt response. I will advise my vendor (RoyalTS) of this issue so they can apply the hotfix.

Thanks again.
by
Was this issue addressed in a hotfix?
by (148k points)
This has been postponed several times due to more important high-priority issues and due to apparent lack of demand in this feature among our customers.

But to address the needs of customers who wish to prefer IPv6 over IPv4, or who wish to use some other approach. we made it possible to customize the process. This involves implementing a simply "custom socket factory", and registering it with an instance of Sftp (or other Rebex client) before calling the connect method:

    var sftp = new Sftp();
    sftp.SetSocketFactory(CustomResolveSocket.Factory); // register a custom socket factory
    sftp.Connect("test.rebex.net");
    sftp.Login("demo", "password");

A custom socket factory to prefer IPv6 addresses to IPv4 might look like this:
 
    public class CustomResolveSocket : ProxySocket, ISocket
    {
        private static IPAddress Resolve(string serverName)
        {
            var entry = Dns.GetHostEntry(serverName);
            if (entry.AddressList != null)
            {
                var address = entry.AddressList.Where(addr => addr.AddressFamily == AddressFamily.InterNetworkV6).FirstOrDefault();
                address = address ?? entry.AddressList.Where(addr => addr.AddressFamily == AddressFamily.InterNetwork).FirstOrDefault();
                if (address != null)
                    return address;
            }

            throw new ProxySocketException("No IP address records found in the host entry.", ProxySocketExceptionStatus.NameResolutionFailure);
        }

        void ISocket.Connect(string serverName, int serverPort)
        {
            IPAddress address;
            if (!IPAddress.TryParse(serverName, out address))
            {
                address = Resolve(serverName);
            }

            var socket = new Socket(address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
            socket.Connect(address, serverPort);
            Bind(socket);
        }

        private class CustomResolveSocketFactory : ISocketFactory
        {
            ISocket ISocketFactory.CreateSocket()
            {
                return new CustomResolveSocket();
            }
        }

        private static readonly CustomResolveSocketFactory _factory = new CustomResolveSocketFactory();

        public static ISocketFactory Factory
        {
            get { return _factory; }
        }
    }

The same socket factory can be used with all Rebex clients.
...