RFC 4038

Application Aspects of IPv6 Transition

πŸ“… published March 2005, from ietf

RFC 4038: Application Aspects of IPv6 Transition πŸ¦‹

Okay bestie, here's the deets πŸ’–

  • Number and title: RFC 4038, Application Aspects of IPv6 Transition 🌸
  • Stream: Network Working Group 🧚
  • Authors: M-K. Shin (Ed.) of ETRI/NIST, Y-G. Hong of ETRI, J. Hagino of IIJ, P. Savola of CSC/FUNET, and E. M. Castro of GSYC/URJC πŸ‘‘
  • Category: Informational πŸŽ€
  • Date: March 2005 πŸ“…
  • Obsoletes and updates: the title block doesn't list anything this RFC obsoletes or updates ✨

Status of This Memo πŸ’œ

This memo gives info to the Internet community. It's not an Internet standard of any kind, and distribution of it is unlimited 🌈

Copyright (C) The Internet Society (2005).

Abstract ✨

Okay so, as IPv6 networks get deployed and everyone's talking about the network transition, we also have to think about how applications running on IPv6 hosts can actually support IPv6, and what the best strategy is for building IP protocol support into apps πŸ’… This doc lays out the scenarios and aspects of application transition. It also suggests guidelines for writing IP version-independent apps during the transition period πŸ¦‹

Table of Contents πŸ—‚οΈ

   1.  Introduction .................................................  3
   2.  Overview of IPv6 Application Transition ......................  3
   3.  Problems with IPv6 Application Transition ....................  5
       3.1.  IPv6 Support in the OS and Applications Are Unrelated...  5
       3.2.  DNS Does Not Indicate Which IP Version Will Be Used ....  6
       3.3.  Supporting Many Versions of an Application Is Difficult.  6
   4.  Description of Transition Scenarios and Guidelines ...........  7
       4.1.  IPv4 Applications in a Dual-Stack Node .................  7
       4.2.  IPv6 Applications in a Dual-Stack Node .................  8
       4.3.  IPv4/IPv6 Applications in a Dual-Stack Node ............ 11
       4.4.  IPv4/IPv6 Applications in an IPv4-only Node ............ 12
   5.  Application Porting Considerations ........................... 12
       5.1.  Presentation Format for an IP Address .................. 13
       5.2.  Transport Layer API .................................... 14
       5.3.  Name and Address Resolution ............................ 15
       5.4.  Specific IP Dependencies ............................... 16
             5.4.1.  IP Address Selection ........................... 16
             5.4.2.  Application Framing ............................ 16
             5.4.3.  Storage of IP addresses ........................ 17
       5.5.  Multicast Applications ................................. 17
   6.  Developing IP Version - Independent Applications ............. 18
       6.1.  IP Version - Independent Structures..................... 18
       6.2.  IP Version - Independent APIs........................... 19
             6.2.1.  Example of Overly Simplistic TCP Server
                     Application .................................... 20
             6.2.2.  Example of Overly Simplistic TCP Client
                     Application .................................... 21
             6.2.3.  Binary/Presentation Format Conversion .......... 22
       6.3.  Iterated Jobs for Finding the Working Address .......... 23
             6.3.1.  Example of TCP Server Application .............. 23
             6.3.2.  Example of TCP Client Application .............. 25
   7.  Transition Mechanism Considerations .......................... 26
   8.  Security Considerations ...................................... 26
   9.  Acknowledgments .............................................. 27
   10. References ................................................... 27
   Appendix A.  Other Binary/Presentation Format Conversions ........ 30
       A.1.  Binary to Presentation Using inet_ntop() ............... 30
       A.2.  Presentation to Binary Using inet_pton() ............... 31
   Authors' Addresses ............................................... 32
   Full Copyright Statement ......................................... 33

1. Introduction ✨

Okay so, IPv6 is getting introduced into the IPv4-based Internet 🌐 and that's going to bring up a bunch of general stuff like routing, addressing, DNS, and scenarios. Lots of moving parts, bestie πŸ’…

The big key to a successful IPv6 transition is compatibility with the huge installed base of IPv4 hosts and routers 🫢 People have studied this a LOT already, and the work is still going on. [2893BIS] covers the basic transition mechanisms: dual-stack deployment and tunneling. There are tons of other mechanisms out there too, but none of them take a stance on whether applications support IPv6 😭

This document is all about the application side of IPv6 transition πŸ¦‹ Two related topics are covered:

  1. How different network transition techniques affect applications, and strategies for applications to support IPv6 and IPv4 πŸ’–
  2. How to build IPv6-capable or protocol-independent applications ("application porting guidelines") using standard APIs [RFC3493][RFC3542] πŸŽ€

When we say "application" here, we mean all kinds of applications, but the focus is on network apps built with relatively low-level APIs (like using the "C" language with standard libraries). Lots of these could be command-line driven, but that isn't a requirement 🧚

Apps will have to get modified to support IPv6 (and IPv4). You can do that using one of a number of techniques described in sections 2 - 4 🌸 Guidelines for writing those apps are in sections 5 and 6 πŸ‘‘

2. Overview of IPv6 Application Transition πŸ—ΊοΈ

Okay bestie, an app's transition can be sorted into four different cases ✨ (we skip the first case when there's no IPv6 support in either the app or the operating system, since that's a whole different vibe πŸ’€)

