memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
error = getaddrinfo(SERVER_NODE, SERVICE, &hints, &res);
if (error != 0) {
/* handle getaddrinfo error */
}
sockfd = socket(res->family, res->ai_socktype, res->ai_protocol);
if (sockfd < 0) {
/* handle socket error */
}
if (connect(sockfd, res->ai_addr, res->ai_addrlen) < 0 ) {
/* handle connect error */
}
/* ... */
freeaddrinfo(res);
6.2.3. Binary/Presentation Format Conversion
We should consider the binary and presentation address format
conversion APIs. The following functions convert network address
structure in its presentation address format and vice versa:
inet_ntop()
inet_pton()
Both are from the basic socket extensions for IPv6. However, these
conversion functions are protocol-dependent. It is better to use
getnameinfo()/getaddrinfo() (inet_pton and inet_ntop equivalents are
described in Appendix A).
Conversion from network address structure to presentation format can
be written as follows:
struct sockaddr_storage ss;
char addrStr[INET6_ADDRSTRLEN];
char servStr[NI_MAXSERV];
int error;
/* fill ss structure */
error = getnameinfo((struct sockaddr *)&ss, sizeof(ss),
addrStr, sizeof(addrStr),
servStr, sizeof(servStr),
NI_NUMERICHOST);
Conversions from presentation format to network address structure can
be written as follows:
struct addrinfo hints, *res;
char addrStr[INET6_ADDRSTRLEN];
int error;
/* fill addrStr buffer */
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
error = getaddrinfo(addrStr, NULL, &hints, &res);
if (error != 0) {
/* handle getaddrinfo error */
}
/* res->ai_addr contains the network address structure */
/* ... */
freeaddrinfo(res);
6.3. Iterated Jobs for Finding the Working Address
In a client code, when multiple addresses are returned from
getaddrinfo(), we should try all of them until connection succeeds.
When a failure occurs with socket(), connect(), bind(), or some other
function, the code should go on to try the next address.
In addition, if something is wrong with the socket call because the
address family is not supported (i.e., in case of section 4.4),
applications should try the next address structure.
Note: In the following examples, the socket() return value error
handling could be simplified by always continuing on with the socket
loop instead of performing special checking of specific error
numbers.
6.3.1. Example of TCP Server Application
The previous TCP server example should be written as follows:
#define MAXSOCK 2
struct addrinfo hints, *res;
int error, sockfd[MAXSOCK], nsock=0;
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_PASSIVE;
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
error = getaddrinfo(NULL, SERVICE, &hints, &res);
if (error != 0) {
/* handle getaddrinfo error */
}
for (aip=res; aip && nsock < MAXSOCK; aip=aip->ai_next) {
sockfd[nsock] = socket(aip->ai_family,
aip->ai_socktype,
aip->ai_protocol);
if (sockfd[nsock] < 0) {
switch errno {
case EAFNOSUPPORT:
case EPROTONOSUPPORT:
/*
* e.g., skip the errors until
* the last address family,
* see section 4.4.
*/
if (aip->ai_next)
continue;
else {
/* handle unknown protocol errors */
break;
}
default:
/* handle other socket errors */
;
}
} else {
int on = 1;
/* optional: works better if dual-binding to wildcard
address */
if (aip->ai_family == AF_INET6) {
setsockopt(sockfd[nsock], IPPROTO_IPV6, IPV6_V6ONLY,
(char *)&on, sizeof(on));
/* errors are ignored */
}
if (bind(sockfd[nsock], aip->ai_addr,
aip->ai_addrlen) < 0 ) {
/* handle bind error */
close(sockfd[nsock]);
continue;
}
if (listen(sockfd[nsock], SOMAXCONN) < 0) {
/* handle listen errors */
close(sockfd[nsock]);
continue;
}
}
nsock++;
}
freeaddrinfo(res);
/* check that we were able to obtain the sockets */
6.3.2. Example of TCP Client Application
The previous TCP client example should be written as follows:
struct addrinfo hints, *res, *aip;
int sockfd, error;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
error = getaddrinfo(SERVER_NODE, SERVICE, &hints, &res);
if (error != 0) {
/* handle getaddrinfo error */
}
for (aip=res; aip; aip=aip->ai_next) {
sockfd = socket(aip->ai_family,
aip->ai_socktype,
aip->ai_protocol);
if (sockfd < 0) {
switch errno {
case EAFNOSUPPORT:
case EPROTONOSUPPORT:
/*
* e.g., skip the errors until
* the last address family,
* see section 4.4.
*/
if (aip->ai_next)
continue;
else {
/* handle unknown protocol errors */
break;
}
default:
/* handle other socket errors */
;
}
} else {
if (connect(sockfd, aip->ai_addr, aip->ai_addrlen) == 0)
break;
/* handle connect errors */
close(sockfd);
sockfd=-1;
}
}
if (sockfd > 0) {
/* socket connected to server address */
/* ... */
}
freeaddrinfo(res);
7. Transition Mechanism Considerations
The mechanism [NAT-PT] introduces a special set of addresses, formed
of an NAT-PT prefix and an IPv4 address these refer to IPv4 addresses
translated by NAT-PT DNS-ALG. In some cases, one might be tempted to
handle these differently.
However, IPv6 applications must not be required to distinguish
"normal" and "NAT-PT translated" addresses (or any other kind of
special addresses, including the IPv4-mapped IPv6 addresses): This
would be completely impractical, and if the distinction must be made,
it must be done elsewhere (e.g., kernel, system libraries).
8. Security Considerations
There are a number of security considerations for IPv6 transition,
but those are outside the scope of this memo.
To ensure the availability and robustness of the service even when
transitioning to IPv6, this memo describes a number of ways to make
applications more resistant to failures by cycling through addresses
until a working one is found. Doing this properly is critical to
maintain availability and to avoid loss of service.
A special consideration about application transition is how IPv4-
mapped IPv6 addresses are handled. The use in the API can be seen
both as a merit (easier application transition) and as a burden
(difficulty in ensuring whether the use was legitimate). Note that
some systems will disable (by default) support for internal IPv4-
mapped IPv6 addresses. The security concerns regarding these on the
wire are legitimate, but disabling it internally breaks one
transition mechanism for server applications originally written to
bind() and listen() to a single socket by using a wildcard address
[V6MAPPED]. This should be considered in more detail when
applications are designed.
9. Acknowledgments
Some of guidelines for development of IP version-independent
applications (section 6) were first brought up by [AF-APP]. Other
work to document application porting guidelines has also been in
progress; for example, [IP-GGF] and [PRT]. We would like to thank
the members of the v6ops working group and the application area for
helpful comments. Special thanks are due to Brian E. Carpenter,
Antonio Querubin, Stig Venaas, Chirayu Patel, Jordi Palet, and Jason
Lin for extensive review of this document. We acknowledge Ron Pike
for proofreading the document.
10. References
10.1. Normative References
[RFC3493] Gilligan, R., Thomson, S., Bound, J., McCann, J., and W.
Stevens, "Basic Socket Interface Extensions for IPv6",
RFC 3493, February 2003.
[RFC3542] Stevens, W., Thomas, M., Nordmark, E., and T. Jinmei,
"Advanced Sockets Application Program Interface (API) for
IPv6", RFC 3542, May 2003.
[BIS] Tsuchiya, K., Higuchi, H., and Y. Atarashi, "Dual Stack
Hosts using the "Bump-In-the-Stack" Technique (BIS)", RFC
2767, February 2000.
[BIA] Lee, S., Shin, M-K., Kim, Y-J., Nordmark, E., and A.
Durand, "Dual Stack Hosts Using "Bump-in-the-API" (BIA)",
RFC 3338, October 2002.
[RFC2460] Deering, S. and R. Hinden, "Internet Protocol, Version 6
(IPv6) Specification", RFC 2460, December 1998.
[RFC3484] Draves, R., "Default Address Selection for Internet
Protocol version 6 (IPv6)", RFC 3484, February 2003.
[RFC3513] Hinden, R. and S. Deering, "Internet Protocol Version 6
(IPv6) Addressing Architecture", RFC 3513, April 2003.
10.2. Informative References
[2893BIS] Nordmark, E. and R. E. Gilligan, "Basic Transition
Mechanisms for IPv6 Hosts and Routers", Work in Progress,
June 2004.
[RFC2133] Gilligan, R., Thomson, S., Bound, J., and W. Stevens,
"Basic Socket Interface Extensions for IPv6", RFC 2133,
April 1997.
[RFC2732] Hinden, R., Carpenter, B., and L. Masinter, "Format for
Literal IPv6 Addresses in URL’s", RFC 2732, December
1999.
[RFC2821] Klensin, J., "Simple Mail Transfer Protocol", RFC 2821,
April 2001.
[TextRep] Main, A., "Textual Representation of IPv4 and IPv6
Addresses", Work in Progress, October 2003.
[NAT-PT] Tsirtsis, G. and P. Srisuresh, "Network Address
Translation - Protocol Translation (NAT-PT)", RFC 2766,
February 2000.
[DNSTRANS] Durand, A. and J. Ihren, "DNS IPv6 Transport Operational
Guidelines", BCP 91, RFC 3901, September 2004.
[DNSOPV6] Durand, A., Ihren, J. and P. Savola, "Operational
Considerations and Issues with IPv6 DNS", Work in
Progress, May 2004.
[AF-APP] Hagino, J., "Implementing AF-independent application",
http://www.kame.net/newsletter/19980604/, 2001.
[V6MAPPED] Hagino, J., "IPv4 mapped address considered harmful",
Work in Progress, April 2002.
[IP-GGF] Chown, T., Bound, J., Jiang, S. and P. O’Hanlon,
"Guidelines for IP version independence in GGF
specifications", Global Grid Forum(GGF) Documentation,
work in Progress, September 2003.
[Embed-RP] Savola, P. and B. Haberman, "Embedding the Rendezvous
Point (RP) Address in an IPv6 Multicast Address", RFC
3956, November 2004.
[RFC3306] Haberman, B. and D. Thaler, "Unicast-Prefix-based IPv6
Multicast Addresses", RFC 3306, August 2002.
[RFC3678] Thaler, D., Fenner, B., and B. Quinn, "Socket Interface
Extensions for Multicast Source Filters, RFC 3678,
January 2004.
[MUL-GW] Venaas, S., "An IPv4 - IPv6 multicast gateway", Work in
Progress, February 2003.
[PRT] Castro, E. M., "Programming guidelines on transition to
IPv6 LONG project", Work in Progress, January 2003.
Appendix A. Other Binary/Presentation Format Conversions
Section 6.2.3 describes the preferred way to perform
binary/presentation format conversions; these can also be done by
using inet_pton() and inet_ntop() and by writing protocol-dependent
code. This approach is not recommended, but it is provided here for
reference and comparison.
Note that inet_ntop()/inet_pton() lose the scope identifier (if used,
e.g., with link-local addresses) in the conversions, contrary to the
getaddrinfo()/getnameinfo() functions.
A.1. Binary to Presentation Using inet_ntop()
Conversions from network address structure to presentation format can
be written as follows:
struct sockaddr_storage ss;
char addrStr[INET6_ADDRSTRLEN];
/* fill ss structure */
switch (ss.ss_family) {
case AF_INET:
inet_ntop(ss.ss_family,
&((struct sockaddr_in *)&ss)->sin_addr,
addrStr,
sizeof(addrStr));
break;
case AF_INET6:
inet_ntop(ss.ss_family,
&((struct sockaddr_in6 *)&ss)->sin6_addr,
addrStr,
sizeof(addrStr));
break;
default:
/* handle unknown family */
}
Note that, the destination buffer addrStr should be long enough to
contain the presentation address format: INET_ADDRSTRLEN for IPv4 and
INET6_ADDRSTRLEN for IPv6. As INET6_ADDRSTRLEN is longer than
INET_ADDRSTRLEN, the first one is used as the destination buffer
length.
A.2. Presentation to Binary Using inet_pton()
Conversions from presentation format to network address structure can
be written as follows:
struct sockaddr_storage ss;
struct sockaddr_in *sin;
struct sockaddr_in6 *sin6;
char addrStr[INET6_ADDRSTRLEN];
/* fill addrStr buffer and ss.ss_family */
switch (ss.ss_family) {
case AF_INET:
sin = (struct sockaddr_in *)&ss;
inet_pton(ss.ss_family,
addrStr,
(sockaddr *)&sin->sin_addr));
break;
case AF_INET6:
sin6 = (struct sockaddr_in6 *)&ss;
inet_pton(ss.ss_family,
addrStr,
(sockaddr *)&sin6->sin6_addr);
break;
default:
/* handle unknown family */
}
Note that, the address family of the presentation format must be
known.
Authors’ Addresses
Myung-Ki Shin
ETRI/NIST
820 West Diamond Avenue
Gaithersburg, MD 20899, USA
Phone: +1 301 975-3613
Fax: +1 301 590-0932
EMail: mshin@nist.gov
Yong-Guen Hong
ETRI PEC
161 Gajeong-Dong, Yuseong-Gu, Daejeon 305-350, Korea
Phone: +82 42 860 6447
Fax: +82 42 861 5404
EMail: yghong@pec.etri.re.kr
Jun-ichiro itojun HAGINO
Research Laboratory, Internet Initiative Japan Inc.
Takebashi Yasuda Bldg.,
3-13 Kanda Nishiki-cho,
Chiyoda-ku,Tokyo 101-0054, JAPAN
Phone: +81-3-5259-6350
Fax: +81-3-5259-6351
EMail: itojun@iijlab.net
Pekka Savola
CSC/FUNET
Espoo, Finland
EMail: psavola@funet.fi
Eva M. Castro
Rey Juan Carlos University (URJC)
Departamento de Informatica, Estadistica y Telematica
C/Tulipan s/n
28933 Madrid - SPAIN
EMail: eva@gsyc.escet.urjc.es
Full Copyright Statement
Copyright (C) The Internet Society (2005).
This document is subject to the rights, licenses and restrictions
contained in BCP 78, and except as set forth therein, the authors
retain all their rights.
This document and the information contained herein are provided on an
"AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
Intellectual Property
The IETF takes no position regarding the validity or scope of any
Intellectual Property Rights or other rights that might be claimed to
pertain to the implementation or use of the technology described in
this document or the extent to which any license under such rights
might or might not be available; nor does it represent that it has
made any independent effort to identify any such rights. Information
on the procedures with respect to rights in RFC documents can be
found in BCP 78 and BCP 79.
Copies of IPR disclosures made to the IETF Secretariat and any
assurances of licenses to be made available, or the result of an
attempt made to obtain a general license or permission for the use of
such proprietary rights by implementers or users of this
specification can be obtained from the IETF on-line IPR repository at
http://www.ietf.org/ipr.
The IETF invites any interested party to bring to its attention any
copyrights, patents or patent applications, or other proprietary
rights that may cover technology that may be required to implement
this standard. Please address the information to the IETF at ietf-
ipr@ietf.org.
Acknowledgement
Funding for the RFC Editor function is currently provided by the
Internet Society.