RFC 4038 - Application Aspects of IPv6 Transition(2)

时间:2006-10-31 来源: 作者: 点击:
shouldsupportbothexplicitly(seesection4.3),and 2.Whetherthesystemsinwhichtheapplicationsareusedsupport IPv6(seesection4.4). Notethatsomesystemswilldisable(bydefault)supportforinternal IPv4-mappedIPv6
  
         should support both explicitly (see section 4.3), and

      2. Whether the systems in which the applications are used support
         IPv6 (see section 4.4).

   Note that some systems will disable (by default) support for internal
   IPv4-mapped IPv6 addresses.  The security concerns regarding these
   are legitimate, but disabling them internally breaks one transition
   mechanism for server applications originally written to bind() and
   listen() to a single socket by using a wildcard address.  This forces
   the software developer to rewrite the daemon to create two separate
   sockets, one for IPv4 only and the other for IPv6 only, and then to
   use select().  However, mapping-enabling of IPv4 addresses on any
   particular system is controlled by the OS owner and not necessarily

   by a developer.  This complicates developers’ work, as they now have
   to rewrite the daemon network code to handle both environments, even
   for the same OS.

4.3.  IPv4/IPv6 Applications in a Dual-Stack Node

   Applications should be ported to support both IPv4 and IPv6.  Over
   time, the existing IPv4-only applications could be removed.  As we
   have only one version of each application, the source code will
   typically be easy to maintain and to modify, and there are no
   problems managing which application to select for which
   communication.

   This transition case is the most advisable.  During the IPv6
   transition period, applications supporting both IPv4 and IPv6 should
   be able to communicate with other applications, irrespective of the
   version of the protocol stack or the application in the node.  Dual
   applications allow more interoperability between heterogeneous
   applications and nodes.

   If the source code is written in a protocol-independent way, without
   dependencies on either IPv4 or IPv6, applications will be able to
   communicate with any combination of applications and types of nodes.

   Implementations typically prefer IPv6 by default if the remote node
   and application support it.  However, if IPv6 connections fail,
   version-independent applications will automatically try IPv4 ones.
   The resolver returns a list of valid addresses for the remote node,
   and applications can iterate through all of them until connection
   succeeds.

   Application writers should be aware of this protocol ordering, which
   is typically the default, but the applications themselves usually
   need not be [RFC3484].

   If the source code is written in a protocol-dependent way, the
   application will support IPv4 and IPv6 explicitly by using two
   separate sockets.  Note that there are some differences in bind()
   implementation - that is,  in whether one can first bind to IPv6
   wildcard addresses, and then to those for IPv4.  Writing applications
   that cope with this can be a pain.  Implementing IPV6_V6ONLY
   simplifies this.  The IPv4 wildcard bind fails on some systems
   because the IPv4 address space is embedded into IPv6 address space
   when IPv4-mapped IPv6 addresses are used.

   A more detailed porting guideline is described in section 6.

4.4.  IPv4/IPv6 Applications in an IPv4-Only Node

   As the transition is likely to take place over a longer time frame,
   applications already ported to support both IPv4 and IPv6 may be run
   on IPv4-only nodes.  This would typically be done to avoid supporting
   two application versions for older and newer operating systems, or to
   support a case in which the user wants to disable IPv6 for some
   reason.

   The most important case is the application support on systems where
   IPv6 support can be dynamically enabled or disabled by the users.
   Applications on such a system should be able to handle a situation
   IPv6 would not be enabled.  Another scenario is when an application
   is deployed on older systems that do not support IPv6 at all (even
   the basic APIs such as getaddrinfo).  In this case, the application
   designer has to make a case-by-case judgment call as to whether it
   makes sense to have compile-time toggle between an older and a newer
   API (having to support both in the code), or whether to provide
   getaddrinfo etc. function support on older platforms as part of the
   application libraries.

   Depending on application/operating system support, some may want to
   ignore this case, but usually no assumptions can be made, and
   applications should also work in this scenario.

   An example is an application that issues a socket() command, first
   trying AF_INET6 and then AF_INET.  However, if the kernel does not
   have IPv6 support, the call will result in an EPROTONOSUPPORT or
   EAFNOSUPPORT error.  Typically, errors like these lead to exiting the
   socket loop, and AF_INET will not even be tried.  The application
   will need to handle this case or build the loop so that errors are
   ignored until the last address family.

   This case is just an extension of the IPv4/IPv6 support in the
   previous case, covering one relatively common but often-ignored case.

