Archived Forum Post

Index of archived forum posts

Question:

CkoSshTunnel ipv6

Oct 04 '17 at 12:41

Hi there,

Does CkoSshTunnel support ipv6?

My app was rejected due to the ipv6 support issue...

Apple documantation


Answer

    ChilkatLog:
 Connect_SshTunnel:
   DllDate: Sep 24 2017
   ChilkatVersion: 9.5.0.70
   Architecture: Little Endian; 64-bit
   Language: IOS C/C++/Swift/Objective-C
   VerboseLogging: 0
   Component successfully unlocked using purchased unlock code.
   hostname: 165.227.202.20
   port: 443
   sshConnect:
     connectSocket:
       connect_ipv6_or_ipv4:
         socketErrno: 51
         socketError: Network is unreachable
       --connect_ipv6_or_ipv4
       connect_ipv6_or_ipv4:
         socketErrno: 51
         socketError: Network is unreachable
       --connect_ipv6_or_ipv4
       connect_ipv6_or_ipv4:
         socketErrno: 51
         socketError: Network is unreachable
       --connect_ipv6_or_ipv4
       connect_ipv6_or_ipv4:
         socketErrno: 51
         socketError: Network is unreachable
       --connect_ipv6_or_ipv4
     --connectSocket
     Failed to establish initial TCP/IP connection
     hostname: 165.227.202.20
     port: 443
   --sshConnect
   Failed.
 --Connect_SshTunnel
--ChilkatLog

Answer

Thanks. I'll begin writing my answer here, and will be updating it because there is much to say. (This way you don't have to wait for the full answer..)

New Features in the 9.5.0.70 Pre-Release

The pre-release I provided to you has the following new features:

  1. The CkoSshTunnel class now has a PreferIpv6 property. The purpose of this property is to prefer IPv6 addresses over IPv4. For example, internal to Chilkat, calling the getaddrinfo function (https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man3/getaddrinfo.3.html) can return multiple addresses. Some may be IPv4, some IPv6. The PreferIpv6 property tells Chilkat to choose an IPv6 address over an IPv4 address if both kinds exist. If only IPv4 addresses are returned, then Chilkat will still choose it because it has no choice. There's nothing else to choose.
  2. The PreferIpv6 property is common to many different Chilkat classes (Ssh, Socket, etc.) I also added the PreferIpv6 property to the CkoGlobal class. This sets the default value of PreferIpv6 properties Chilkat-wide. If CkoGlobal.PreferIpv6 is set to true (YES), then the default PreferIpv6 property value of any newly created Chilkat object will have this value.
  3. Internally, Chilkat left the "1st try" for the argument values passed to getaddrinfo unchanged. This is to avoid disrupting or causing additional trouble. If the getaddrinfo/connect fails, then Chilkat re-tries with different combinations of getaddrinfo argument values. Internally, I call these "profiles". If you read about the getaddrinfo function at https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man3/getaddrinfo.3.html, you'll see that it's quite complicated. There are many different possible combinations of values, especially with the ai_flags. You can read about AI_ADDRCONFIG, AI_ALL, AI_V4MAPPED, AI_V4MAPPED_CFG, AI_DEFAULT, etc. In the LastErrorText shown above, I can see that Chilkat tried combinations. In fact, it was known that a dotted IPv4 address is what we have, and we're trying to get the damn getaddrinfo to return an IPv4-mapped IPv6 address. Apparently it does not. Thus the error "Network is unreachable" is caused by trying to connect to an IPv4 address on an IPv6-only network. If only we can get the friggin getaddrinfo to return a mapped IPv6 address, all would be dandy.

Did You Try Setting CkoSshTunnel.PreferIpv6 = YES?

Just in case you haven't, make sure you set either CkoGlobal.PreferIpv6 = YES, or sshTunnel.PreferIpv6 = YES.

You Can Take Matters Into Your Own Hands

In this case, you're writing code in Objective-C, which is just a superset of "C". Therefore, nothing stops you from calling getaddrinfo yourself to try to map your IPv4 address to an IPv6 address. If you can do that, then you can simply pass the IPv6 address string to CkoSshTunnel.Connect, and the problem should be solved.


Answer

Yes, of course, I set CkoSshTunnel.PreferIpv6 = YES

