NTT情報流通プラットフォーム研究所
加藤淳也
【その1からの続き】
アダプタの状態を表示するサンプルプログラム -GetAdaptersAddresses.exeコマンドの動作とそのソースコード
GetAdaptersAddresses()関数を利用するサンプルプログラムとしてGetAdaptersAddresses.exeコマンドを作成しました。文末のリスト1として掲載するとともに、コンパイル済みのバイナリを用意しましたので、お使いの環境で実際に動作させて表示を確認してみてください。このコマンドには引数は必要ありません、そのままコマンドプロンプト上で実行するだけです。なお今回はIP_ADAPTER_ADDRESSES構造体の各メンバを文字列に可視化して画面表示を行っているだけなので、ソースコードに関する詳細は解説を割愛します。詳細なコメントを記しましたので参照してください。次節ではGetAdaptersAddresses.exeコマンドの出力例を紹介しておきます。
IPv6ループバックアダプタに関する情報の出力例図2はIPv6ループバックアダプタに関する情報を出力した画面です。一つのアダプタに対してインデントにより構造を持たせた画面が出力されます。仮想アダプタも含めてアダプタが複数装着されているホストではアダプタの数だけ図2に示す構造が繰り返して表示されます。IPv6ループバックアダプタについて先頭の行から表示内容を順に見て行きます。
図2:IPv6ループバックアダプタに関する情報の出力例
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
| 01行目 | FriendlyNameメンバの出力 可読なアダプタの名称を表示する。以降はこのアダプタに関する情報はスペース2つ分インデントして表示します。 |
| 02行目 | AdapterNameメンバの出力 UID形式のアダプタ名の表示 |
| 03行目 | Descriptionメンバの出力 アダプタの解説の出力 |
| 04行目 | IfTypeメンバの出力 メディアタイプの表示(この場合はLoopback) |
| 05行目 | OperStatusメンバの出力 Up/Down等の状態の表示を行う |
| 06~17行目 | FirstUnicastAddressメンバの表示 アダプタに付与されている2つのユニキャストアドレスを順に表示している。それぞれのユニキャストアドレスの情報はスペース2つ分のインデントを行って表示している。 |
| 07行目 | FirstUnicastAddress->Addressの表示 一つ目のユニキャストIPv6アドレスが::1であることを表示 |
| 08行目 | FirstUnicastAddress->ValidLifetime,PreferredLifetimeの表示 アドレスの寿命は無限(ループバックアドレスのため) |
| 09~10行目 | FirstUnicastAddress->PrefixOrigin, SuffixOriginの表示 アドレスの種類の表示(ループバックアドレスのためWellknown) |
| 11行目 | FirstUnicastAddress->DadStateの表示 DAD状態の表示。 有効なIPv6アドレスであることを示している。 |
| 12~17行目 | 2つ目のユニキャストについても同様 |
| 18行目 | Mtuメンバの出力 アダプタのMTU値が1500であることを出力 |
| 19行名 | Ipv6IfIndexメンバの出力 アダプタ(インターフェイス)インデックスの表示 |
| 20行目 | Flagsメンバの出力 DynamicDNSが有効になっていることが表示される |
| 21行目 | ZoneIndicesメンバの表示 リンクローカルアドレスのスコープ(link)のゾーン番号が1 サイトローカルアドレスのスコープ(site)のゾーン番号が5 グローバルスアドレスのコープ(global)のゾーン番号が0 その他のスコープについては、OS内部で実際にどのように利用されているか不明。 得られた値をそのまま表示している |
| 22行目 | FirstPrefixメンバの出力 リンクローカルアドレスのプリフィックスfe80::/64を表示している |
なお、ループバックアドレスのため物理アドレスを持たない、またマルチキャストアドレスとエニーキャストアドレスはループバックアダプタには付与されていないため、表示が行われません。なおWindows XP SP2の実装では、IPv6とIPv4で独立したループバックアダプタがもちいられているため、IPv4のループバックアドレス(127.0.0.1)表示されていません。
ローカルエリア接続(有線Ethernetアダプタ)に関する情報の出力例図3は有線Ethernetアダプタに関する情報を出力した画面です。ループバックアダプタと出力内容はほぼ同じのため詳細な解説は割愛します。
図3:ローカルエリア接続アダプタに関する情報の出力例
01:Adapter Name : ローカル エリア接続
02: Adapter UID = {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}
03: Description : Intel(R) PRO/1000 MT Mobile Connection - パケット スケジューラ ミニポート
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
6~28行目の出力によりローカルエリア接続アダプタにはIPv6、IPv4の両者のアドレスが割り当てられていることがわかります。IPv6アドレスが2つ付与されていますが、これらはRAとアダプタのMACアドレスから構成したものと、匿名アドレスです。またこのアダプタは物理アドレスをもつため、50行目ではMACアドレスが表示されています。その他は29~40行目にマルチキャストアドレスやDNSに関する表示がある他は、ループバックアダプタと同じ内容です。
GetAdaptersAddresses.exeコマンドのソースコードとバイナリのダウンロードソースコードとコンパイル済みバイナリをダウンロードできるようにしておきました。
- ソースコード:GetAdaptersAddresses.c
- コンパイル済みバイナリ:GetAdaptersAddresses.exe
001:/*
002: * GetAdaptersAddresses() API によりアダプタ情報を取得するコマンド
003: *
004: * コンパイル方法
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:/* IPアドレスのプレフィックス(ネットワーク)部の付与元 */
017:/* を表すIP_PREFIX_ORIGIN型の列挙子を文字列に変換する */
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:/* IPアドレスのインターフェイスID(ホスト部)の付与元 */
033:/* を表すIP_SUFFIX_ORIGIN型の列挙子を文字列に変換する*/
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:/* IPv6アドレスのDAD状態を示す */
050:/* IP_DAD_STATE型の列挙子を文字列に変換する */
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:/* アダプタの状態を示す */
065:/* IF_OPER_STATUS型の列挙子を文字列に変換する */
066:const char *getString_IF_OPER_STATUS(IF_OPER_STATUS ios)
067:{
068: const char *szOperationalStatus[] = {
069: "", /* IF_OPER_STATUS列挙子の定義では0は欠番 */
070: "Up",
071: "Down",
072: "Testing",
073: "Unknown",
074: "Dormant",
075: "NotPresent",
076: "LowerLayerDown"
077: };
078:
079: return szOperationalStatus[ios];
080:}
081:
082:
083:/* アダプタのタイプ(メディア種別)を示す */
084:/* 値(dwIfType)を文字列に変換する */
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:/* 寿命を表すULONG値(lt)を文字列に変換しszBufへ書き込む。 */
101:/* 寿命値ltがULONG_MAXに等しい場合は"無限を表す文字列 */
102:/* "infinite"を返却する。szBufに十分な大きさ(size)が確保 */
103:/* されていない場合は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:/* アダプタの属性を示すフラグ情報を文字列に変換する。フラグの名前は */
119:/* カンマ(,)で区切って出力sれる */
120:/* szBufに十分な大きさ(size)が確保されていない場合は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:/* スコープを示すSCOPE_LEVEL型の列挙子を文字列に変換する */
163:const char *getString_SCOPE_LEVEL(SCOPE_LEVEL sl)
164:{
165: const char *szScopeLevel[] = {
166: "", /* SCOPE_LEVEL列挙子の定義では0は欠番 */
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: * WinSockの初期化
188: */
189: if (WSAStartup(MAKEWORD(2, 2), &wsaData)) {
190: fprintf(stderr, "cannot initilize WinSock\n");
191: exit(1);
192: }
193:
194:
195: /*
196: * 戻り値を格納するのに必要なバッファの大きさを求める
197: * dwSizeにその値が得られる。FirstPrefixメンバにプリフィックス
198: * 情報を得るため。第2引数のフラグにGAA_FLAG_INCLUDE_PREFIXを立てる
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: * pAdapterAddressesにdwSizeの大きさのバッファを確保する
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: * GetAdaptersAddresses()を再度呼び出しpAdapterAddressesに
220: * アダプタ情報を取得する。FirstPrefixメンバにプリフィックス
221: * 情報を得るため。第2引数のフラグにGAA_FLAG_INCLUDE_PREFIXを立てる
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: * すべてのアダプタについて、それぞれがもつ情報を表示する
233: * pAAが現在注目するアダプタのIP_ADAPTER_ADDRESSES構造体の
234: * インスタンス
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: * FriendlyNameメンバにより可読なアダプタ名を表示する
252: */
253: /* FriendlyNameはユニコードのためマルチバイト */
254: /* 文字(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: * AdapterNameメンバによりアダプタ名(UID形式)を表示する
270: */
271: printf(" Adapter UID = %s\n", pAA-›AdapterName);
272:
273:
274: /*
275: * Descriptionメンバからアダプタの解説を表示する
276: */
277: /* Descriptionはユニコードのためマルチバイト */
278: /* 文字(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: * IfTypeメンバによりアダプタのメディアタイプを表示する
295: */
296: printf(" Type : %s\n", getString_IfType(pAA-›IfType));
297:
298:
299: /*
300: * OperStatusメンバによりアダプタの状態を表示する
301: */
302: printf(" Operational Status : %s\n",
303: getString_IF_OPER_STATUS(pAA-›OperStatus));
304:
305:
306: /*
307: * FirstUnicastAddressメンバによりアダプタに
308: * 付与されたユニキャストアドレスを表示する
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: * ユニキャストアドレスの表示処理
320: */
321: /* ネットワークフォーマット(バイナリ)で格納されるアドレスを */
322: /* 可読な文字列(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: /* ユニキャストアドレスの文字列を表示する */
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: /* 寿命を文字列に変換し表示する */
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: * IPアドレスの取得元(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: * IPv6アドレスの場合DAD状態を表示する
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: * FirstAnycastAddressメンバによりエニーキャストアドレスを表示する
384: */
385: for (i = 0, pAnycastAddress = pAA-›FirstAnycastAddress;
386: pAnycastAddress;
387: i++, pAnycastAddress = pAnycastAddress-›Next) {
388: char szAddress[NI_MAXHOST];
389:
390: /*
391: * エニーキャストアドレスの表示処理
392: */
393: /* ネットワークフォーマット(バイナリ)で格納されるアドレスを */
394: /* 可読な文字列(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: /* エニーキャストアドレスの文字列を表示する */
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: * FirstMulticastAddressメンバによりマルチキャストアドレスを表示する
414: */
415: for (i = 0, pMulticastAddress = pAA-›FirstMulticastAddress;
416: pMulticastAddress;
417: i++, pMulticastAddress = pMulticastAddress-›Next) {
418: char szAddress[NI_MAXHOST];
419:
420: /*
421: * マルチキャストアドレスの表示処理
422: */
423: /* ネットワークフォーマット(バイナリ)で格納されるアドレスを */
424: /* 可読な文字列(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: /* マルチキャストアドレスの文字列を表示する */
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: * FirstDnsServerAddressメンバによりDNSサーバのアドレスを表示する
444: */
445: for (i = 0, pDnsServerAddress = pAA-›FirstDnsServerAddress;
446: pDnsServerAddress;
447: i++, pDnsServerAddress = pDnsServerAddress-›Next) {
448: char szAddress[NI_MAXHOST];
449:
450: /*
451: * DNSサーバのアドレスの表示処理
452: */
453: /* ネットワークフォーマット(バイナリ)で格納されるアドレスを */
454: /* 可読な文字列(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: /* DNSサーバアドレスの文字列を表示する */
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: * DnsSuffixメンバによりDNSサフィックス(ドメイン名)を表示する
474: */
475: /* DnsSuffixはユニコードのためマルチバイト */
476: /* 文字(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: * PhysicalAddress, PhysicalAddressLengthメンバにより
495: * アダプタの物理アドレス(MACアドレス)を表示する
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: * MtuメンバによりアダプタのMTU値を表示する
508: */
509: printf(" MTU : %d\n", pAA-›Mtu);
510:
511:
512: /*
513: * Ipv6IfIndexメンバによりインターフェイスインデックスを表示する
514: * fe80::1%6 --- %に後ろに記述されるアダプタを示す番号と一致
515: */
516: printf(" IPv6 Interface Index : %d\n", pAA-›Ipv6IfIndex);
517:
518:
519: /*
520: * Flagsメンバによりアダプタの属性を表示する
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: * ZoneIndicesメンバによりゾーン情報を表示する
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: * FirstPrefixメンバによりアダプタの持つプレフィックスを表示する
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: * アダプタ情報を格納していた領域を開放する
580: */
581: free(pAdapterAddresses);
582:
583:
584: /*
585: * WinSockのクリーンナップ
586: */
587: WSACleanup();
588:
589: exit(0);
590:}
第6回のまとめ
今回はホストに取り付けられているアダプタの詳細情報を取り出すAPIGetAdaptersAddresses()関数の使い方を紹介し、アダプタ情報を表示するコンソールアプリケーションをサンプルとして提示しました。自身の持つIPアドレスを取得したり、アダプタ情報を見てきめ細かな制御を行うことは、高度なアプリケーションを作成する上で必要になると思われます。
連載全体を通じてのまとめ
これまで、全6回にわたりWindows上でIPv6に対応したTCPを使ったサーバ・クライアントプログラムの基本的な作成パラダイムを解説しました。ポイントはIPv6特化した機構を組み込むのではなくプロトコルになるべく依存しないプログラムを作成することでした。将来出現するであろうプロトコルに対しても、ソースコードレベルでもエレガントかつ効率的に対応できるプログラムを作成することはメリットが大きいといえます。
第6回で紹介したような、特定のアダプタやアドレスファミリに注目して処理を行う場合もありますが、プロトコルに依存する部分は極力最小化するように心がけてください。
本連載はここでいったん終了となりますが、さらに高度なIPv6アプリケーションを作成する上で、まだ紹介しきれていない機能がたくさん残されています。TCPのサーバ・クライアントでも重複I/Oを使いパフォーマンスを追求したプログラムや、UDP、マルチキャスト、ICMPv6、RAWソケット、補助データつきのI/Oの扱い、非同期名前解決の機能など、まだまだ重要な項目が解説できていません。改めて機会を設けて皆様に紹介させていただきたいと思います。
半年間の短い間ではありましたが、お付き合いいただきありがとうございました。本連載が皆様のIPv6アプリケーション作成の一助になれば幸いです。


