Appendix B -- Windows Sockets Changes for IPv6

Appendix B

Windows Sockets Changes for IPv6

This appendix includes information on changes that have been made to the Windows Sockets API to support IPv6 applications. The following topics are discussed:

  • Added constants
  • Address data structures
  • Wildcard addresses
  • Core sockets functions
  • Name-to-address translation
  • Address-to-name translation
  • Address conversion functions
  • Socket options
  • New macros
  • Unsupported APIs

Examples of how and when to utilize these changes in an application are discussed. Additional details can be found on the Microsoft Developer Network web site at http://msdn.microsoft.com.

Added Constants

A new address family name for IPv6 is required so that the address structure can be correctly identified and parsed. Similarly, a new protocol family name (with the same value as the address family name) must be defined so that a socket is created using the appropriate protocol. The address family name and protocol family name constants for IPv6 are:

  • AF_INET6
  • PF_INET6

Address Data Structures

The term sockets defines a protocol-specific data structure that holds elements of a socket address. For IPv4, this structure is sockaddr_in. Sockets also defines a protocol-independent structure (sockaddr) for the protocol-specific structures to be cast into. The identifying field (the address family) in the protocol-specific structure overlays the family field in the generic structure. Because IPv6 addresses are different than IPv4 addresses, a new protocol-specific structure for IPv6 is required.

The data structures sockaddr and sockaddr_in are the same size which could lead one into making incorrect assumptions about the size of their related address structures. The IPv6 address structure, sockaddr_in6, is larger by necessity. For example, the sockaddr structure cannot be used to allocate storage for sockaddr_in6. This is discussed in more detail below.

in6_addr

 struct in6_addr {     union {         u_char Byte[16];         ushort Word[8];         } u; }; 

The socket address structure contains information above and beyond the address for the socket. One portion of the structure, however, must be the address. In IPv4's address structure, this address is contained in in_addr. A larger structure, in6_addr, has been defined to hold the larger IPv6 address.

sockaddr_in6

In addition to the larger address size, there are other members that must be represented in the socket address structure for IPv6. Although the IPv4 sockaddr_in structure has unused space, it is not enough to contain this additional information. The sockaddr_in6 structure is used to contain an IPv6 address.

 struct sockaddr_in6 {     sa_family_t     sin6_family;         in_port_t       sin6_port;           uint32_t        sin6_flowinfo;       struct in6_addr sin6_addr;           uint32_t        sin6_scope_id;   }; 

In addition to the family, port, and address information, this structure contains sin6_flowinfo and sin6_scope_id members. sin6_flowinfo is intended to contain the traffic class and flow label from and for the IPv6 header. sin6_flowinfo is not supported in Windows XP and the Windows .NET Server 2003 family. sin6_scope_id contains the scope ID, which is used to identify a set of interfaces that are appropriate for the address carried in the address field.

sockaddr_storage

As mentioned earlier, sockaddr and sockaddr_in6 have different sizes. Because of this, struct sockaddr cannot be used to allocate storage and then be cast to a sockaddr_in6 pointer. If static allocation of storage for sockaddr_in6 (or even sockaddr_in) structures is needed, struct sockaddr_storage should be used. Here is an example:

 struct sockaddr_storage newaddr; ... msgsock = accept(listen_socket,(struct sockaddr*)&newaddr, &newaddrlen); 

In addition to being large enough to accommodate all known protocol-specific socket address structures (including sockaddr_in6), sockaddr_storage is aligned at an appropriate boundary so that protocol-specific socket address data-structure pointers can be cast to it, enabling it to access fields without experiencing alignment problems.

Wildcard Addresses

To allow the protocol implementation to choose the source address for a connection or datagram with IPv4, a constant of INADDR_ANY (the wildcard address) is used as the address in the bind() call.

The IPv6 address type (in6_addr) is a structure. A constant cannot be used in an assignment for this variable, but can be used to initialize the structure. Thus, we end up with two possible ways to provide the wildcard address.