also, I wrote my custom resolver, but something wrong. Can you help me with it?

    ChilkatLog:
 Connect_SshTunnel:
   DllDate: Sep 24 2017
   ChilkatVersion: 9.5.0.70
   Architecture: Little Endian; 64-bit
   Language: IOS C/C++/Swift/Objective-C
   VerboseLogging: 0
   Component successfully unlocked using purchased unlock code.
   hostname: 1c1e:1bb::2001:2:0:1baa
   port: 443
   sshConnect:
     connectSocket:
       connect_ipv6_or_ipv4:
         timeout waiting for connect to complete;
         failedWaitToConnect: Socket operation timeout.
       --connect_ipv6_or_ipv4
     --connectSocket
     Failed to establish initial TCP/IP connection
     hostname: 1c1e:1bb::2001:2:0:1baa
     port: 443
   --sshConnect
   Failed.
 --Connect_SshTunnel
--ChilkatLog

Answer

The above LastErrorText is for a call to CkoSshTunnel.Connect, which is to connect with an SSH server. Your port number, however, is 443. That makes no sense because port 443 is the customary port number for SSL/TLS for an HTTP server. Change 443 to 22, which is the customary port for SSH servers.


Answer

We configured the ssh port to 443. Ssh is the only service running on the server and it’s listening on port 443. But this port number works fine for ipv4... I don't think that port number is a cause of this problem.

Do you have some other suggestions?


Answer

ChilkatLog:
 Connect_SshTunnel(30634ms):
   DllDate: Sep 24 2017
   ChilkatVersion: 9.5.0.70
   UnlockPrefix: FEDCMS.CB10618
   Architecture: Little Endian; 64-bit
   Language: IOS C/C++/Swift/Objective-C
   VerboseLogging: 1
   Component successfully unlocked using purchased unlock code.
   hostname: 1c1e:1bb::2001:2:0:1baa
   port: 443
   sshConnect(30634ms):
     connectSocket(30634ms):
       domainOrIpAddress: 1c1e:1bb::2001:2:0:1baa
       port: 443
       connectTimeoutMs: 30000
       connect_ipv6_or_ipv4(30634ms):
         This is an IPV6 numeric address.
         Domain to IP address resolution not needed.
         AddrInfoList:
           AddrInfo:
             ai_flags: 0
             ai_family: 30
             ai_socktype: 1
             ai_protocol: 6
             ai_addrlen: 28
             ai_canonname: (NULL)
             ipAddress: 1c1e:1bb::2001:2:0:1baa
           --AddrInfo
         --AddrInfoList
         The application prefers IPv6 over IPv4. Looking for IPv6 addresses first...
         connecting to IPV6 address...
         ipAddress: 1c1e:1bb::2001:2:0:1baa
         createSocket:
           Setting SO_SNDBUF size
           sendBufSize: 262144
           Setting SO_RCVBUF size
           recvBufSize: 4194304
         --createSocket
         connect(30634ms):
           Waiting for the connect to complete...
           timeout waiting for connect to complete;
           failedWaitToConnect: Socket operation timeout.
         --connect
       --connect_ipv6_or_ipv4
     --connectSocket
     Failed to establish initial TCP/IP connection
     hostname: 1c1e:1bb::2001:2:0:1baa
     port: 443
   --sshConnect
   Failed.
 --Connect_SshTunnel
--ChilkatLog

Answer

If the socket connection timed out, then either something is blocking the connection (such as a hardware or software firewall) or the IPv6 address is wrong.

Here's a new build with better logging:
https://chilkatdownload.com/prerelease/chilkat-9.5.0-ios9-259.zip

I would recommend doing something simple and experimenting. For example, create a CkoSocket object, and try connecting to various web servers using domain names, IPv4, and IPv6 addresses. Then see what can connect, and what does not.

Here are some samples. Connect to port 80 for all of them.

  1. akamai.com -- This web server has DNS records for both IPv4 and IPv6. If PreferIpv6 is true, then Chilkat should connect with an IPv6 address.
  2. chilkatsoft.com -- This web server has an IPv4 address (DNS record) but no IPv6 address. If you are on a computer with both IPv4 and IPv6, it should connect using IPv4. If on an IPv6 only network, check to see if you get an IPv6 address (translated from IPv4) which is used by a NAT64 router.
  3. Try "2600:1409:a:381::6a3". I think this is an IPv6 address for Akamai.com
  4. Try "107.180.46.206". This is chilkatsoft.com's IPv4 address.
  5. Try "145.72.70.20". I think this is an IPv4 address for Akamai.com
  6. Try "ipv6.test-ipv6-ct.comcast.net". This is a domain name for an IPv6 only host.

The information in the verbose LastErrorText should show you the exact values passed to getaddrinfo in each case. You can then compare those with what you are using in your custom resolver.