5.  Application Porting Considerations

   The minimum changes for IPv4 applications to work with IPv6 are based
   on the different size and format of IPv4 and IPv6 addresses.

   Applications have been developed with IPv4 network protocol in mind.
   This assumption has resulted in many IP dependencies through source
   code.

   The following list summarizes the more common IP version dependencies
   in applications:

      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
         to 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: One must find the IPv6 equivalents to
         the IPv4 multicast addresses and use the right socket
         configuration options.

   The following subsections describe the problems with the
   aforementioned IP version dependencies.  Although application source
   code can be ported to IPv6 with minimum changes related to IP
   addresses, some recommendations are given to modify the source code
   in a protocol-independent way, which will allow applications to work
   with both IPv4 and IPv6.

5.1.  Presentation Format for an IP Address

   Many applications use IP addresses to identify network nodes and to
   establish connections to destination addresses.  For instance, using
   the client/server model, clients usually need an IP address as an
   application parameter to connect to a server.  This IP address is
   usually provided in the presentation format, as a string.  There are
   two problems when porting the presentation format for an IP address:
   the allocated memory and the management of the presentation format.

   Usually, the memory allocated to contain an IPv4 address
   representation as a string is unable to contain an IPv6 address.
   Applications should be modified to prevent buffer overflows made
   possible by the larger IPv6 address.

   IPv4 and IPv6 do not use the same presentation format.  IPv4 uses a
   dot (.) to separate the four octets written in decimal notation, and
   IPv6 uses a colon (:) to separate each pair of octets written in
   hexadecimal notation [RFC3513].  In cases where one must be able to
   specify, for example, port numbers with the address (see below), it
   may be desirable to require placing the address inside the square
   brackets [TextRep].

   A particular problem with IP address parsers comes when the input is
   actually a combination of IP address and port number.  With IPv4
   these are often coupled with a colon; for example, "192.0.2.1:80".
   However, this approach would be ambiguous with IPv6, as colons are
   already used to structure the address.

   Therefore, the IP address parsers that take the port number separated
   with a colon should distinguish IPv6 addresses somehow.  One way is
   to enclose the address in brackets, as is done with Uniform Resource
   Locators (URLs) [RFC2732]; for example, http://[2001:db8::1]:80.

   Some applications also need to specify IPv6 prefixes and lengths:
   The prefix length should be inserted outside of the square brackets,
   if used; for example, [2001:db8::]/64 or 2001:db8::/64 and not
   [2001:db8::/64].  Note that prefix/length notation is syntactically
   indistinguishable from a legal URI; therefore, the prefix/length
   notation must not be used when it isn’t clear from the context that
   it’s used to specify the prefix and length and not, for example, a
   URI.

   In some specific cases, it may be necessary to give a zone identifier
   as part of the address; for example, fe80::1%eth0.  In general,
   applications should not need to parse these identifiers.

   The IP address parsers should support enclosing the IPv6 address in
   brackets, even when the address is not used in conjunction with a
   port number.  Requiring that the user always give a literal IP
   address enclosed in brackets is not recommended.

   Note that some applications may also represent IPv6 address literals
   differently; for example, SMTP [RFC2821] uses [IPv6:2001:db8::1].

   Note that the use of address literals is strongly discouraged for
   general-purpose direct input to the applications.  Host names and DNS
   should be used instead.