Here's the lineup, figure and all:

      +-------------------+
      |       appv4       | (appv4 - IPv4-only applications)
      +-------------------+
      | TCP / UDP / others| (transport protocols - TCP, UDP,
      +-------------------+  SCTP, DCCP, etc.)
      |    IPv4 | IPv6    | (IP protocols supported/enabled in the OS)
      +-------------------+

      Case 1. IPv4 applications in a dual-stack node.

      +-------------------+ (appv4 - IPv4-only applications)
      |  appv4  |  appv6  | (appv6 - IPv6-only applications)
      +-------------------+
      | TCP / UDP / others| (transport protocols - TCP, UDP,
      +-------------------+             SCTP, DCCP, etc.)
      |    IPv4 | IPv6    | (IP protocols supported/enabled in the OS)
      +-------------------+

      Case 2. IPv4-only applications and IPv6-only applications
              in a dual-stack node.

      +-------------------+
      |     appv4/v6      | (appv4/v6 - applications supporting
      +-------------------+             both IPv4 and IPv6)
      | TCP / UDP / others| (transport protocols - TCP, UDP,
      +-------------------+             SCTP, DCCP, etc.)
      |    IPv4 | IPv6    | (IP protocols supported/enabled in the OS)
      +-------------------+

      Case 3. Applications supporting both IPv4 and IPv6
              in a dual-stack node.

      +-------------------+
      |     appv4/v6      | (appv4/v6 - applications supporting
      +-------------------+             both IPv4 and IPv6)
      | TCP / UDP / others| (transport protocols - TCP, UDP,
      +-------------------+             SCTP, DCCP, etc.)
      |       IPv4        | (IP protocols supported/enabled in the OS)
      +-------------------+

      Case 4. Applications supporting both IPv4 and IPv6
              in an IPv4-only node.

         Figure 1. Overview of Application Transition

Figure 1 shows the cases of application transition, so here's the rundown πŸ’…

  • Case 1: IPv4-only apps in a dual-stack node 🌸 IPv6 is introduced in the node, but the apps haven't been ported to support IPv6 yet.
  • Case 2: IPv4-only apps and IPv6-only apps in a dual-stack node πŸ¦‹ Apps get ported for IPv6-only, so you end up with two similar apps, one per protocol version (for example, ping and ping6) πŸ‘―
  • Case 3: Apps supporting both IPv4 and IPv6 in a dual-stack node πŸ’– Apps get ported for both IPv4 and IPv6, so the existing IPv4 apps can be removed 🧹
  • Case 4: Apps supporting both IPv4 and IPv6 in an IPv4-only node 🌈 Apps get ported for both IPv4 and IPv6 support, but the same apps may also have to work when IPv6 isn't being used (for example, when it's disabled from the OS) πŸ™ˆ

The first two cases aren't that interesting in the long run πŸ₯± Only a few apps are inherently IPv4- or IPv6-specific, and the rest should work with both protocols without having to care which one is being used 🫢

3. Problems with IPv6 Application Transition 🚧

Okay so, there are several reasons the transition period between IPv4 and IPv6 apps may not be a straight shot 😩 We'll go through those issues in this section πŸ¦‹

3.1. IPv6 Support in the OS and Applications Are Unrelated 🌷

Think about the cases from the last section, and you'll see IPv4 and IPv6 protocol stacks are likely to co-exist in a node for a long time ⏳

Similarly, most apps are expected to handle both IPv4 and IPv6 for another long stretch 🫠 A dual-stack operating system isn't meant to have both IPv4 and IPv6 apps. So IPv6-capable app transition may be independent of the protocol stacks in a node πŸ’…

Apps that are capable of both IPv4 and IPv6 will probably have to work properly in IPv4-only nodes, whether IPv6 is completely disabled or there's no IPv6 connectivity at all πŸ™


To be continued, bestie πŸ’œπŸ¦‹ more parts are coming!

3.2. DNS Does Not Indicate Which IP Version Will Be Used 🌸

okay so, in a node, the DNS name resolver is the one that gathers the list of destination addresses πŸ“‹. DNS queries and responses get sent using either IPv4 or IPv6 to carry the queries, no matter what protocol version the data records are [DNSTRANS] 🧚

the DNS name resolution issue for application transition is that a client app can not be certain which version of the peer app it's talking to just from doing a DNS name lookup 😭. for example, say a server app doesn't support IPv6 yet, but it runs on a dual-stack machine that has other IPv6 services πŸ–₯️. if this host is listed with an AAAA record in the DNS, the client app will fail to connect to the server app πŸ’€. that's because there's a mismatch between the DNS query result (IPv6 addresses) and the server app's version (IPv4) πŸ™ˆ

using SRV records would avoid these problems ✨ 🌈 unfortunately, they aren't used widely enough to be useful in most cases 😩 so the operational fix is to use "service names" in the DNS πŸŽ€. if a node offers multiple services, but only some of them over IPv6, a DNS name can be added for each of these services or group of services (with the associated A/AAAA records) πŸ’…. so it's not just one name for the physical machine, and the AAAA records get included too πŸ¦‹. but ngl, applications can not depend on this operational practice 🚫

here's the vibe for the app: it should request all IP addresses without any address family constraints, then try all the records the DNS sends back, in some order, until it finds a working address πŸ”. the big thing is that the app has to be able to handle all the IP versions returned from the DNS 🫢. this is talked about in more detail in [DNSOPV6] πŸ“š