Answer

This new build: https://chilkatdownload.com/prerelease/chilkat-9.5.0-ios9-260.zip

Fixes an problem such that if PreferIpv6 is true, and your application is running on an IPv4-only network, then an IPv4 address will be used even if choices for both IPv6 and IPv4 are provided by getaddrinfo (internally).

I realize this wasn't the problem you're facing, but it's potentially another problem that you haven't encountered..


Answer

unfortunately, the library still fails on the apple NAT64 test network configuration using an ipv4 address, as well as an ipv6 address, but the ipv6 failure is probably due the the nat test configuration itself becuase ipv6 works fine on an ipv6 network.

Mentioned in point 3 under the "New Features in the 9.5.0.70 Pre-Release" post above that gettaddrinfo appears to be complicated, but it looks like apple lays everything out that needs to be done on this page: https://developer.apple.com/library/content/documentation/NetworkingInternetWeb/Conceptual/NetworkingOverview/UnderstandingandPreparingfortheIPv6Transition/UnderstandingandPreparingfortheIPv6Transition.html

see the sections "Check Source Code for IPv6 DNS64/NAT64 Incompatibilities" and "Use System APIs to Synthesize IPv6 Addresses"

So it looks like the solution may be that if you know you have an ipv4 address, you try to connect with it, and if it fails, execute the code that apple provides in this section: "Use System APIs to Synthesize IPv6 Addresses"


Answer

Thanks.

You mentioned this link: https://developer.apple.com/library/content/documentation/NetworkingInternetWeb/Conceptual/NetworkingOverview/UnderstandingandPreparingfortheIPv6Transition/UnderstandingandPreparingfortheIPv6Transition.html

At the aforementioned link, Apple provides a code snippet that supposedly can synthesize an IPv6 address from an IPv4 address:

Use System APIs to Synthesize IPv6 Addresses

If your app needs to connect to an IPv4-only server without a DNS hostname, use getaddrinfo to resolve the IPv4 address literal. If the current network interface doesn’t support IPv4, but supports IPv6, NAT64, and DNS64, performing this task will result in a synthesized IPv6 address.

Listing 10-1 shows how to resolve an IPv4 literal using getaddrinfo. Assuming you have an IPv4 address stored in memory as four bytes (such as {192, 0, 2, 1}), this example code converts it to a string (such as "192.0.2.1"), uses getaddrinfo to synthesize an IPv6 address (such as a struct sockaddr_in6 containing the IPv6 address "64:ff9b::192.0.2.1") and tries to connect to that IPv6 address.

Chilkat already does this exact thing. In fact, Chilkat was always doing it. The new versions I provided to you have two enhancements:

1) The exact inputs to getaddrinfo are logged in the LastErrorText. Specifically, Chilkat logs the hostname, the servname (which is a decimal port number), and the details passed in the hints. The hints.ai_flags are logged using the names, such as AI_ADDRCONFIG, AI_NUMERICSERV, etc. so that it's easy to see exactly which flags are set.

2) If the subsequent connect system function fails with the results from the getaddrinfo (or if the getaddrinfo did not return any sufficient results), then Chilkat re-tries with some alternative settings -- and you can see the retries w/ all the details in the LastErrorText.

I contend that what Apple claims about getaddrinfo being able to synthesize IPv6 addresses from an IPv4 address must not be working. (At least not in their environment when they are doing their testing -- but they provide you with no information, thank you very much Apple..)

It is entirely within your capability to play with the getaddrinfo code snippet provide by Apple at the above URL. See if you can synthesize an IPv6 address from an IPv4 address. If you can, then compare the values of the arguments you passed to getaddrinfo (including the hints) with what Chilkat logs in the LastErrorText. See if they are different, and let me know.

Of course, if you can synthesize the IPv6 address directly using getaddrinfo, then you can pass it to Chilkat instead of passing the IPv4 address.

I believe I've provided everything you need to move forward in solving this problem. If you find it impossible to synthesize an IPv6 address from an IPv4 address using getaddrinfo, then I don't know what else I can do. Also, if you can synthesize the IPv6 address in your test environment, and if Chilkat can also do it in your test environment, but Apple still rejects your app and provides no information to help you understand the reason, then I don't know what else I can do.

One possible way to avoid all of this trouble is to host your service on a computer/network such that it has both an IPv4 and IPv6 address. (i.e. an AAAA record) This way you can just avoid the entire IPv4-->IPv6 synthesis.