NTT Information Sharing Platform Laboratories
Introduction
Through the past five articles of this series, you have learned how to create a basic program using TCP. This time, I will introduce an API, which I did not cover in previous articles, that will allow you to obtain detailed information about the network adapter (interface). One example of adapter information would be the IPv6 address assigned to it. Also, depending on the program you create, your program will probably need to obtain information about the kind of adapters that are installed and about which IPv6 address is assigned to each adapter. The API that I will introduce this time will enable you to obtain detailed information about the adapter. This detailed information includes not only the IPv6 address, but also other information such as the IPv4 address, MAC address, MTU value, and the adapter’s up/down status.
IP Helper API
Outline
The IP Helper API is a set of utility APIs that contains functions that assist the WinSock API. The adapter information that I mentioned above cannot be obtained using only WinSock functions. This package also provides routing table handling, DNS query functions, and ICMPv4/ICMPv6 functions that are normally handled using the RAW socket. The function that I will explain is one of the functions for obtaining adapter information, the “GetAdaptersAddresses()” function.
Header and library for IP Helper APIAs you can see below, you include the header file “iphlpapi.h” in the source code of the program that uses the IP Helper API.
#include ‹winsock2.h›
#include ‹ws2tcpip.h›
#include ‹iphlpapi.h› ←-- Header file necessary for the IP Helper API
.
.
|
|
C:\>cl v6programm.c ws2_32.lib iphlpapi.lib ←-- Import library for the IP Helper API |
|
DWORD WINAPI GetAdaptersAddresses( ULONG Family, DWORD Flags, PVOID Reserved, PIP_ADAPTER_ADDRESSES pAdapterAddresses, PULONG pOutBufLen ); |
For the third argument, Reserved, always specify NULL. The fifth argument is the buffer size needed to store adapter information. Depending on the structure of the adapter and address information, the buffer space needed varies considerably. Because of that, it is hard for a programmer to guess how much buffer space is needed in advance. So, if you specify NULL in the fourth argument and call the GetAdaptersAddresses() function, it will store the buffer size needed to store the information in the pOutBufLen variable. The function assumes that you will allocate a buffer of that size, then call the GetAdaptersAddresses() function again, specifying the buffer you allocated, where it will store the adapter information, as the fourth argument. Since the pAdapterAddresses data structure is an IP_ADAPTER_ADDRESSES structure, we will look at its members in detail in the next section. Also, the return values of the GetAdaptersAddresses() function are shown in table 2.
IP_ADAPTER_ADDRESSES structure The IP_ADAPTER_ADDRESSES structure is defined in the header file “iptypes.h”. When the header file “iphlpapi.h” is included, this header is also automatically included, so the programmer does not have to explicitly include it. |
typedef struct _IP_ADAPTER_ADDRESSES {
union {
ULONGLONG Alignment;
struct {
ULONG Length;
DWORD IfIndex;
};
};
struct _IP_ADAPTER_ADDRESSES* Next;
PCHAR AdapterName;
PIP_ADAPTER_UNICAST_ADDRESS FirstUnicastAddress;
PIP_ADAPTER_ANYCAST_ADDRESS FirstAnycastAddress;
PIP_ADAPTER_MULTICAST_ADDRESS FirstMulticastAddress;
PIP_ADAPTER_DNS_SERVER_ADDRESS FirstDnsServerAddress;
PWCHAR DnsSuffix;
PWCHAR Description;
PWCHAR FriendlyName;
BYTE PhysicalAddress[MAX_ADAPTER_ADDRESS_LENGTH];
DWORD PhysicalAddressLength;
DWORD Flags;
DWORD Mtu;
DWORD IfType;
IF_OPER_STATUS OperStatus;
DWORD Ipv6IfIndex;
DWORD ZoneIndices[16];
PIP_ADAPTER_PREFIX FirstPrefix;
} IP_ADAPTER_ADDRESSES, *PIP_ADAPTER_ADDRESSES; |
The AdapterName member, which stores the adapter name |
PCHAR AdapterName; |
|
"{F1CA1BF8-B3BF-1FEE-99DB-FEA9C9B57B9CC}" |
The FriendlyName member, which stores the human-readable adapter name, and the Description member, which stores the description |
PWCHAR FriendlyName;
PWCHAR Description; |
|
FriendlyName: “Local Area Connection” Description: "Intel(R) PRO/1000 MT Mobile Connection – Packet Scheduler Miniport |
Note that when GAA_FLAG_SKIP_FRIENDLY_NAME is specified in the second argument of the GetAdaptersAddresses() function, Flags, this member is not returned. FirstUnicastAddress member, which stores the list of unicast addresses |
PIP_ADAPTER_UNICAST_ADDRESS FirstUnicastAddress; |
Definition of the IP_ADAPTER_UNICAST_ADDRESS structure The IP_ADAPTER_UNICAST_ADDRESS structure is defined as follows: |
typedef struct _IP_ADAPTER_UNICAST_ADDRESS {
union {
struct {
ULONG Length;
DWORD Flags;
};
};
struct _IP_ADAPTER_UNICAST_ADDRESS* Next;
SOCKET_ADDRESS Address;
IP_PREFIX_ORIGIN PrefixOrigin;
IP_SUFFIX_ORIGIN SuffixOrigin;
IP_DAD_STATE DadState;
ULONG ValidLifetime;
ULONG PreferredLifetime;
ULONG LeaseLifetime;
} IP_ADAPTER_UNICAST_ADDRESS, *PIP_ADAPTER_UNICAST_ADDRESS; |
The Address member, which stores the IP address The Address member is a SOCKET_ADDRESS structure, and the IP address of the socket address can be obtained via the lpSockaddr variable. Along with the socket address, the iSockaddrLength variable can be used to obtain the size of the socket address. |
typedef struct _SOCKET_ADDRESS {
LPSOCKADDR lpSockaddr;
INT iSockaddrLength;
} SOCKET_ADDRESS, *PSOCKET_ADDRESS; |
The PrefixOrigin and SuffixOrigin members, which are related to address types The PrefixOrigin and SuffixOrigin variables show the origins of the prefix (network) part and host part of the address. It can determine how the address was created; it can determine if it was created using DHCP, if it was configured using router advertisement, if it is an anonymous address, if it was setup manually or not, etc. In the header file “iptypes.h”, the IP_PREFIX_ORIGIN and IP_SUFFIX_ORIGIN types are defined by the enum as shown below. |
typedef enum {
IpPrefixOriginOther = 0,
IpPrefixOriginManual,
IpPrefixOriginWellKnown,
IpPrefixOriginDhcp,
IpPrefixOriginRouterAdvertisement,
} IP_PREFIX_ORIGIN;
typedef enum {
IpSuffixOriginOther = 0,
IpSuffixOriginManual,
IpSuffixOriginWellKnown,
IpSuffixOriginDhcp,
IpSuffixOriginLinkLayerAddress,
IpSuffixOriginRandom,
} IP_SUFFIX_ORIGIN; |
The ValidLifetime, PreferredLifetime and LeaseLifetime members, which show an address’ lifetime For addresses that are set to expire at a certain time, the length of their life span is set in three ULONG members. All values are in seconds (sec).
DadState, which stores DAD (Duplicated Address Detection) status This member stores the status of the functionality that detects duplicate IPv6 addresses. As for IPv4 addresses, since there is no DAD functionality, DadState member values have no meaning. In the header file “iptypes.h”, the enum defines five statuses. |
typedef enum {
IpDadStateInvalid = 0,
IpDadStateTentative, // Temporary use
IpDadStateDuplicate, // Duplication detected
IpDadStateDeprecated, // Expired
IpDadStatePreferred, // Valid IPv6 address
} IP_DAD_STATE; |
IP_ADAPTER_ANYCAST_ADDRESS structure is the same as the FirstUnicastAddress member that stores unicast addresses in that it creates a list and stores multiple addresses. However, since the life span for anycast and multicast addresses cannot be set on the protocol stack, members are significantly simplified and only address information is stored for these structures. |
typedef struct _IP_ADAPTER_ANYCAST_ADDRESS {
union {
ULONGLONG Alignment;
struct {
ULONG Length;
DWORD Flags;
};
};
struct _IP_ADAPTER_ANYCAST_ADDRESS *Next;
SOCKET_ADDRESS Address;
} IP_ADAPTER_ANYCAST_ADDRESS, *PIP_ADAPTER_ANYCAST_ADDRESS;
typedef struct _IP_ADAPTER_MULTICAST_ADDRESS {
union {
ULONGLONG Alignment;
struct {
ULONG Length;
DWORD Flags;
};
};
struct _IP_ADAPTER_MULTICAST_ADDRESS *Next;
SOCKET_ADDRESS Address;
} IP_ADAPTER_MULTICAST_ADDRESS, *PIP_ADAPTER_MULTICAST_ADDRESS; |
DNS information includes the DNS server’s IP address and the domain name. These are set in the FirstDnsServerAddress variable, which is an IP_ADAPTER_DNS_SERVER_ADDRESS structure, and the DnsSuffix variable (PWCHAR type). As for the format of the former, when multiple addresses are stored, an IP_ADAPTER_DNS_SERVER_ADDRESS structure list is created, just like with anycast and multicast addresses. The structure contents are also the same. |
typedef struct _IP_ADAPTER_DNS_SERVER_ADDRESS {
union {
ULONGLONG Alignment;
struct {
ULONG Length;
DWORD Reserved;
};
};
struct _IP_ADAPTER_DNS_SERVER_ADDRESS *Next;
SOCKET_ADDRESS Address;
} IP_ADAPTER_DNS_SERVER_ADDRESS, *PIP_ADAPTER_DNS_SERVER_ADDRESS; |
The IfType member, which shows the adapter type This variable shows the adapter’s media type. Types include Ethernet, Tunnel Adapter, Dial-up Adapter, Loopback Adapter, etc. The specifics are defined in the header file “ipifcons.h” and each starts with IF_TYPE*. The primary defines are the numbers shown below. |
#define IF_TYPE_ETHERNET_CSMACD 6 #define IF_TYPE_PPP 23 #define IF_TYPE_SOFTWARE_LOOPBACK 24 #define IF_TYPE_TUNNEL 131 // Encapsulation interface |
|
BYTE PhysicalAddress[MAX_ADAPTER_ADDRESS_LENGTH]; DWORD PhysicalAddressLength; |
The Mtu member, which stores the adapter’s MTU value This member stores the MTU value for the adapter. For Ethernet, the Mtu variable value is typically 1500. If the MTU value is changed by the user, that value is stored. The OperStatus member, which stores the adapter’s status The OperStatus member is an IF_OPER_STATUS variable, and it shows the adapter’s status such as up/down. The IF_OPER_STATUS type variables are defined by the enum shown below. |
typedef enum {
IfOperStatusUp = 1, // Adapter is up
IfOperStatusDown, // Adapter is down
IfOperStatusTesting, // Adapter is currently checking the link
IfOperStatusUnknown, // Adapter’s status is unknown
IfOperStatusDormant, // Adapter is dormant
IfOperStatusNotPresent, // Adapter does not exist
IfOperStatusLowerLayerDown // Link Layer and below that are down
} IF_OPER_STATUS; |
The Ipv6IfIndex member is valid only for IPv6. It is the number that shows adapter (interface) index. For example, when describing the link local address, the adapter (interface) is specified using “%”, as shown below. fe80::1%6 The number specified here matches the value of Ipv6ifIndex. The Flags member, which shows the adapter’s attributes This member stores the target adapter’s attributes. The possible values for the Flags member are any combination of the values shown in Table 3. Table 3: The adapter attributes returned in the Flags member
The ZoneIndices member, which stores zone information |
DWORD ZoneIndices[16]; |
|
typedef enum
{
ScopeLevelInterface = 1,
ScopeLevelLink = 2,
ScopeLevelSubnet = 3,
ScopeLevelAdmin = 4,
ScopeLevelSite = 5,
ScopeLevelOrganization = 8,
ScopeLevelGlobal = 14
} SCOPE_LEVEL; |
|
ZoneIndices[ScopeLevelSite] |
Figure 1: Example of netsh interface ipv6 show interface output for “Local Area Connection” |
|
|
The FirstPrefix member, which stores the adapter’s prefix This member stores the adapter’s prefix information. In order to obtain this member information, you need to specify GAA_FLAG_INCLUDE_PREFIX in the second argument, Flags, in advance when calling the GetAdaptersAddresses() function. If this flag is not specified, the FirstPrefix member is set to NULL. The information stored in the FirstPrefix member is the adapter’s prefix (the last 64 bits are zeroed out). The difference from the FirstUnicastAddress member is that the FirstUnicastAddress member stores unicast addresses. For example, when the following two IPv6 unicast addresses have the same adapter prefix, fe80::1 fe80::2012:34ff:fe56:789a FirstUnicastAddress creates a list of two addresses; however, the FirstPrefix member creates only one element with the prefix fe80::/64. For IPv4 addresses, a network address that has the host part zeroed out can be also obtained; however, the member for obtaining the netmask is missing. Note that if you use the old GetAdapterInfo()API (see end note 3), it is possible to obtain complete information on IPv4 addresses. [Continues in Part 2] End Notes 1. “other stateful configuration” is a mechanism that creates an IPv6 address based on the prefix information option included in the RA and obtains other information such as DNS in a stateful way, e.g. DHCPv6, when an RA that contains a specific flag called the O flag is received. The definition of the O flag embedded in RA and how to use it are provided in RFC2461 and draft-ietf-ipv6-ra-mo-flags-01.txt. 2. It has been already decided that the use of site local addresses will be discontinued, so you should not start using it now (RFC3879). On Windows XP SP2, the setup items were left in since it is still implemented. 3. The GetAdaptersInfo() function is also an API for obtaining adapter information. However, it obtains IPv4 address information only. That is why the GetAdaptersAddresses() function, which supports IPv6, was created.
|


