IPv6 Programming on Windows Tutorial Part 6

IPv6 Programming on Windows Tutorial Part 6

tags:
Junya Kato
NTT Information Sharing Platform Laboratories

GetAdaptersAddresses.exe, a sample program that displays the adapter’s status – its operation and source code

As a sample program that uses the GetAdaptersAddresses() function, I created the GetAdaptersAddresses.exe command.  At the end of the article, I inserted the listing, “GetAdaptersAddresses.exe source code” and I also made a pre-compiled binary available.  So, please try running it in your environment and check the output.  This command does not need any arguments; it only needs to be run on the command prompt.  Since I only converted each member of the IP_ADAPTER_ADDRESSES structure into a human-readable character string and displayed it on the screen this time, a detailed explanation of the source code is omitted.  I put together detailed comments here so please read it as reference.  Example output for GetAdaptersAddresses.exe is also presented in the next section.

Example output for an IPv6 loopback adapter

Figure 2 shows the output displayed for the IPv6 loopback adapter.  Output is displayed for each adapter, indented to show the hierarchy of items.  For hosts that have multiple adapters installed, including virtual adapters, the structure shown in Figure 2 is displayed repeatedly for each of the adapters.  We will take a look at the items shown for the IPv6 loopback adapter one by one, starting from the top.

Figure 2: Example output for an IPv6 loopback adapter

01:Adapter Name : Loopback Pseudo-Interface
02:  Adapter UID = {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}
03:  Description : Loopback Pseudo-Interface
04:  Type : Loopback	
05:  Operational Status : Up
06:  Unicast Address#0
07:    Family=IPv6, Addr=::1
08:    ValidLifetime=infinite, PreferredLifetime=infinite, LeaseLifetime=infinite
09:    prefix origin : WellKnown
10:    suffix origin : WellKnown
11:    DAD state : Preferred
12:  Unicast Address#1
13:    Family=IPv6, Addr=fe80::1%1
14:    ValidLifetime=infinite, PreferredLifetime=infinite, LeaseLifetime=infinite
15:    prefix origin : WellKnown
16:    suffix origin : LinkLayerAddress
17:    DAD state : Preferred
18:  MTU : 1500
19:  IPv6 Interface Index : 1
20:  Flags: DDNS_ENABLED
21:  Zone Info: if 1, link 1, subnet 5, admin 5, site 5, org 1, global 0
22:  Prefix#0
23:    Family=IPv6, Addr=fe80::/64
Line 01:

Output of the FriendlyName member
Displays human-readable adapter name.  Adapter information below this line is displayed indented by two spaces.

Line 02:

Output of the AdapterName member
Displays adapter name in UID format.

Line 03:

Output of the Description member
Outputs the description of the adapter.

Line 04:

Output of the IfType member
Displays the media type (in this case, Loopback)

Line 05:

Output of the OperStatus member
Displays the status of the adapter, such as UP/Down.

Lines 06-17:

Display of the FirstUnicastAddress member
Displays the two unicast addresses given to the adapter in order.  Each piece of information on the unicast address is displayed indented by two spaces.

Line 07:

Display of FirstUnicastAddress->Address
Displays that the first unicast IPv6 address is ::1.

Line 08:

Display of FirstUnicastAddress->ValidLifetime and PreferredLifetime
Address life span is infinite (because it’s a loopback address).

Lines 09-10:

Display of FirstUnicastAddress->PrefixOrigin and SuffixOrigin
Displays address types (Wellknown because it’s a loopback address).

Line 11:

Display of FirstUnicastAddress->DadState
Displays DAD status.  Indicates that it is a valid IPv6 address.

Lines 12-17: Same for the second unicast.
Line 18:

Output of the Mtu member
Outputs that the adapter’s MTU value is 1500.

Line 19:

Output of the Ipv6IfIndex member
Displays adapter (interface) index.

Line 20:

Output of the Flags member
Displays that DynamicDNS is enabled.

Line 21:

Display of the ZoneIndices member
Zone number of the link local address scope (link) is 1.
Zone number of the site local address scope (site) is 5.
Zone number of the global address scope (global) is 0.
As for the other scopes, it is unknown how they are actually used within the OS.  The obtained values are displayed without modification.

Line 22:

Output of the FirstPrefix member
Displays link local address prefix fe80::/64.

Note that it does not have a physical address because it is a loopback address.  Also, since multicast and anycast addresses are not given to a loopback adapter, they are not displayed.  As for the Windows XP SP2 implementation, since separate loopback adapters are used for IPv6 and IPv4, the loopback address for IPv4 (127.0.0.1) is not displayed.

Example output for Local Area Connection (wired Ethernet adapter)

Figure 3 shows the output of the wired Ethernet adapter information.  Since the contents of the output are mostly the same as the loopback adapter, I will omit detailed explanations.

Figure 3: Example output for the Local Area Connection adapter

01:Adapter Name : Local Area Connection
02:  Adapter UID = {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}
03:  Description : Intel(R) PRO/1000 MT Mobile Connection - Packet scheduler miniport
04:  Type : Ethernet
05:  Operational Status : Up
06:  Unicast Address#0
07:    Family=IPv4, Addr=192.168.1.56
08:    ValidLifetime=259167, PreferredLifetime=259167, LeaseLifetime=259167
09:    prefix origin : Dhcp
10:    suffix origin : Dhcp
11:  Unicast Address#1
12:    Family=IPv6, Addr=2001:db8:ffff::432:c9a2:bdcc:4b1a
13:    ValidLifetime=604765, PreferredLifetime=86198, LeaseLifetime=infinite
14:    prefix origin : RouterAdvertisement
15:    suffix origin : Random
16:    DAD state : Preferred
17:  Unicast Address#2
18:    Family=IPv6, Addr=2001:db8:ffff:611::20d:60ff:fe11:7713
19:    ValidLifetime=2591997, PreferredLifetime=604797, LeaseLifetime=infinite
20:    prefix origin : RouterAdvertisement
21:    suffix origin : LinkLayerAddress
22:    DAD state : Preferred
23:  Unicast Address#3
24:    Family=IPv6, Addr=fe80::20d:60ff:fe11:7713%6
25:    ValidLifetime=infinite, PreferredLifetime=infinite, LeaseLifetime=infinite
26:    prefix origin : WellKnown
27:    suffix origin : LinkLayerAddress
28:    DAD state : Preferred
29:  Multicast Address#0
30:    Family=IPv4, Addr=224.0.0.1
31:  Multicast Address#1
32:    Family=IPv4, Addr=239.255.255.250
33:  Multicast Address#2
34:    Family=IPv6, Addr=ff01::1%6
35:  Multicast Address#3
36:    Family=IPv6, Addr=ff02::1%6
37:  Multicast Address#4
38:    Family=IPv6, Addr=ff02::1:ff11:7713%6
39:  Multicast Address#5
40:    Family=IPv6, Addr=ff02::1:ffcc:4b1a%6
41:  DNS Server Address#0
42:    Family=IPv6, Addr=fec0:0:0:ffff::1%1

From the output of lines 6 through 28, you can see that both IPv6 and IPv4 addresses are assigned to the Local Area Connection adapter.  There are two IPv6 addresses given; one is generated from RA and the adapter’s MAC address and the other is an anonymous address.  Also, since this adapter has a physical address, the MAC address is displayed in line 50.  Information on multicast addresses and DNS are displayed in lines 29 through 40; the rest is the same as the loopback adapter.

Downloading the GetAdaptersAddresses.exe source code and binary

I made the source code and compiled binary available for download.

Source code download: GetAdaptersAddresses.c
Pre-compiled binary download:GetAdapterAddresses.exe

Listing 1: GetAdaptersAddresses.exe source code