5.2.  Transport Layer API

   Communication applications often include a transport module that
   establishes communications.  Usually this module manages everything
   related to communications and uses a transport-layer API, typically
   as a network library.  When an application is ported to IPv6, most
   changes should be made in this application transport module in order
   to be adapted to the new IPv6 API.

   In the general case, porting an existing application to IPv6 requires
   an examination of the following issues related to the API:

      -  Network Information Storage: IP address Data Structures
         The new structures must contain 128-bit IP addresses.  The use
         of generic address structures, which can store any address
         family, is recommended.

         Sometimes special addresses are hard-coded in the application
         source code.  Developers should pay attention to these in order
         to use the new address format.  Some of these special IP
         addresses are wildcard local, loopback, and broadcast.  IPv6
         does not have the broadcast addresses, so applications can use
         multicast instead.

      -  Address Conversion Functions
         The address conversion functions convert the binary address
         representation to the presentation format and vice versa.  The
         new conversion functions are specified to the IPv6 address
         format.

      -  Communication API Functions
         These functions manage communications.  Their signatures are
         defined based on a generic socket address structure.  The same
         functions are valid for IPv6; however, the IP address data
         structures used when calling these functions require the
         updates.

      -  Network Configuration Options
         These are used when different communication models are
         configured for Input/Output (I/O) operations
         (blocking/nonblocking, I/O multiplexing, etc.) and should be
         translated for IPv6.

5.3.  Name and Address Resolution

   From the application point of view, the name and address resolution
   is a system-independent process.  An application calls functions in a
   system library, the resolver, which is linked into the application
   when it is built.  However, these functions use IP address
   structures, that are protocol dependent and must be reviewed to
   support the new IPv6 resolution calls.

   With IPv6, there are two new basic resolution functions,
   getaddrinfo() and getnameinfo().  The first returns a list of all
   configured IP addresses for a hostname.  These queries can be
   constrained to one protocol family; for instance, only IPv4 or only

   IPv6 addresses.  However, it is recommended that all configured IP
   addresses be obtained to allow applications to work with every kind
   of node.  The second function returns the hostname associated to an
   IP address.

5.4.  Specific IP Dependencies

