An Introduction to Writing Protocol Independant Code
In the 1990's the internet undertook a huge and unexpected
explosion of growth. It was soon realized that the current internet
protocol, IPv4, would be inadequate to handle the internet's continued
growth. So IPv6 was developed, allowing for millions of more IP addresses.
This, however, poses a new problem for us, the programmers. We can no
longer develop an application that is only supported by IPv4, nor would it
be an expeditious or cost effective solution to develop two versions of
the same application, one for IPv4 and another for IPv6. We must develop
our applications to work with both IPv4 and IPv6.
As the transition to IPv6 occurs, it is unlikely that IPv4 will be
discarded. Instead, the environment we are concerned with is one that
supports both IPv4 and IPv6, or one that runs a dual stack. A great deal
of the work is taken care of for us in the TCP/IP stack itself. I will
start this tutorial by discussing how hosts running on a dual stack can
communicate with other hosts. [Throughout this tutorial we assume all
programming takes place under a posix-compliant unix environment.]
Let's start by looking at our target environment, an IPv6 server
running on a host with a dual stack (we will discuss the client side
shortly). This is done by mapping an IPv4 address into an IPv6 address.
This is handled in the IP stack itself. Figure 1.1 shows an example of
| IPv4 Client | | IPv6 Client |
| TCP | | TCP |
| IPv4 | | IPv6 |
| Data Link | | Data Link |
| Data Link |
ipv4 addr (184.108.40.206) / \ ipv6 addr (5f1b:...)
| IPv4 | | IPv6 |
ipv4-mapped ipv6 addr \ / ipv6 addr (5f1b:...)
| TCP |
| IPv6 Server |
We now go through what happens step-by-step.
1. The IPv6 server starts and creates an IPv6 listening socket.
2. The IPv4 client calls gethostbyname() and requests the servers
A record. The IPv6 client calls gethostbyname() and requests the
servers AAAA record.
3. Both clients call connect() and send a SYN segment to the
4. The datalink reads both segments and passes them to the
appropriate IP module. The IPv4 SYN is sent to the IPv4 module,
the IPv6 SYN is sent to the IPv6 module.
5. The IPv4 module recieves an IPv4 SYN that is destined for an
IPv6 listening socket. The IPv4 module flags that the connection
will use an IPv4-mapped IPv6 address and accept() returns the
IPv4-mapped IPv6 address. The IPv6 module merely passes the IPv6
address after completing the 3-way handshake.
6. All further communications take place using IPv4 datagrams with
the IPv4 client and IPv6 datagrams with the IPv6 client.
Unless the server explicitely makes a query as to the nature of
the IP address (we discuss how this is one later) it will never know that
it is communicating with an IPv4 client using an IPv4-mapped IPv6 address.
We assume here that our server has both an IPv4 address (for the A record)
and an IPv6 address (for the AAAA record). Our scenerio will work until
all IPv4 addresses are taken. By that time most systems should, hopefully,
be running a dual stack.
Now we switch hosts and observe what happens when an IPv6 client
tries to communicate with an IPv4 server. We assume that the IPv6 client
is running under a dual stack, while the IPv4 server is not.
1) The IPv4 client starts, creating an IPv4 listening socket.
2) The IPv6 client calls gethostbyname() requesting the server's
AAAA record. IPv4 hosts only have A records so an IPv4-mapped IPv6
address is returned to the client.
3) The IPv6 client calls connect() using the IPv4-mapped IPv6
address. The kernel recognizes the mapped address and sends an
IPv4 SYN to the server.
4) The IPv4 server responds with the appropriate SYN/ACK and
the connection is established.
5) All further communications take place using IPv4 datagrams.
Through this example we can see how hosts running different IP
versions can communicate with one another. This is done by mapping an IPv4
address into an IPv6 address. We conclude the example by displaying in
figure 1.2 what server/client combinations are applicable for communications
S E R V E R
| IPv4 | IPv6 | IPv4- | IPv6- |
| | | dual stack | dual stack |
| IPv4 | yes | no | yes | yes |
| IPv6 | no | yes | no | yes |
| IPv4- | yes | no | yes | yes |
E | dual stack | | | | |
N | IPv6- | yes | yes | * | yes |
| dual stack | | | | |
In the case of an IPv6 client and an IPv4 server that are both
running under a dual stack, the client must request the servers A record
and send an IPv4 datagram for a connection to be established. This is
because, while an IPv4 address can always be represented as an IPv6
address, an IPv6 address cannot be represented as an IPv4 address. If the
IPv6 client were to send an IPv6 SYN, the IPv4 server would not be able to
create an IPv6-mapped IPv4 address.
There are many "no"'s in figure 1.2, however all of these occur
because of communication with an IPv6 host that does not run a dual stack.
We need not concern ourselves with such instances because it appears that
all IPv6 hosts will be running a dual stack. The only problem is the
instance of an IPv6 client and an IPv4 server, both of which running
under a dual stack, which we've already discussed.
Most existing code has been written to for compatibility with only
IPv4. One could port every application to be compatible with IPv6 and
write two versions of each new application (one for IPv4 and the other for
IPv6), however this would be a time consuming and tedious process. It
would furthermore fail to allow communications between IPv6 clients and
IPv4 servers (both running off of a dual stack); this problem needs to be
handled in the application layer. The prefered method would be to write
code that is compatible with both IPv4 and IPv6. In the next article I
will cover the use of the inet_XXX functions and getaddrinfo() in writing
protocol independant code.
Thanks to the #C crew, Avalonian and Weaver for answering my questions and
providing helpful documentaion, and to W. Richard Stevens for his
invaluable book, "Unix Network Programming, vol. 1", which helped me
solidify the concepts discussed here.
This page is Copyright © 1998 By
C Scene. All Rights Reserved