001:/*
002: * Program for obtaining adapter information using the GetAdaptersAddresses() function
003: *
004: * How to compile
005: *
006: * C:¥›cl GetAdaptersAddresses.c ws2_32.lib iphlpapi.lib
007: *
008: */
009:#include ‹stdio.h›
010:#include ‹stdlib.h›
011:#include ‹winsock2.h›
012:#include ‹ws2tcpip.h›
013:#include ‹iphlpapi.h› /* for IP Helper API */
014:#include ‹limits.h›
015:
016:/* Convert IP_PREFIX_ORIGIN enum value, which specifies */
017:/* the origin of the IP address prefix (network part), into a character string. */
018:const char *getString_IP_PREFIX_ORIGIN(IP_PREFIX_ORIGIN ipo)
019:{
020: const char *szOriginString[] = {
021: "Other",
022: "Manual",
023: "WellKnown",
024: "Dhcp",
025: "RouterAdvertisement"
026: };
027:
028: return szOriginString[ipo];
029:}
030:
031:
032:/* Convert IP_SUFFIX_ORIGIN enum value, which specifies */
033:/* the origin of the IP address interface ID (host part), into a character string. */
034:const char *getString_IP_SUFFIX_ORIGIN(IP_SUFFIX_ORIGIN iso)
035:{
036: const char *szOriginString[] = {
037: "Other",
038: "Manual",
039: "WellKnown",
040: "Dhcp",
041: "LinkLayerAddress",
042: "Random"
043: };
044:
045: return szOriginString[iso];
046:}
047:
048:
049:/* Show IP address DAD status. */
050:/* Convert IP_DAD_STATE enum value into a character string. */
051:const char *getString_IP_DAD_STATE(IP_DAD_STATE ids)
052:{
053: const char *szDADstate[] = {
054: "Invalid",
055: "Tentative",
056: "Duplicate",
057: "Deprecated",
058: "Preferred"
059: };
060:
061: return szDADstate[ids];
062:}
063:
064:/* Show adapter status. */
065:/* Convert IF_OPER_STATUS enum value into a character string. */
066:const char *getString_IF_OPER_STATUS(IF_OPER_STATUS ios)
067:{
068: const char *szOperationalStatus[] = {
069: "", /* According to the IF_OPER_STATUS enum definition, 0 is skipped. */
070: "Up",
071: "Down",
072: "Testing",
073: "Unknown",
074: "Dormant",
075: "NotPresent",
076: "LowerLayerDown"
077: };
078:
079: return szOperationalStatus[ios];
080:}
081:
082:
083:/* Show adapter type (media type). */
084:/* Convert value (dwIfType) into a character string. */
085:const char *getString_IfType(DWORD dwIfType)
086:{
087: switch(dwIfType) {
088: case IF_TYPE_ETHERNET_CSMACD: /* 6 */
089: return "Ethernet";
090: case IF_TYPE_SOFTWARE_LOOPBACK: /* 24 */
091: return "Loopback";
092: case IF_TYPE_TUNNEL: /* 131 */
093: return "Tunnel";
094: default:
095: return "Other Adapter Type";
096: }
097:}
098:
099:
100:/* Convert the ULONG value (lt), which specifies the life span, into a character string and write it to szBuf. */
101:/* When the life span value. lt, is equal to ULONG_MAX, return the character string “infinite”. */
102:/* When enough size is not allocated in szBuf */
103:/* it returns NULL. */
104:const char *getString_Lifetime(char *szBuf, size_t size, ULONG lt)
105:{
106: if (lt == ULONG_MAX) {
107: if (_snprintf(szBuf, size, "%s", "infinite") ‹ 0)
108: return NULL;
109: } else {
110: if (_snprintf(szBuf, size, "%u", lt) ‹ 0)
111: return NULL;
112: }
113:
114: return szBuf;
115:}
116:
117:
118:/* Convert the flag information that specifies adapter attributes into a character string. */
119:/* The names of the flags are output separated by commas. */
120:/* When enough size is not allocated in szBuf, it returns NULL. */
121:char *getString_AdapterFlags(char *szBuf, size_t size, DWORD dwFlags)
122:{
123: char *p = szBuf;
124: int len;
125: struct _FlagList {
126: DWORD Flag;
127: const char *szFlagName;
128: } FlagList[] = {
129: { IP_ADAPTER_DDNS_ENABLED, "DDNS_ENABLED" },
130: { IP_ADAPTER_REGISTER_ADAPTER_SUFFIX, "REGISTER_ADAPTER_SUFFIX" },
131: { IP_ADAPTER_DHCP_ENABLED, "DHCP_ENABLED" },
132: { IP_ADAPTER_RECEIVE_ONLY, "RECEIVE_ONLY" },
133: { IP_ADAPTER_NO_MULTICAST, "NO_MULTICAST" },
134: { IP_ADAPTER_IPV6_OTHER_STATEFUL_CONFIG, "OTHER_STATEFUL_CONFIG"}
135: };
136: int i;
137:
138: for (i = 0; i ‹ sizeof(FlagList) / sizeof(struct _FlagList); ++i) {
139: if (dwFlags & FlagList[i].Flag) {
140: if ((len = _snprintf(p, size, "%s", FlagList[i].szFlagName)) ‹ 0)
141: return NULL;
142: p+= len;
143: size -= len;
144:
145: break;
146: }
147: }
148:
149: for (i++; i ‹ sizeof(FlagList) / sizeof(struct _FlagList); ++i) {
150: if (dwFlags & FlagList[i].Flag) {
151: if ((len = _snprintf(p, size, ",%s", FlagList[i].szFlagName)) ‹ 0)
152: return NULL;
153: p+= len;
154: size -= len;
155: }
156: }
157:
158: return szBuf;
159:}
160:
161:
162:/* Convert SCOPE_LEVEL enum value, which specifies the scope, into a character string. */
163:const char *getString_SCOPE_LEVEL(SCOPE_LEVEL sl)
164:{
165: const char *szScopeLevel[] = {
166: "", /* According to the SCOPE_LEVEL enum definition, 0 is skipped. */
167: "Interface",
168: "Link",
169: "Subnet",
170: "Admin",
171: "Site",
172: "Origanization",
173: "Global"
174: };
175:
176: return szScopeLevel[sl];
177:}
178:
179:
180:int main(int argc, char *argv[])
181:{
182: WSADATA wsaData;
183: PIP_ADAPTER_ADDRESSES pAdapterAddresses, pAA;
184: DWORD dwRet, dwSize;
185:
186: /*
187: * Initialize WinSock
188: */
189: if (WSAStartup(MAKEWORD(2, 2), &wsaData)) {
190: fprintf(stderr, "cannot initilize WinSock¥n");
191: exit(1);
192: }
193:
194:
195: /*
196: * dwSize, which requests the buffer size necessary to store the return value, obtains that value.
197: * In order to obtain the prefix information in the FirstPrefix member,
198: * specify GAA_FLAG_INCLUDE_PREFIX in the second argument flag.
199: */
200: dwRet = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX,
201: NULL, NULL, &dwSize);
202: if (dwRet != ERROR_BUFFER_OVERFLOW) {
203: fprintf(stderr, "no enough buffer¥n");
204: exit(1);
205: }
206:
207:
208: /*
209: * Allocate a buffer of size dwSize in pAdapterAddresses.
210: */
211: pAdapterAddresses = (PIP_ADAPTER_ADDRESSES)malloc(dwSize);
212: if (pAdapterAddresses == NULL) {
213: fprintf(stderr, "no enough buffer¥n");
214: exit(1);
215: }
216:
217:
218: /*
219: * Call the GetAdaptersAddresses() function again and obtain the adapter information
220: * in pAdapterAddresses. In order to obtain prefix information in the FirstPrefix member,
221: * specify GAA_FLAG_INCLUDE_PREFIX in the second argument flag.
222: */
223: dwRet = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX,
224: NULL, pAdapterAddresses, &dwSize);
225: if (dwRet != ERROR_SUCCESS) {
226: fprintf(stderr, "GetAdaptersAddresses() failed¥n");
227: exit(1);
228: }
229:
230:
231: /*
232: * For each adapter, the variable pAA,
233: * which shows adapter information, is set to point to
234: * an IP_ADAPTER_ADDRESSES instance.
235: */
236: for (pAA = pAdapterAddresses; pAA; pAA = pAA-›Next) {
237: char szAdapterName[BUFSIZ];
238: char szAdapterDescription[BUFSIZ];
239: char szDnsSuffix[BUFSIZ];
240: int len;
241: PIP_ADAPTER_UNICAST_ADDRESS pUnicastAddress;
242: PIP_ADAPTER_ANYCAST_ADDRESS pAnycastAddress;
243: PIP_ADAPTER_MULTICAST_ADDRESS pMulticastAddress;
244: PIP_ADAPTER_DNS_SERVER_ADDRESS pDnsServerAddress;
245: char szFlagsString[BUFSIZ];
246: PIP_ADAPTER_PREFIX pIpAdapterPrefix;
247: int i;
248:
249:
250: /*
251: * Display the human-readable adapter name using the FriendlyName member.
252: */
253: /* Since FriendlyName is encoded in Unicode, */
254: /* convert it into multi-byte characters (Shift JIS). */
255: len = WideCharToMultiByte(CP_ACP, 0,
256: pAA-›FriendlyName,
257: wcslen(pAA-›FriendlyName),
258: szAdapterName, sizeof(szAdapterName),
259: NULL, NULL);
260: if (len == 0) {
261: fprintf(stderr, "cannot convert adapter name¥n");
262: exit(1);
263: }
264: szAdapterName[len] = '¥0';
265: printf("Adapter Name : %s¥n", szAdapterName);
266:
267:
268: /*
269: * * Display the adapter name (UID format) using the AdapterName member.
270: */
271: printf(" Adapter UID = %s¥n", pAA-›AdapterName);
272:
273:
274: /*
275: * Display the adapter description from the Description member.
276: */
277: /* Since Description is encoded in Unicode, */
278: /* convert it into multi-byte characters (Shift JIS). */
279: len = WideCharToMultiByte(CP_ACP, 0,
280: pAA-›Description,
281: wcslen(pAA-›Description),
282: szAdapterDescription,
283: sizeof(szAdapterDescription),
284: NULL, NULL);
285: if (len == 0) {
286: fprintf(stderr, "cannot convert adapter description¥n");
287: exit(1);
288: }
289: szAdapterDescription[len] = '¥0';
290: printf(" Description : %s¥n", szAdapterDescription);
291:
292:
293: /*
294: * Display the adapter’s media type using IfType member.
295: */
296: printf(" Type : %s¥n", getString_IfType(pAA-›IfType));
297:
298:
299: /*
300: * Display the adapter’s status using the OperStatus member.
301: */
302: printf(" Operational Status : %s¥n",
303: getString_IF_OPER_STATUS(pAA-›OperStatus));
304:
305:
306: /*
307: * Display the unicast address given to the adapter
308: * using the FirstUnicastAddress member.
309: */
310: for (i = 0, pUnicastAddress = pAA-›FirstUnicastAddress;
311: pUnicastAddress;
312: i++, pUnicastAddress = pUnicastAddress-›Next) {
313: char szAddress[NI_MAXHOST];
314: char szValidLifetime[BUFSIZ];
315: char szPreferredLifetime[BUFSIZ];
316: char szLeaseLifetime[BUFSIZ];
317:
318: /*
319: * Process for displaying unicast address
320: */
321: /* Convert the address stored in network format (binary) */
322: /* into a human-readable character string (presentation format). */
323: if (getnameinfo(pUnicastAddress-›Address.lpSockaddr,
324: pUnicastAddress-›Address.iSockaddrLength,
325: szAddress, sizeof(szAddress), NULL, 0,
326: NI_NUMERICHOST)) {
327: fprintf(stderr,
328: "can't convert network format to presentation format");
329: exit(1);
330: }
331: /* Display the unicast address character string. */
332: printf(" Unicast Address#%d¥n", i);
333: printf(" Family=%s, Addr=%s¥n",
334: ((pUnicastAddress-›Address.lpSockaddr)-›sa_family
335: == AF_INET) ? "IPv4" : "IPv6",
336: szAddress);
337:
338: /* Convert life span into a character string and display it. */
339: if (getString_Lifetime(szValidLifetime,
340: sizeof(szValidLifetime),
341: pUnicastAddress-›ValidLifetime) == NULL) {
342: fprintf(stderr, "cannot convert to string¥n");
343: exit(1);
344: }
345: if (getString_Lifetime(szPreferredLifetime,
346: sizeof(szPreferredLifetime),
347: pUnicastAddress-›PreferredLifetime)
348: == NULL) {
349: fprintf(stderr, "cannot convert to string¥n");
350: exit(1);
351: }
352: if (getString_Lifetime(szLeaseLifetime,
353: sizeof(szLeaseLifetime),
354: pUnicastAddress-›LeaseLifetime) == NULL) {
355: fprintf(stderr, "cannot convert to string¥n");
356: exit(1);
357: }
358: printf(" ValidLifetime=%s, "
359: "PreferredLifetime=%s, "
360: "LeaseLifetime=%s¥n",
361: szValidLifetime, szPreferredLifetime, szLeaseLifetime);
362:
363: /*
364: * Display the IP address origin (PREFIX, SUFFIX).
365: */
366: printf(" prefix origin : %s¥n",
367: getString_IP_PREFIX_ORIGIN(pUnicastAddress-›PrefixOrigin));
368: printf(" suffix origin : %s¥n",
369: getString_IP_SUFFIX_ORIGIN(pUnicastAddress-›SuffixOrigin));
370:
371:
372: /*
373: * Display the DAD status for IPv6 addresses.
374: */
375: if ((pUnicastAddress-›Address.lpSockaddr)-›sa_family == AF_INET6) {
376: printf(" DAD state : %s¥n",
377: getString_IP_DAD_STATE(pUnicastAddress-›DadState));
378: }
379: }
380:
381:
382: /*
383: * Display anycast address using the FirstAnycastAddress member.
384: */
385: for (i = 0, pAnycastAddress = pAA-›FirstAnycastAddress;
386: pAnycastAddress;
387: i++, pAnycastAddress = pAnycastAddress-›Next) {
388: char szAddress[NI_MAXHOST];
389:
390: /*
391: * Process for displaying anycast address
392: */
393: /* Convert the address stored in network format (binary) */
394: /* into a human-readable character string (presentation format). */
395: if (getnameinfo(pAnycastAddress-›Address.lpSockaddr,
396: pAnycastAddress-›Address.iSockaddrLength,
397: szAddress, sizeof(szAddress), NULL, 0,
398: NI_NUMERICHOST)) {
399: fprintf(stderr,
400: "can't convert network format to presentation format");
401: exit(1);
402: }
403: /* Display anycast address character string. */
404: printf(" Anycast Address#%d¥n", i);
405: printf(" Family=%s, Addr=%s¥n",
406: ((pAnycastAddress-›Address.lpSockaddr)-›sa_family
407: == AF_INET) ? "IPv4" : "IPv6",
408: szAddress);
409: }
410:
411:
412: /*
413: * Display multicast address using the FirstMulticastAddress member.
414: */
415: for (i = 0, pMulticastAddress = pAA-›FirstMulticastAddress;
416: pMulticastAddress;
417: i++, pMulticastAddress = pMulticastAddress-›Next) {
418: char szAddress[NI_MAXHOST];
419:
420: /*
421: * Process for displaying multicast address
422: */
423: /* Convert the address stored in network format (binary) */
424: /* into a human-readable character string (presentation format). */
425: if (getnameinfo(pMulticastAddress-›Address.lpSockaddr,
426: pMulticastAddress-›Address.iSockaddrLength,
427: szAddress, sizeof(szAddress), NULL, 0,
428: NI_NUMERICHOST)) {
429: fprintf(stderr,
430: "can't convert network format to presentation format");
431: exit(1);
432: }
433: /* Display the multicast address character string. */
434: printf(" Multicast Address#%d¥n", i);
435: printf(" Family=%s, Addr=%s¥n",
436: ((pMulticastAddress-›Address.lpSockaddr)-›sa_family
437: == AF_INET) ? "IPv4" : "IPv6",
438: szAddress);
439: }
440:
441:
442: /*
443: * Display DNS server address using the FirstDnsServerAddress member.
444: */
445: for (i = 0, pDnsServerAddress = pAA-›FirstDnsServerAddress;
446: pDnsServerAddress;
447: i++, pDnsServerAddress = pDnsServerAddress-›Next) {
448: char szAddress[NI_MAXHOST];
449:
450: /*
451: * Process for displaying DNS server address
452: */
453: /* Convert the address stored in network format (binary) */
454: /* into a human-readable character string (presentation format). */
455: if (getnameinfo(pDnsServerAddress-›Address.lpSockaddr,
456: pDnsServerAddress-›Address.iSockaddrLength,
457: szAddress, sizeof(szAddress), NULL, 0,
458: NI_NUMERICHOST)) {
459: fprintf(stderr,
460: "can't convert network format to presentation format");
461: exit(1);
462: }
463: /* Display DNS server address character string. */
464: printf(" DNS Server Address#%d¥n", i);
465: printf(" Family=%s, Addr=%s¥n",
466: ((pDnsServerAddress-›Address.lpSockaddr)-›sa_family
467: == AF_INET) ? "IPv4" : "IPv6",
468: szAddress);
469: }
470:
471:
472: /*
473: * Display DNS suffix (domain name) using the DnsSuffix member.
474: */
475: /* Since DnsSuffix is encoded in Unicode, */
476: /* convert it to multi-byte characters (Shift JIS). */
477: if (wcslen(pAA-›DnsSuffix) != 0) {
478: len = WideCharToMultiByte(CP_ACP, 0,
479: pAA-›DnsSuffix,
480: wcslen(pAA-›DnsSuffix),
481: szDnsSuffix,
482: sizeof(szDnsSuffix),
483: NULL, NULL);
484: if (len == 0) {
485: fprintf(stderr, "cannot convert DNS suffix¥n");
486: exit(1);
487: }
488: szDnsSuffix[len] = '¥0';
489: printf(" DNS suffix : %s¥n", szDnsSuffix);
490: }
491:
492:
493: /*
494: * Display the adapter’s physical address (MAC address)
495: * using the PhysicalAddress and PhysicalAddressLength members.
496: */
497: if (pAA-›PhysicalAddressLength != 0) {
498: printf(" PhysicalAddress : ");
499: for (i = 0; i ‹ pAA-›PhysicalAddressLength - 1; ++i)
500: printf("%02X:", pAA-›PhysicalAddress[i]);
501: printf("%02X¥n",
502: pAA-›PhysicalAddress[pAA-›PhysicalAddressLength - 1]);
503: }
504:
505:
506: /*
507: * Display the adapter’s MTU value using the Mtu member.
508: */
509: printf(" MTU : %d¥n", pAA-›Mtu);
510:
511:
512: /*
513: * Display the interface index using the Ipv6IfIndex member.
514: * fe80::1%6 --- The number written after % matches the number that indicates the adapter.
515: */
516: printf(" IPv6 Interface Index : %d¥n", pAA-›Ipv6IfIndex);
517:
518:
519: /*
520: * Display the adapter’s attributes using the Flags member?B
521: */
522: if (getString_AdapterFlags(szFlagsString, sizeof(szFlagsString),
523: pAA-›Flags) == NULL) {
524: fprintf(stderr, "cannot convert to string¥n");
525: exit(1);
526: }
527: printf(" Flags: %s¥n", szFlagsString);
528:
529:
530: /*
531: * Display zone information using the ZoneIndices member?B
532: */
533: printf(" Zone Info: if %d, link %d, subnet %d, admin %d, site %d, "
534: "org %d, global %d¥n",
535: pAA-›ZoneIndices[ScopeLevelInterface],
536: pAA-›ZoneIndices[ScopeLevelLink],
537: pAA-›ZoneIndices[ScopeLevelSubnet],
538: pAA-›ZoneIndices[ScopeLevelAdmin],
539: pAA-›ZoneIndices[ScopeLevelSite],
540: pAA-›ZoneIndices[ScopeLevelOrganization],
541: pAA-›ZoneIndices[ScopeLevelGlobal]);
542:
543:
544: /*
545: * Display the adapter’s prefix using the FirstPrefix member
546: */
547: for (i = 0, pIpAdapterPrefix= pAA-›FirstPrefix;
548: pIpAdapterPrefix;
549: i++, pIpAdapterPrefix = pIpAdapterPrefix-›Next) {
550: char szAddress[NI_MAXHOST];
551:
552: if (getnameinfo(pIpAdapterPrefix-›Address.lpSockaddr,
553: pIpAdapterPrefix-›Address.iSockaddrLength,
554: szAddress, sizeof(szAddress), NULL, 0,
555: NI_NUMERICHOST)) {
556: fprintf(stderr,
557: "can't convert network format to presentation format");
558: exit(1);
559: }
560:
561: printf(" Prefix#%d¥n", i);
562: switch((pIpAdapterPrefix-›Address.lpSockaddr)-›sa_family) {
563: case AF_INET:
564: printf(" Family=IPv4, Addr=%s¥n", szAddress);
565: break;
566: case AF_INET6:
567: printf(" Family=IPv6, Addr=%s/64¥n", szAddress);
568: break;
569: default:
570: printf(" Family=Unknown, Addr=%s¥n", szAddress);
571: }
572: }
573:
574: putchar('¥n');
575: }
576:
577:
578: /*
579: * Free the space that was used to store the adapter information.
580: */
581: free(pAdapterAddresses);
582:
583:
584: /*
585: * Clean up WinSock.
586: */
587: WSACleanup();
588:
589: exit(0);
590:}}