3.3. Supporting Many Versions of an Application is Difficult πŸ’œ

during the application transition period, sysadmins may have different versions of the same application running around πŸŒ€. like, an IPv4-only app, an IPv6-only app, or an app that supports both IPv4 and IPv6 🫠

typically, you can't know which IP versions must be supported before doing a DNS lookup and trying the addresses that come back (see section 3.2) πŸ€·β€β™€οΈ. so if there are multiple versions of the same app available, local users have a hard time picking the right one for the exact IP version they need 😀

to avoid problems with an app that doesn't support the specified protocol version, it's desirable to have hybrid apps that support both 🌟 iykyk, hybrid apps are the move πŸ’–

there's also an alternative for local client apps: a "wrapper application" 🎁. it does certain tasks (like figuring out which protocol version will be used) and calls the IPv4/IPv6-only apps as needed 🧁. this wrapper would do connection establishment (or similar tasks) and then pass the opened socket to another app πŸ”Œ. but here's the tea: since a wrapper like this has to do more than just a DNS lookup or work out the literal IP address, it gets complex, probably way more complex than a hybrid app πŸ˜΅β€πŸ’«. and writing "wrapping" apps that do complex stuff with IP addresses (like FTP clients) could be even more challenging, or even impossible πŸ’€. so in short, wrapper apps don't look like a robust approach for application transition πŸ™…β€β™€οΈ

4. Description of Transition Scenarios and Guidelines πŸ¦‹

okay now we're getting into the good stuff ✨. once the IPv6 network is deployed, apps that support IPv6 can use IPv6 network services to set up IPv6 connections πŸš€. however, upgrading every node to IPv6 at the same time is not feasible, so the move from IPv4 to IPv6 will be a gradual process 🐒

dual-stack nodes are one solution for keeping IPv4 compatibility in unicast communications 🫢. in this section we'll look at the different application transition scenarios (as introduced in section 2) and guidelines for keeping apps interoperable across different types of nodes 🧩

note that the first two cases, IPv4-only and IPv6-only applications, aren't that interesting long term πŸ™„ only a few apps are inherently IPv4- or IPv6-specific, and ideally they should work with both protocols without caring which one is in use πŸ’…

4.1. IPv4 Applications in a Dual-Stack Node πŸ’–

in this scenario, IPv6 gets added to a node, but IPv6-capable apps aren't available or installed yet 🌱. even though the node implements the dual stack, IPv4 apps can only manage IPv4 communications, and they accept and establish connections only with nodes that implement an IPv4 stack πŸ”’

to let an app talk to other nodes over IPv6, the first priority is to port the app to IPv6 🎯

in some cases (like when no source code is available), existing IPv4 apps can work if the Bump-in-the-Stack [BIS] or Bump-in-the-API [BIA] mechanism is installed on the node πŸ› οΈ. we strongly recommend that app developers don't use these mechanisms when the app's source code is available 🚨 also, they shouldn't be used as an excuse to skip porting or to delay it πŸ™…β€β™€οΈ

when [BIA] or [BIS] is used, the problem described in section 3.2 shows up (the IPv4 client on a [BIS]/[BIA] node tries to connect to an IPv4 server on a dual-stack system) 😬. still, you can rely on the [BIA]/[BIS] mechanism, which should cycle through all the addresses instead of the applications doing it πŸ”„

[BIS] and [BIA] don't work with every kind of app, especially apps that exchange IP addresses as application data (like FTP) 😭. these mechanisms give the apps IPv4 temporary addresses and do the translation between IPv4 and IPv6 communication locally πŸͺ„. because of that, these IPv4 temporary addresses are only valid in the node's scope πŸ“

4.2. IPv6 Applications in a Dual-Stack Node πŸ¦‹

okay so we already saw in the last bit that apps should be ported to IPv6 πŸ’…. the easiest way to do it is to swap the old IPv4 API calls for the new IPv6 ones, one-to-one. ✨ but then the app is IPv6-only, and that code can't work on IPv4-only nodes 😭. so you'd have to keep the old IPv4 app around for those machines, which means two similar apps running on different protocol versions (think telnet and telnet6 πŸ™ˆ). ngl that's a mess, because keeping two versions of the same source code per app can be really hard to maintain. it also makes users pick which version to run, and we already talked about why that's a problem in section 3.3 πŸ’€.

most dual-stack implementations let IPv6-only apps talk to both IPv4 and IPv6 nodes 🫢. the trick is that IPv4 packets headed for an IPv6 app on a dual-stack node still arrive, because the addresses get mapped using IPv4-mapped IPv6 addresses. the IPv6 address ::FFFF:x.y.z.w stands for the IPv4 address x.y.z.w 🌈.

      +----------------------------------------------+
      | +------------------------------------------+ |
      | |                                          | |
      | |        IPv6-only applications            | |
      | |                                          | |
      | +------------------------------------------+ |
      |                      |                       |
      | +------------------------------------------+ |
      | |                                          | |
      | |   TCP / UDP / others (SCTP, DCCP, etc.)  | |
      | |                                          | |
      | +------------------------------------------+ |
      |    IPv4-mapped    |        |    IPv6         |
      |  IPv6 addresses   |        |   addresses     |
      | +--------------------+ +-------------------+ |
      | |        IPv4        | |      IPv6         | |
      | +--------------------+ +-------------------+ |
      |   IPv4       |                 |             |
      |   addresses  |                 |             |
      +--------------|-----------------|-------------+
                     |                 |
                IPv4 packets      IPv6 packets

