Converting C++ TCP/IP applications from IPv4 to IPv6. Difficult? Worth the trouble?

NTDLS picture NTDLS · Feb 26, 2010 · Viewed 13.3k times · Source

Over the years I've developed a small mass of C++ server/client applications for Windows using WinSock (Routers, Web/Mail/FTP Servers, etc... etc...).

I’m starting to think more and more of creating an IPv6 version of these applications (While maintaining the original IPv4 version as well, of course).

Questions:

  1. What pitfalls might I run into?
  2. Is the porting/conversion difficult?
  3. Is the conversion worth it?


For a reference (or for fun), you can sneek a peak of the IPv4 code at the core of my applications.

Answer

Einstein picture Einstein · Mar 3, 2010

getaddrinfo and getnameinfo are your friends.. As much as possible I suggest they be your best friends in your quest to provide IPv4 and IPv6 support in an existing application.

If done right by adding IPv6 support you also end up abstracting the system to the point where an unknown future IP protocol can run without code modification.

Normally when connecting you would fill out a socket structure, port, address family, IP address, converting address/ports to network byte order, etc.

With getaddrinfo you send an IP address or hostname and port or port name, and it returns a linked list with the structures and everything ready to be passed directly into socket() and connect().

getaddrinfo is critical for working with both IP protocols as it knows if the host has IPv6 or IPv4 connectivity and it knows if the peer does as well by looking at DNS AAAA vs A records and dynamically figures out which protocol(s) are available to service the specific connection request.

I highly advise against use of inet_pton(), inet_addr() or smiliar devices that are IP version specific. On the Windows platform specifically inet_pton() is not compatible with earlier versions of MS Windows (XP, 2003 et al.) unless you roll your own. Also advise against separate versions for IPv4 and IPv6... This is unworkable as a technical solution because in the near future both protocols will need to be used concurrently and people may not know ahead of time which to use. The socket interfaces are abstract and it's easy to detect dualstack or IPv6 support by attempting to create an IPv6 socket or attempt to set the IPv6 dualstack socket option for listeners. There is no reason the resulting application won't run on a system that does not support or know about IPv6.

For outgoing connections use PF_UNSPEC in getaddrinfo so that the address family is chosen for you when making outgoing connections. This, IMHO, is better than the dualstack approach because it allows platforms that do not support dualstack to work.

For incoming connections you can either bind IPv4/IPv6 sockets separately if it's reasonable given the design or use dualstack if you can't do separate listeners. When using dualstack getnameinfo returns an IPv6 address for IPv4 addresses which IMHO ends up being quite useless. A small utility routine can convert the string to a normal IPv4 address.

From my experience when done right you've removed dependencies on specific IP versions and ended up with less socket management code than you started.