Table of Contents

Table of Chapters

12 IPv6 Sockets

The IETF IPv6 working group has produced RFC-2133, which formally documents the use of "sockets" as a TCP/IP API. No API for IPv4 was ever formally documented by the IETF, which historically has taken the position that it should only specify protocols and not APIs. RFC-2133 is an "informational" RFC, which means it does not specify a standard - only a description of one way of doing things. Nevertheless, the InterNiche code provides extensions and changes to the InterNiche IPv4 sockets interface to bring the IPv6 product into compliance with this document.

IPv4 applications require changes to use IPv6 sockets. The scope of changes varies greatly, depending on the complexity of the application and the extent to which it encodes IP addressing information in data streams. This section reviews the potential changes throughout the InterNiche API. The reader should already be familiar with IPv4 sockets, as described in the Chapter 5, "Sockets".

12.1 Definitions and headers

RFC-2133 recommends a set of new structure and definitions for using IPv6 sockets, and is implemented by the InterNiche code. All the additional definitions for IPv6 sockets are in the InterNiche header file "socket6.h". This header file should be the only addition header needed to port an IPv4 application to IPv6.

RFC-2133 also recommends a series of header files, including path names, for use with IPv6 sockets. These paths and files are not included are part of the InterNiche deliverables, however providing an environment which simulates them is very easy. The engineer should simply create the needed paths (if they don't already exist on the development system), and inside each path create the named header files (again, if they don't already exist). The contents of these files should simply be a line including the all-purpose InterNiche IPv6 socket header, socket6.h.

12.2 Socket Creation

In almost every IPv4 application, the code used to create and connect sockets will need to be changed to support IPv6. In some cases (such as the InterNiche telnet server), this is the only change required.

As you may suspect, IPv6 needs to associate the longer IPv6 addresses with socket structures in place of the IPv4 addresses. In addition, a new address family parameter, "AF_INET6", is defined in addition to the traditional AF_INET.

Throughout the IPv6 sockets extensions, structures are usually named by taking the name of the traditional IPv4 structure and appending a "6" to the name. AF_INET and AF_INET6 are the first of many examples of this naming convention.

The type of socket (v4 or v6) is determined by the address family parameter passed to socket() when the socket is created. Once created, a socket may only be used for the family indicated. Below is an example IPv6 socket create call:

SOCKTYPE sock;

sock = t_socket(AF_INET6, SOCK_STREAM, 0);
if (sock == INVALID_SOCKET)
   return INVALID_SOCKET;

(note : "SOCKTYPE" is an InterNiche-ism.)

The IPv6 socket create call only differs from the IPv4 version by using AF_INET6 instead of AF_INET.

12.3 Connecting

Once created, a socket is usually connected or put into a listen mode. Either step involves associating the socket with IP addressing information, and therein is the major difference between v4 and v6 sockets.

The IPv6 addresses are accommodated by a new type of "sockaddr" structure, sockaddr_in6. The replaces the "sockaddr_in" structure widely used in IPv4.

struct sockaddr_in6
{
   u_short        sin6_family;   /* AF_INET6 */
   u_short        sin6_port;     /* transport layer port # */
   u_long         sin6_flowinfo; /* IPv6 flow information */
   ip6_addr       sin6_addr;     /* IPv6 address */
};

Active TCP connections (those which call connect() rather than listen() ) need to pass a sockaddr_in6 structure to the connect() call, rather than the v4-ish sockaddr_in structure. As mentioned above, the socket must have been created as an IPv6 socket by passing AF_INET6 to the socket() call.

The a sockaddr_in6 structure is larger than the a sockaddr_in structure, so the structure size parameter passed to connect() must reflect this. The InterNiche code performs a check on the size of the sockaddr length field, but currently the only effect of an incorrect size is a dtrap() call.

The sockaddr_in6 structure must have the sin6_family field set to AF_INET6, and the sin6_flowinfo field (which is new for IPv6) should be set to zero. [Note: The sin6_flowinfo field will be used for setting the IPv6 header's "flow label" field, pending specification by the IETF.]

The sin6_port filed is identical to the IPv4 sockaddr_in->sin_port field. It contains the 16-bit TCP or UDP port number to which the socket is to be bound.

Lastly, the sin6_addr field is the 128 bit IPv6 address for the socket. The sockaddr_in6 structure contains a complete copy of the address, not a pointer. In InterNiche code this is best set with IP6CPY().

Here is the example IPv6 active connect code from the FTP sever:

IP6CPY(&ftpsin.sin6_addr, &ftp->ip6_host);
ftpsin.sin6_port = htons(ftp->dataport);
ftpsin.sin6_family = AF_INET6;

e = t_connect(sock, (struct sockaddr*)&ftpsin, sizeof(ftpsin));
if (e != 0)
{
   ... error handling

Passive TCP connections over IPv6 (those which form TCP connections via the bind() - listen() - accept() sequence) differ from IPv4 passive connections by passing the sockaddr_in6 structure to bind(), rather than the IPv4 version sockaddr_in. As with connect(), the sockaddr size parameter must reflect the size of a sockaddr_in6. The members of the sockaddr_in6 structure are set in the same way as they are for a connect() call (see above).

Here is the example IPv6 bind code from the FTP sever:

 IP6CPY(&ftpsin6.sin6_addr, &in6addr_any);
 ftpsin6.sin6_port = htons(*lport);
 ftpsin6.sin6_family = AF_INET6;
 e = t_bind(sock, (struct sockaddr *)&ftpsin6, addrlen);
 if (e != 0)
 {
    ... error handling

Most other socket calls are the same for IPv6 and IPv4 sockets. Specifically, the calls to read write and close sockets are identical between the two IP versions.

12.4 FTP and IP addressing in the data stream

Of all the RFC-defined InterNiche TCP/IP applications, only FTP transmits IP addressing information (IP addresses and port numbers) in the data stream. RFC-2428 ("FTP Extensions for IPv6 and NATs") provides the specification for encoding IPv6 addresses in the FTP command socket's ASCII data stream. The RFC-2428 specification also provides for encoding IPv4 address in the FTP command socket's ASCII data stream.

The InterNiche FTP server code supports RFC-2428 IPv6 encoding, since the FTP standard (RFC-959) does not allow for IP addresses other than IPv4. The IPv4 encoding is still done per RFC-959, since it will probably be many years before FTP servers on IPv4 networks widely support RFC-2428 encoding.

12.5 Socket domain field

Throughout the sockets and transport layer InterNiche code, IPv4 sockets are distinguished from IPv6 sockets by the new socket structure field so_domain. This field is set to either AF_INET or AF_INET6, and is present no matter what compile-time definitions are used.

12.6 DNS (getnodebyname())

The InterNiche DNS client has been modified to provide the sockets call "getnodebyname()" as a manner consistent with RFC-2553. This is similar to the IPv4-only function gethostbyname(), however RFC-2553 has extended the syntax to handle IPv6 addresses.

The DNS client implementation currently uses AAAA records to implement DNS requests for an IPv6 host.