we're going to look at how IPv6 apps behave when they swap IPv4 packets with IPv4 apps, using the client/server model πŸ‘‘. the default case is when IPV6_V6ONLY has not been set. on these dual-stack nodes, that default gives you a limited amount of IPv4 communication through the IPv4-mapped IPv6 addresses 🧚.

IPv6-only server: When an IPv4 client app sends data to an IPv6-only server app on a dual-stack node using the wildcard address, the IPv4 client address shows up as an IPv4-mapped IPv6 address on that node. ✨ This lets the IPv6 app handle the conversation. the IPv6 server treats that mapped address like any regular IPv6 address, and it's a usual IPv6 connection from its point of view πŸŽ€. but the actual packets exchanged between the nodes are IPv4. kernels with dual stack properly read IPv4-mapped IPv6 addresses as IPv4 ones, and the other way around too πŸ’œ.

IPv6-only client: IPv6-only client apps on a dual-stack node won't get IPv4-mapped addresses back from the hostname resolution API functions, unless you pass the special hint AI_V4MAPPED πŸ™ˆ. if you do pass it, the IPv6 client uses the mapped address as if it were a regular IPv6 address, and it's a usual IPv6 connection again ✨. still, IPv4 packets get exchanged between the apps 🌸.

so when IPV6_V6ONLY is set, an IPv6-only server app will only talk to IPv6 nodes, and an IPv6-only client will only talk to IPv6 servers, because the mapped addresses are turned off πŸš«πŸ’…. this option can be useful if your apps use new IPv6 features like the Flow Label πŸ§šβ€β™€οΈ. but if you do need to talk to IPv4, then either IPV6_V6ONLY must not be used, or you need dual-stack apps, which section 4.3 covers 🫢.

some dual-stack implementations don't let IPv4-mapped IPv6 addresses be used for IPv4 and IPv6 apps to interoperate 😭. in those cases there are two ways to deal with it:

  1. Deploy two different versions of the application (possibly attached with '6' in the name).
  2. Deploy just one application supporting both protocol versions as described in the next section.

the first method is not recommended, because picking the right app runs into a whole pile of problems πŸ’€. those problems are described in sections 3.2 and 3.3 πŸ™ˆ.

so there are two separate things to think about when you write one app that supports both protocols:

  1. Whether the app can (or should) support both IPv4 and IPv6 through IPv4-mapped IPv6 addresses, or whether the apps should support both explicitly (see section 4.3), and
  2. Whether the systems where the apps run support IPv6 (see section 4.4) 🌈.

heads up, some systems turn off support for internal IPv4-mapped IPv6 addresses by default πŸ‘€. the security concerns around these are legit 😭, but turning them off breaks one transition mechanism for server apps that were originally written to bind() and listen() to a single socket on a wildcard address. this forces the developer to rewrite the daemon so it creates two separate sockets, one for IPv4 only and one for IPv6 only, and then uses select() πŸ’€. the catch is that whether IPv4 addresses get mapped on a particular system is controlled by the OS owner, not necessarily by the developer πŸ™ˆ. that makes life harder, because now developers have to rewrite the daemon's network code to handle both environments, even on the same OS 😀.


4.3. IPv4/IPv6 Applications in a Dual-Stack Node πŸ’–

apps should be ported to support both IPv4 and IPv6 🫢. over time, the old IPv4-only apps can be removed ✨. since you only have one version of each app, the source code is usually easy to maintain and change, and there's no hassle figuring out which app to pick for which communication πŸ’….

this transition case is the most advisable one πŸ‘‘. during the IPv6 transition period, apps that support both IPv4 and IPv6 should be able to talk to other apps, no matter which protocol stack version or app version is on the node 🌈. dual apps mean more interoperability between different apps and nodes, which is iconic πŸ¦‹.

if the source code is written in a protocol-independent way, with no dependencies on IPv4 or IPv6, then apps can talk to any combo of apps and node types 🧚.

implementations usually prefer IPv6 by default, as long as the remote node and app support it ✨. but if IPv6 connections fail, version-independent apps will automatically try IPv4 instead πŸ™Œ. the resolver returns a list of valid addresses for the remote node, and apps can work through all of them until one connection succeeds πŸ’œ.

app writers should be aware of this protocol ordering, which is usually the default, but the apps themselves typically don't need to be [RFC3484] 🌸.

if the source code is written in a protocol-dependent way, the app supports IPv4 and IPv6 explicitly by using two separate sockets πŸŽ€. note that bind() behaves a bit differently across implementations, specifically about whether you can first bind to IPv6 wildcard addresses and then to the IPv4 ones 😭. writing apps that cope with this can be a real pain πŸ’€. implementing IPV6_V6ONLY makes this simpler 🫢. the IPv4 wildcard bind fails on some systems because the IPv4 address space gets embedded into the IPv6 address space when IPv4-mapped IPv6 addresses are used πŸ™ˆ.

a more detailed porting guideline is in section 6 ✨.


4.4. IPv4/IPv6 Applications in an IPv4-Only Node πŸ“

the transition is likely to take a long time, so apps that already support both IPv4 and IPv6 may end up running on IPv4-only nodes 🌈. this usually happens to avoid maintaining two app versions for older and newer operating systems, or when a user wants to turn IPv6 off for some reason πŸ’….