The global variable, in6addr_any, can be used in an assignment. For example:

 sin6.sin6_addr = in6addr_any;  

Or the constant, IN6ADDR_ANY_INIT, can be used to initialize the address structure (at declaration time only). For example:

 struct in6_addr anyaddr = IN6ADDR_ANY_INIT; 

in6addr_loopback and IN6ADDR_LOOPBACK_INIT

Similarly, the INADDR_LOOPBACK constant is used in IPv4 connect(), send(), and sendmsg() calls to communicate with services that reside on the local node. For IPv6 loopback, a global variable (in6addr_loopback) is used for assignment and a constant (IN6ADDR_LOOPBACK_INIT) is used for initialization at declaration time.

The IPv4 INADDR_XXX constants were defined in host-byte order. The IPv6 equivalents are defined in network-byte order.

Core Sockets Functions

An address is passed in core Sockets functions as an opaque address pointer and length. Because of this, changes need not be made to these core Sockets functions for IPv6. The application developer needs simply to supply the appropriate IPv6 address structure and family constants.

Sockets functions that pass addresses are the following:

  • bind()
  • connect()
  • sendmsg()
  • sendto()

Sockets functions that return addresses are the following:

  • accept()
  • recvfrom()
  • recvmsg()
  • getpeername()
  • getsockname()

Name-to-Address Translation

To resolve a host name to one or more IP addresses in IPv4, the application might use gethostbyname(). This API does not allow the caller to specify anything about the types of addresses wanted and the structure contains only enough space to store an IPv4 address. To address these issues, a new API named getaddrinfo() is introduced with IPv6. This API is protocol-independent and can be used for both IPv4 and IPv6 name-to-address resolutions. The return from this call is in the form of addrinfo structures that can subsequently be used to both open and use a socket.

The function prototype for getaddrinfo() is the following:

 int getaddrinfo(     IN const char FAR *nodename,     IN const char FAR *servname,     IN const struct addrinfo FAR *hints,     OUT struct addrinfo FAR *FAR *res     ); struct addrinfo {     int ai_flags;     int ai_family;     int ai_socktype;     int ai_protocol;     size_t ai_addrlen;      char *ai_canonname;     struct sockaddr *ai_addr; struct addrinfo *ai_next; }; 

As arguments, either a node name or service name (or both) are provided. The node name can (optionally) be a numeric address string and the service name can (optionally) be a decimal port number. An addrinfo structure can be provided (optionally) to provide hints for the type of socket that the caller supports. The addrinfo structure pointed to by this hints parameter can specify a preferred socket type, family and protocol, and the following flags:

  • AI_PASSIVE

    This flag indicates that the caller plans to use the returned address structure in a bind() call when set, or a connect() call when not set. Setting the node name to NULL has additional meaning depending on this flag. If the node name in the hints is NULL, and this flag is set, the returned addresses will be wildcard addresses. If the node name in the hints is NULL, and this flag is not set, the returned addresses will be loopback addresses.

  • AI_CANONNAME

    The AI_CANONNAME flag indicates (when set) that the first addrinfo structure returned should contain a null-terminated string that contains the canonical name of the node name in the ai_canonname member.

  • AI_NUMERICHOST

    This flag indicates that the nodename in the call is a numeric address string.

  • AI_V4MAPPED

    If the address family specified is AF_INET6, the caller will accept IPv4-mapped IPv6 addresses. The IPv6 protocol for Windows XP and the Windows .NET Server 2003 family does not support the use of IPv4-mapped addresses.

  • AI_ALL

    Used with the AI_V4MAPPED flag to indicate that the caller would like all addresses, both true IPv6 addresses and IPv4-mapped IPv6 addresses. The address family specified must be AF_INET6. The IPv6 protocol for Windows XP and the Windows .NET Server 2003 family does not support the use of this flag.

  • AI_ADDRCONFIG

    The AI_ADDRCONFIG flag controls whether the query requests AAAA DNS records or A records, based on the locally configured source addresses. AAAA records will be queried only if the node has at least one IPv6 source address. A records will be queried only if the node has at least one IPv4 source address.