Part 6 conclusion

In this article, I explained how to use the GetAdaptersAddresses() function for obtaining detailed information on the adapters installed in the host and showed a sample console application that displays adapter information.  When creating advanced applications, I think it will become necessary for the program to obtain the IP address and carry out precise management by looking at the adapter information.

Series conclusion

Through the six articles in this series, I have explained the basic paradigm for creating IPv6-ready server/client programs that use TCP on Windows.  The important point was that rather than creating programs with IPv6-specific functionality, developers should instead create programs that are not protocol-dependent whenever possible.  Also for the protocols that may appear in the future, it is fair to say that creating a program with source code that can deal with them elegantly and efficiently is a huge benefit.

Although there are times, such as the ones I mentioned in Part 6, when you need to pay attention to the specific adapter and address family, please try to minimize the parts that are protocol dependent as much as possible.

This series ends with this article; however, there are still many other functions for creating advanced IPv6 applications that I could not introduce.  Programs that seek performance by using overlapped I/O on both the TCP server and client.  UDP, multicast, ICMPv6, RAW sockets, handling I/O with auxiliary data, functions for asynchronous name resolution, etc.  There are many other important items that I haven not covered yet.  I would like to have the opportunity to introduce them to you in the future.

Although it was a short 6 months, I appreciate you reading my articles.  It would make me happy if this series could be of help to you when you create IPv6 applications.

この記事のトラックバックURL

http://www.ipv6style.jp/trackback/633
Ads by Google

Link

go6 is a community based portal dedicated to advancing the deployment of IPv6.
http://go6.net/