the most important case is apps on systems where users can turn IPv6 support on or off dynamically πŸ‘€. apps on a system like that should be able to handle the situation where IPv6 is not enabled 🫢. another scenario is an app deployed on older systems that don't support IPv6 at all, not even basic APIs like getaddrinfo 😭. here the app designer has to make a case-by-case call: either build a compile-time toggle between an older and a newer API (so the code supports both), or provide getaddrinfo and friends as part of the app's libraries on the older platforms 🧚.

depending on the app and OS support, you might be tempted to ignore this case, but usually no assumptions can be made, and apps should also work in this scenario πŸ’–.

here's an example: an app that calls socket(), first trying AF_INET6 and then AF_INET πŸ™ˆ. but if the kernel doesn't have IPv6 support, the call results in an EPROTONOSUPPORT or EAFNOSUPPORT error πŸ’€. errors like these usually make the app exit the socket loop, so AF_INET never even gets tried 😀. the app needs to handle this case, or build the loop so errors are ignored until the last address family ✨.

this case is just an extension of the IPv4/IPv6 support from the previous case, covering one relatively common but often-ignored situation πŸ¦‹.


5. Application Porting Considerations πŸŽ€

the minimum changes IPv4 apps need in order to work with IPv6 come down to the different size and format of IPv4 and IPv6 addresses πŸ’….

apps were developed with the IPv4 protocol in mind, and that assumption has left lots of IP dependencies scattered through the source code 😭.

here's a summary of the more common IP version dependencies in apps πŸ“:

  • a) Presentation format for an IP address: an ASCII string that represents the IP address, a dotted-decimal string for IPv4, and a hexadecimal string for IPv6 🧚.
  • b) Transport layer API: functions to establish communications and exchange information 🌸.
  • c) Name and address resolution: conversion functions between hostnames and IP addresses 🫢.
  • d) Specific IP dependencies: more specific IP version dependencies, such as IP address selection, application framing, and storage of IP addresses πŸ‘€.
  • e) Multicast applications: you have to find the IPv6 equivalents of the IPv4 multicast addresses and use the right socket configuration options 🌈.

the next subsections describe the problems with these IP version dependencies πŸ™Œ. even though application source code can be ported to IPv6 with minimum changes related to IP addresses, some recommendations are given for modifying the source code in a protocol-independent way ✨, which lets apps work with both IPv4 and IPv6 πŸ’–.

5.1. Presentation Format for an IP Address

Okay so πŸŽ€ this section is about how IP addresses get written as text, and it's way more drama than it sounds. Lots of apps use IP addresses to find network nodes and set up connections. In the client/server model, clients usually need an IP address as an app parameter to reach a server πŸ’–. That address is usually handed over as a string in presentation format. Porting that causes two problems: the memory you allocated and how you manage the presentation format 😭.

The memory is the first issue. The space that holds an IPv4 address as a string is usually way too small for an IPv6 address πŸ’€. Apps should be modified so the bigger IPv6 address can't cause buffer overflows 🫢.

IPv4 and IPv6 don't even use the same format ✨. IPv4 uses a dot (.) to separate four octets written in decimal, while IPv6 uses a colon (:) to separate each pair of octets written in hexadecimal [RFC3513]. If you need to specify things like port numbers along with the address (more on that below), it may be desirable to require putting the address inside square brackets [TextRep] 🧚.

The parsing part is where things get messy πŸ™ˆ. A particular problem with IP address parsers shows up when the input is a combination of an IP address and a port number. With IPv4, these are often joined with a colon, like "192.0.2.1:80". With IPv6, that's ambiguous, because colons already structure the address itself.

So IP address parsers that take the port number separated by a colon should somehow tell IPv6 addresses apart πŸ‘‘. One way is to enclose the address in brackets, the same way Uniform Resource Locators (URLs) do [RFC2732]. For example: http://[2001:db8::1]:80.

Some apps also need to specify IPv6 prefixes and lengths 🌸. The prefix length should go outside the square brackets, if they're used. So write [2001:db8::]/64 or 2001:db8::/64, and not [2001:db8::/64]. Heads up: prefix/length notation looks exactly like a legal URI, so the prefix/length notation must not be used when it isn't clear from the context that it's specifying a prefix and length and not, for example, a URI 🚫.

Sometimes you need to give a zone identifier as part of the address, like fe80::1%eth0. Generally, apps shouldn't need to parse these identifiers πŸ’….

IP address parsers should support enclosing the IPv6 address in brackets, even when there's no port number involved ✨. Requiring that users always give a literal IP address in brackets is not recommended.

Also, some apps represent IPv6 address literals differently. For example, SMTP [RFC2821] uses [IPv6:2001:db8::1] πŸ¦‹.

Last but not least: using address literals is strongly discouraged for general-purpose direct input to apps. Host names and DNS should be used instead 🫢🌈.


5.2. Transport Layer API

Communication apps often include a transport module that sets up communications πŸ”₯. That module usually handles everything communication-related and uses a transport-layer API, typically from a network library. When an app gets ported to IPv6, most of the changes should land in this transport module so it can adapt to the new IPv6 API πŸ’œ.