A pointer to a linked list of addrinfo structures is returned. The order of the addresses is in decreasing order of desirability.

The addrinfo structures (and structures contained as members within those structures) are dynamically allocated and must be released by calling freeaddrinfo() with a pointer to the linked list of addrinfo structures.

The function prototype for freeaddrinfo() is the following:

 void freeaddrinfo(   struct addrinfo FAR *ai ); 

Address-to-Name Translation

A reverse lookup can be performed by using another new Sockets function, getnameinfo(). To use this API, a socket address structure is provided. The function prototype for getnameinfo() is the following:

 int getnameinfo(     IN const struct sockaddr FAR *sa,     IN socklen_t salen,     OUT char FAR *host,     IN size_t hostlen,     OUT char FAR *serv,     IN size_t servlen,     IN int flags     ); 

It contains the address and port in question. This can be either an IPv4 or IPv6 socket address structure because the length is also provided.

Additionally, buffers are provided to receive the node name and service name associated with that address, and the flags field can be used to change the default behavior of the API. The lengths of these buffers are provided in the call, and constants are defined (NI_MAXHOST, NI_MAXSERV) to aid the application in allocating buffers of the maximum size required.

The flags adjust the behavior as follows:

  • NI_NOFQDN

    Setting the NI_NOFQDN flag results in returning only the node name (not the fully qualified domain name, or FQDN) for local hosts.

  • NI_NUMERICHOST

    Setting this flag results in returning the numeric form of the host's address instead of its name.

  • NI_NAMEREQD

    Setting the NI_NAMEREQD flag results in returning an error if the name cannot be located.

  • NI_NUMERICSERV

    Setting NI_NUMERICSERV results in returning the numeric port number instead of the service name.

  • NI_DGRAM

    Setting this flag specifies that the service is a datagram service, causing a search for a UDP service (instead of a TCP service).

Using getaddrinfo

Here is an example of a client application using getaddrinfo() to connect to a specific server:

 {/* Client Side...*/} if (getaddrinfo(service_name, port, NULL, &ai) != 0) {/* Error Handling */}      conn_socket = socket(ai->ai_family, ai->ai_socktype,ai->ai_protocol);  if (conn_socket <0 ) {/* Error Handling */} if (connect(conn_socket,ai->ai_addr,ai->ai_addrlen) == SOCKET_ERROR)  {/* Error Handling */} freeaddrinfo(ai); 

For an example of an application that checks each address returned, see the white paper titled "Adding IPv6 Capability to Windows Sockets Applications" in the \White_Papers folder on the companion CD-ROM.

Here is an example of the corresponding server application using getaddrinfo() to resolve the address information for the socket creation and bind calls:

 {/* Server Side... */} hints.ai_family = AF_INET6; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE;   retval = getaddrinfo(interface, port, &hints, &ai); if (retval != 0) {/* Error Handling */} listen_socket = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);  if (listen_socket == INVALID_SOCKET){/* Error Handling */} if (bind(listen_socket,ai->ai_addr,ai->ai_addrlen )== SOCKET_ERROR)  {/* Error Handling */} freeaddrinfo(ai); 

The interface parameter in this call could be NULL, or could be set to a numeric string.

Address Conversion Functions

The inet_addr() and inet_ntoa() functions are provided to convert IPv4 addresses between binary and text formats. The IETF defined the similar functions, inet_pton() and inet_ntop(), to convert both IPv4 and IPv6 addresses. These functions contain an additional address family argument to make them protocol-independent.

Because getaddrinfo() and getnameinfo() provide the same functionality, the IETF is in the process of deprecating the inet_pton() and the inet_ntop() functions. As a result, the IPv6 protocol for Windows XP and the Windows .NET Server 2003 family does not support the inet_pton() and the inet_ntop() functions.