5.4.1.  IP Address Selection

   Unlike the IPv4 model, IPv6 promotes the configuration of multiple IP
   addresses per node, however, applications only use a
   destination/source pair for a communication.  Choosing the right IP
   source and destination addresses is a key factor that may determine
   the route of IP datagrams.

   Typically, nodes, not applications, automatically solve the source
   address selection.  A node will choose the source address for a
   communication following some rules of best choice, per [RFC3484], but
   will also allow applications to make changes in the ordering rules.

   When selecting the destination address, applications usually ask a
   resolver for the destination IP address.  The resolver returns a set
   of valid IP addresses from a hostname.  Unless applications have a
   specific reason to select any particular destination address, they
   should try each element in the list until the communication succeeds.

   In some cases, the application may need to specify its 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).  Note that if it
   is not yet known which protocol will be used for communication there
   may be an increase in complexity for IP version - independent
   applications that have to specify the source address (especially for
   client applications.  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.  Applications
   implementing ALF are often responsible for packetizing data into
   Application Data Units (ADUs).  The application problem with ALF
   arrives from the ADU size selection to obtain better performance.

   Applications using connectionless protocols (such as UDP) typically
   need application framing.  These applications have three choices: (1)
   to use packet sizes no larger than the IPv6 minimum Maximum
   Transmission Unit (MTU) of 1280 bytes [RFC2460], (2) to use any

   packet sizes, but to force IPv6 fragmentation/reassembly when
   necessary, or (3) to optimize the packet size and avoid unnecessary
   fragmentation/reassembly, and to 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
   Path MTU or whether IPv4 or IPv6 is being used (due to different
   header sizes, possible IPv6-in-IPv4 tunneling overhead, etc.).  These
   factors have to be taken into consideration when application framing
   is implemented.

5.4.3.  Storage of IP Addresses

   Some applications store IP addresses as remote peer information.  For
   instance, one of the most popular ways to register remote nodes in
   collaborative applications uses IP addresses as registry keys.

   Although the source code that stores IP addresses can be modified to
   IPv6 by following the previous basic porting recommendations,
   applications should not store IP addresses for the following reasons:

      -  IP addresses can change throughout 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, applications should store names such as FQDNs or other
   protocol-independent identities instead of addresses.  In this case
   applications are only bound to specific addresses at run time, or for
   the duration of a cache lifetime.  Other types of applications, such
   as 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

   There is an additional problem in porting multicast applications.
   When multicast facilities are used some changes must be carried out
   to support IPv6.  First, applications must change the IPv4 multicast
   addresses to IPv6 ones, and second, the socket configuration options
   must be changed.

   All IPv6 multicast addresses encode scope; the scope was only
   implicit in IPv4 (with multicast groups in 239/8).  Also, although a
   large number of application-specific multicast addresses have been
   assigned with IPv4, this has been (luckily enough) avoided with IPv6.
   So there are no direct equivalents for all the multicast addresses.
   For link-local multicast, it’s possible to pick almost anything
   within the link-local scope.  The global groups could use unicast
   prefix - based addresses [RFC3306].  All in all, this may force the
   application developers to write more protocol-dependent code.

   Another problem is that IPv6 multicast does not yet have a
   standardized mechanism for traditional Any Source Multicast for
   Interdomain multicast.  The models for Any Source Multicast (ASM) or
   Source-Specific Multicast (SSM) are generally similar between IPv4
   and IPv6, but it is possible that PIM-SSM will become more widely
   deployed in IPv6 due to its simpler architecture.

   It might be beneficial to port the applications to use SSM semantics,
   requiring off-band source discovery mechanisms and a different API
   [RFC3678].  Inter-domain ASM service is available only through a
   method embedding the Rendezvous Point address in the multicast
   address [Embed-RP].

   Another generic problem with multiparty conferencing applications,
   similar to the issues with peer-to-peer applications, is that all
   users of the session must use the same protocol version (IPv4 or
   IPv6), or some form of proxy or translator (e.g., [MUL-GW]).

6.  Developing IP Version - Independent Applications

   As stated, dual applications working with both IPv4 and IPv6 are
   recommended.  These applications should avoid IP dependencies in the
   source code.  However, if IP dependencies are required, one of the
   better solutions would be to build a communication library that
   provides an IP version -  independent API to applications and that
   hides all dependencies.

   To develop IP version - independent applications, the following
   guidelines should be considered.

6.1.  IP Version - Independent Structures

   All memory structures and APIs should be IP version-independent.  One
   should avoid structs in_addr, in6_addr, sockaddr_in, and
   sockaddr_in6.

   Suppose a network address is passed to some function, foo().  If one
   uses struct in_addr or struct in6_addr, results an extra parameter to
   indicate address family, as below:

      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 having to consider each scenario
   from both perspectives independently, which is difficult to maintain.
   So we should use struct sockaddr_storage, as below:

      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()
   hide the gory details of name-to-address and address-to-name
   translations.  They implement functionalities of the following
   functions:

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

   They also obsolete the functionality of gethostbyname2(), defined in
   [RFC2133].

   The new variants can perform hostname/address and service name/port
   lookups, though the features can be turned off, if desired.
   Getaddrinfo() can return multiple addresses, as below:

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

   In this example, if IPv6 is preferred, getaddrinfo first returns ::1;
   then both 127.0.0.1 and 127.0.0.2 are in a random order.

   Getaddrinfo() and getnameinfo() can query hostname and service
   name/port at once.

   Hardcoding AF-dependent knowledge is not preferred in the program.
   Constructs such as that below should be avoided:

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

   Instead, we should use the ai_addrlen member of the addrinfo
   structure, as returned by getaddrinfo().

   The gethostbyname(), gethostbyaddr(), getservbyname(), and
   getservbyport() are mainly used to get server and client sockets.  In
   the following sections, we will see simple examples creating these
   sockets by using the new IPv6 resolution functions.

6.2.1.  Example of Overly Simplistic TCP Server Application

   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

   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 follows:

      /*
       * 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;
------分隔线----------------------------
顶一下
(0)
0%
踩一下
(0)
0%
------分隔线----------------------------
最新评论 查看所有评论
发表评论 查看所有评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 密码: 验证码:
推荐内容