In the general case, porting an existing app to IPv6 means looking at the following API issues πŸ‘€:

  • Network Information Storage: IP address Data Structures The new structures must contain 128-bit IP addresses. Using generic address structures, which can store any address family, is recommended. Sometimes special addresses are hard-coded in the app's source code, so developers should pay attention to those and switch them to the new address format. Some of these special addresses are wildcard local, loopback, and broadcast. IPv6 doesn't have broadcast addresses, so apps can use multicast instead 🌈.
  • Address Conversion Functions These convert between the binary address representation and the presentation format, and back again. The new conversion functions are specified for the IPv6 address format ✨.
  • Communication API Functions These manage communications, and their signatures are defined around a generic socket address structure. The same functions are valid for IPv6, but the IP address data structures passed to them need updating πŸ’–.
  • Network Configuration Options These get used when different communication models are configured for Input/Output (I/O) operations, like blocking/nonblocking, I/O multiplexing, and so on. They should be translated for IPv6 🧚.

5.3. Name and Address Resolution

From the app's point of view, name and address resolution is a system-independent process πŸ¦‹. An app calls functions in a system library, the resolver, which gets linked into the app when it's built. But these functions use IP address structures, which are protocol dependent, so they must be reviewed to support the new IPv6 resolution calls 😭.

With IPv6 there are two new basic resolution functions: getaddrinfo() and getnameinfo() πŸŽ€. The first one returns a list of all configured IP addresses for a hostname. These queries can be limited to one protocol family, for instance only IPv4 or only IPv6 addresses. However, it is recommended that all configured IP addresses be obtained so apps can work with every kind of node πŸ’…. The second function returns the hostname associated with an IP address 🌸.


5.4. Specific IP Dependencies

5.4.1. IP Address Selection

Unlike the IPv4 model, IPv6 promotes configuring multiple IP addresses per node πŸ”₯. But apps only use a destination/source pair for a communication, and choosing the right source and destination addresses is a key factor in the route IP datagrams take πŸ‘‘.

Typically, nodes (not apps) automatically handle source address selection. A node chooses the source address for a communication by following some rules of best choice, per [RFC3484], but it also lets apps make changes to the ordering rules ✨.

When it comes to picking the destination address, apps usually ask a resolver for the destination IP address. The resolver returns a set of valid IP addresses for a hostname. Unless an app has a specific reason to pick a particular destination address, it should try each element in the list until the communication succeeds πŸ’–.

Sometimes the app may need to specify its own source address. The destination address selection process picks the best destination for the source address, instead of picking the best source address for the chosen destination address πŸ¦‹. Heads up: if it isn't yet known which protocol will be used for communication, there may be an increase in complexity for IP version - independent apps that have to specify the source address (especially for client apps. Fortunately, specifying the source address is not typically required) πŸ™ˆ.

5.4.2. Application Framing

The Application Level Framing (ALF) architecture controls mechanisms that traditionally fall within the transport layer 🧚. Apps implementing ALF are often responsible for packetizing data into Application Data Units (ADUs). The app problem with ALF comes from ADU size selection, which is needed to get better performance πŸ”₯.

Apps using connectionless protocols (such as UDP) typically need application framing πŸ’…. These apps have three choices:

  1. Use packet sizes no larger than the IPv6 minimum Maximum Transmission Unit (MTU) of 1280 bytes [RFC2460].
  2. Use any packet sizes, but force IPv6 fragmentation/reassembly when necessary.
  3. Optimize the packet size to avoid unnecessary fragmentation/reassembly, and guess or find out the optimal packet sizes that can be sent and received, end-to-end, on the network.

This memo takes no stance on that approach is best πŸ€·β€β™€οΈ.

Note that the most optimal ALF depends on dynamic factors, such as the Path MTU or whether IPv4 or IPv6 is being used (because of different header sizes, possible IPv6-in-IPv4 tunneling overhead, and so on) 🌈. These factors have to be taken into consideration when application framing is implemented ✨.

5.4.3. Storage of IP Addresses

Some apps store IP addresses as remote peer information πŸŽ€. For instance, one of the most popular ways to register remote nodes in collaborative apps is to use IP addresses as registry keys πŸ’–.

Even though the source code that stores IP addresses can be modified for IPv6 by following the basic porting recommendations above, apps should not store IP addresses for the following reasons 😭:

  • IP addresses can change over time, for instance after a renumbering process.
  • The same node can reach a destination host using different IP addresses, possibly with a different protocol version.

When possible, apps should store names such as FQDNs or other protocol-independent identities instead of addresses πŸ¦‹. In that case, apps are only bound to specific addresses at run time, or for the duration of a cache lifetime. Other kinds of apps, like massive peer-to-peer systems with their own rendezvous and discovery mechanisms, may need to cache addresses for performance reasons. But cached addresses should not be treated as permanent, reliable information 🧚. In highly dynamic networks, any form of name resolution may be impossible, and here again addresses must be cached 🌸.

5.5. Multicast Applications

okay so multicast apps have their own drama πŸŽ€ when you port them, and it's not just one thing. first, apps have to swap the IPv4 multicast addresses for IPv6 ones, and second, the socket configuration options need updating too πŸ’…

here's the tea: every IPv6 multicast address encodes its scope, but in IPv4 the scope was only implicit (think multicast groups living in 239/8) πŸ¦‹ also, a bunch of application-specific multicast addresses got assigned back in the IPv4 days, and (thank goodness) that didn't happen with IPv6 πŸ™ˆ so there's no direct one-to-one equivalent for every group. for link-local multicast you can pick pretty much anything inside the link-local scope ✨ for the global groups, you could build them on unicast prefix-based addresses [RFC3306]. honestly it's giving "more protocol-dependent code," so devs might have to write extra stuff to keep up 😭