Socket Options

A new socket option level, IPPROTO_IPV6, has been defined for IPv6-specific socket options. Although an application can send multicast UDP packets by specifying a multicast address in sendto(), most of the new socket options currently defined for IPv6 are intended to adjust multicast behavior. New socket options are the following:

  • IPV6_MULTICAST_IF

    This option sets the default interface to use for outgoing multicast traffic to the interface indicated by the index specified in the argument (0 indicates that the system chooses the interface).

  • IPV6_MULTICAST_HOPS

    This option sets the hop limit for outgoing multicast packets based on the argument. Valid values are either 0 to 255 inclusive or -1 (to use the system default).

  • IPV6_MULTICAST_LOOP

    This option controls whether outgoing multicast packets addressed to a group, of which the interface is a member, is looped back.

For reception of multicast traffic, new options are defined to join and leave multicast groups. These options take an argument of an ipv6_mreq structure:

 struct ipv6_mreq {       struct in6_addr ipv6mr_multiaddr;       unsigned int ipv6mr_interface;     }; 

This structure contains the multicast address of the group to be joined or left, and an interface index to use for this join or leave.

New multicast socket options are:

  • IPV6_JOIN_GROUP

    This option is used to join the specified multicast group on the interface indicated (0 indicates that the system chooses the interface).

  • IPV6_LEAVE_GROUP

    The IPV6_LEAVE_GROUP option is used to leave the specified group on the interface indicated.

In addition, another socket option, IPV6_UNICAST_HOPS, is defined to control the hop limit for outgoing unicast packets.

New Macros

The additions to Windows Sockets that support IPv6 include the following set of macros to test addresses and determine whether they are special IPv6addresses:

  • IN6_IS_ADDR_UNSPECIFIED
  • IN6_IS_ADDR_LOOPBACK
  • IN6_IS_ADDR_MULTICAST
  • IN6_IS_ADDR_LINKLOCAL
  • IN6_IS_ADDR_SITELOCAL
  • IN6_IS_ADDR_V4MAPPED
  • IN6_IS_ADDR_V4COMPAT
  • IN6_IS_ADDR_MC_NODELOCAL
  • IN6_IS_ADDR_MC_LINKLOCAL
  • IN6_IS_ADDR_MC_SITELOCAL
  • IN6_IS_ADDR_MC_ORGLOCAL
  • IN6_IS_ADDR_MC_GLOBAL

The first seven macros return a true value if the address is of the specified type. The last five test the scope of a multicast address, returning a true value if the address is a multicast address of the specified scope and a false value if the address is either not a multicast address or is not of the specified scope.

The IN6_IS_ADDR_V4MAPPED macro can be use to determine whether the destination address for a socket is an IPv4 node. IPv4-mapped addresses are not supported by the IPv6 protocol for Windows XP and the Windows .NET Server 2003 family.

Unsupported APIs

The following are APIs that are currently specified in RFC 2553 or RFC 2292 that the IPv6 protocol for Windows XP and the Windows .NET Server 2003 family does not support:

  • The APIs getipnodebyname(), getipnodebyaddr(), inet_pton(), and inet_ntop() are being deprecated by the IETF. They are redundant, as the functionality they provide is available with getaddrinfo() and getnameinfo().
  • There is a set of name/interface index conversion functions that are not supported, but might be supported in future versions of Windows.
  • The IETF is in the process of revising the advanced API specification (RFC 2292). The revised RFC will include a discussion of programming raw sockets and access to various options for IPv6 packets.

References

RFC 2553 - "Basic Socket Interface Extensions for IPv6"

RFC 2292 - "Advanced Sockets API for IPv6"



Understanding IPv6
Understanding Ipv6
ISBN: 0735612455
EAN: 2147483647
Year: 2005
Pages: 124
Authors: Joseph Davies

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net