another wrinkle: IPv6 multicast doesn't have a standardized mechanism yet for the traditional Any Source Multicast for interdomain multicast 🌸 ASM and Source-Specific Multicast (SSM) work pretty similarly in IPv4 and IPv6, but PIM-SSM might end up getting more love in IPv6 because its architecture is simpler πŸ’œ

it could be a good move to port apps to SSM semantics. that means you need off-band source discovery mechanisms and a different API [RFC3678]. inter-domain ASM is only available through a method that embeds the Rendezvous Point address inside the multicast address [Embed-RP] 🧚

last but not least, multiparty conferencing apps have a similar problem to peer-to-peer apps. everyone in the session has to use the same protocol version (IPv4 or IPv6), or you need some kind of proxy or translator (e.g., [MUL-GW]) 🫢


6. Developing IP Version - Independent Applications ✨

okay so dual apps that work with both IPv4 and IPv6 are recommended πŸ‘‘ these apps should avoid IP dependencies in the source code. but if IP dependencies are unavoidable, one of the better solutions is to build a communication library that gives applications an IP version-independent API and hides all of the dependencies πŸŽ€

if you want to build IP version-independent apps, here are the guidelines to keep in mind πŸ’–

6.1. IP Version - Independent Structures

all memory structures and APIs should be IP version-independent 🌈 you should avoid struct in_addr, in6_addr, sockaddr_in, and sockaddr_in6 (yes, even though they're tempting 😭)

say a network address gets passed to some function, foo(). if you use struct in_addr or struct in6_addr, you end up needing an extra parameter to say which address family it is, like this:

struct in_addr in4addr;
struct in6_addr in6addr;
 /* IPv4 case */
foo(&in4addr, AF_INET);
 /* IPv6 case */
foo(&in6addr, AF_INET6);

this leads to duplicated code, and you have to think through every scenario from both sides separately, which is a pain to maintain πŸ₯² so instead we should use struct sockaddr_storage, like this:

struct sockaddr_storage ss;
int sslen;
/* AF independent! - use sockaddr when passing a pointer */
/* note: it's typically necessary to also pass the length
   explicitly */
foo((struct sockaddr *)&ss, sslen);

6.2. IP Version - Independent APIs

the new address-independent variants getaddrinfo() and getnameinfo() handle all the gory name-to-address and address-to-name translation stuff for you 🧚 they cover the functionality of these older functions:

gethostbyname()
gethostbyaddr()
getservbyname()
getservbyport()

they also obsolete the functionality of gethostbyname2(), which was defined in [RFC2133] πŸ’…

the new variants can do hostname/address and service name/port lookups, and you can turn those features off if you want πŸ¦‹ getaddrinfo() can return multiple addresses, like this:

localhost.      IN A    127.0.0.1
                IN A    127.0.0.2
                IN AAAA ::1

in this example, if IPv6 is preferred, getaddrinfo returns ::1 first. then 127.0.0.1 and 127.0.0.2 come back in a random order 🎲

getaddrinfo() and getnameinfo() can query the hostname and the service name/port all at once ✨

hardcoding AF-dependent knowledge into your program is not preferred πŸ™ˆ constructs like this one should be avoided:

/* BAD EXAMPLE */
switch (sa->sa_family) {
case AF_INET:
        salen = sizeof(struct sockaddr_in);
        break;
}

instead, use the ai_addrlen member of the addrinfo structure, as returned by getaddrinfo() 🌸

gethostbyname(), gethostbyaddr(), getservbyname(), and getservbyport() are mainly used to get server and client sockets. in the next sections we'll look at simple examples that create these sockets using the new IPv6 resolution functions 🫢

6.2.1. Example of Overly Simplistic TCP Server Application

here's a simple TCP server socket at service name (or port number string) SERVICE:

/*
 * BAD EXAMPLE: does not implement the getaddrinfo loop as
 * specified in 6.3.  This may result in one of the following:
 *  - an IPv6 server, listening at the wildcard address,
 *    allowing IPv4 addresses through IPv4-mapped IPv6 addresses.
 *  - an IPv4 server, if IPv6 is not enabled,
 *  - an IPv6-only server, if IPv6 is enabled but IPv4-mapped IPv6
 *    addresses are not used by default, or
 *  - no server at all, if getaddrinfo supports IPv6, but the
 *    system doesn't, and socket(AF_INET6, ...) exits with an
 *    error.
 */
struct addrinfo hints, *res;
int error, sockfd;

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 */

}

sockfd = socket(res->family, res->ai_socktype, res->ai_protocol);
if (sockfd < 0) {
   /* handle socket error */
}

if (bind(sockfd, res->ai_addr, res->ai_addrlen) < 0) {
   /* handle bind error */
}

/* ... */

freeaddrinfo(res);

6.2.2. Example of Overly Simplistic TCP Client Application

here's a simple TCP client socket connecting to a server running at node name (or IP address presentation format) SERVER_NODE and service name (or port number string) SERVICE πŸ“

/*
 * BAD EXAMPLE: does not implement the getaddrinfo loop as
 * specified in 6.3.  This may result in one of the following:
 *  - an IPv4 connection to an IPv4 destination,
 *  - an IPv6 connection to an IPv6 destination,
 *  - an attempt to try to reach an IPv6 destination (if AAAA
 *    record found), but failing -- without fallbacks -- because:
 *     o getaddrinfo supports IPv6 but the system does not
 *     o IPv6 routing doesn't exist, so falling back to e.g., TCP
 *       timeouts
 *     o IPv6 server reached, but service not IPv6-enabled or
 *       firewalled away
 *  - if the first destination is not reached, there is no
 *    fallback to the next records
 */
struct addrinfo hints, *res;
int error, sockfd;

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 look at the binary and presentation address format conversion APIs πŸŽ€ the following functions convert a network address structure to its presentation address format, and vice versa:

inet_ntop()
inet_pton()

both come from the basic socket extensions for IPv6. but these conversion functions are protocol-dependent, so it's better to use getnameinfo()/getaddrinfo() instead (the inet_pton and inet_ntop equivalents are described in Appendix A) 🧚

converting from a network address structure to presentation format can look like this:

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);

and converting from presentation format to a network address structure can look like this:

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 client code, when multiple addresses come back from getaddrinfo(), we should try all of them until the connection succeeds πŸ”₯ when a failure happens with socket(), connect(), bind(), or some other function, the code should move on and try the next address πŸ’–

also, if something goes wrong with the socket call because the address family isn't supported (i.e., in the 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

okay so the previous TCP server example should be written like this, bestie πŸŽ€ it's giving cleaner, safer, and way more IP-version-independent πŸ’…

#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

next up, the previous TCP client example should be written as follows πŸ¦‹ same energy, just way more glow-up ✨

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 🌈

okay transition time, and this part is lowkey tricky πŸ‘€ the mechanism [NAT-PT] introduces a special set of addresses. they're made of a NAT-PT prefix plus an IPv4 address, and they refer to IPv4 addresses that got translated by the NAT-PT DNS-ALG. some people might be tempted to treat these differently from everything else, but...

the spec is clear that IPv6 applications must not be required to distinguish "normal" and "NAT-PT translated" addresses πŸ™…β€β™€οΈ (or any other kind of special address, including the IPv4-mapped IPv6 addresses). the whole thing would be completely impractical, and if the distinction does have to be made, it has to happen somewhere else, like the kernel or the system libraries πŸ’–

8. Security Considerations πŸ’€

okay, security era. there are a number of security considerations for IPv6 transition, but those are outside the scope of this memo, so we're not diving in here πŸ™ˆ

BUT the memo does describe a bunch of ways to make applications more resistant to failures by cycling through addresses until a working one is found. this keeps the service available and robust even while transitioning to IPv6, and doing it properly is critical to maintain availability and to avoid loss of service. not a vibe to mess up 😭

a special consideration for application transition is how IPv4-mapped IPv6 addresses get handled. using them in the API can be a merit (easier application transition) and a burden (it gets harder to tell whether the use was legitimate) at the same time. some systems disable internal IPv4-mapped IPv6 address support by default. the security concerns about these on the wire are legit, but turning it off internally breaks one transition mechanism for server applications that were originally written to bind() and listen() to a single socket using a wildcard address [V6MAPPED]. this should be thought through in more detail when applications are designed 🧠✨

9. Acknowledgments 🫢

some of the guidelines for developing IP version-independent applications (section 6) were first brought up by [AF-APP]. other work to document application porting guidelines has been in progress too, for example [IP-GGF] and [PRT] 🌸

big thank-yous to the members of the v6ops working group and the application area for helpful comments. special thanks to Brian E. Carpenter, Antonio Querubin, Stig Venaas, Chirayu Patel, Jordi Palet, and Jason Lin for extensive review of this document πŸ™Œ and we acknowledge Ron Pike for proofreading it πŸ“

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 πŸ¦‹

okay bonus round! section 6.2.3 describes the preferred way to do binary/presentation format conversions. you can also do them with inet_pton() and inet_ntop() and by writing protocol-dependent code. this approach is not recommended, but it's here for reference and comparison, so you can see the difference πŸ‘€

heads up: inet_ntop()/inet_pton() lose the scope identifier (the one you'd use with link-local addresses, for example) during the conversions. getaddrinfo()/getnameinfo() don't do that, so that's a real difference 🚨

A.1. Binary to Presentation Using inet_ntop()

conversions from a network address structure to presentation format can be written like this:

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 hold the presentation address format: INET_ADDRSTRLEN for IPv4 and INET6_ADDRSTRLEN for IPv6. since 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() 🧚

okay so this is the reverse trip πŸ¦‹ you start with a readable string and want the raw binary address back. here's how that looks in code:

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 */
}

ngl the key thing to remember πŸ’… is that the address family of the presentation format must be known before you start. no family, no party πŸ₯Ί


Authors' Addresses πŸŽ€

the cute crew who made this happen 🫢

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

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 on whether any Intellectual Property Rights or other rights might apply to the technology in this document, or whether any license under those rights might or might not be available. it also doesn't claim to have checked for any such rights itself. info on how rights work for RFC documents is in BCP 78 and BCP 79.

copies of IPR disclosures sent to the IETF Secretariat, any assurances of licenses that will be made available, and the results of any attempt to get a general license or permission for implementers or users of this specification can be found in 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 send that information to the IETF at ietf-ipr@ietf.org πŸ’Œ


Acknowledgement πŸ’œ

funding for the RFC Editor function is currently provided by the Internet Society. thank you, internet society 🫢✨

πŸ“¦ where this page comes from