don't try and display data if iphlpapi functions fail
[reactos.git] / reactos / apps / utils / net / ipconfig / ipconfig.c
1 /*
2 * ReactOS Win32 Applications
3 * Copyright (C) 2005 ReactOS Team
4 *
5 * COPYRIGHT: See COPYING in the top level directory
6 * PROJECT: ReactOS arp utility
7 * FILE: apps/utils/net/ipconfig/ipconfig.c
8 * PURPOSE:
9 * PROGRAMMERS: Ged Murphy (gedmurphy@gmail.com)
10 * REVISIONS:
11 * GM 14/09/05 Created
12 *
13 */
14 /*
15 * TODO:
16 * fix renew / release
17 * implement flushdns, registerdns, displaydns, showclassid, setclassid
18 * allow globbing on adapter names
19 */
20 #define WIN32_LEAN_AND_MEAN
21 #include <windows.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <time.h>
25 #include <tchar.h>
26 #include <string.h>
27 #include <ctype.h>
28 #include <winsock2.h>
29 #include <iphlpapi.h>
30
31 #define UNICODE
32 #define _UNICODE
33
34
35 PTCHAR GetNodeTypeName(UINT NodeType)
36 {
37 switch (NodeType) {
38 case 1: return _T("Broadcast");
39 case 2: return _T("Peer To Peer");
40 case 4: return _T("Mixed");
41 case 8: return _T("Hybrid");
42 default : return _T("unknown");
43 }
44 }
45
46 PTCHAR GetInterfaceTypeName(UINT InterfaceType)
47 {
48 switch (InterfaceType) {
49 case MIB_IF_TYPE_OTHER: return _T("Other Type Of Adapter");
50 case MIB_IF_TYPE_ETHERNET: return _T("Ethernet Adapter");
51 case MIB_IF_TYPE_TOKENRING: return _T("Token Ring Adapter");
52 case MIB_IF_TYPE_FDDI: return _T("FDDI Adapter");
53 case MIB_IF_TYPE_PPP: return _T("PPP Adapter");
54 case MIB_IF_TYPE_LOOPBACK: return _T("Loopback Adapter");
55 case MIB_IF_TYPE_SLIP: return _T("SLIP Adapter");
56 default: return _T("unknown");
57 }
58 }
59
60 /* print MAC address */
61 PTCHAR PrintMacAddr(PBYTE Mac)
62 {
63 static TCHAR MacAddr[20];
64
65 _stprintf(MacAddr, _T("%02x-%02x-%02x-%02x-%02x-%02x"),
66 Mac[0], Mac[1], Mac[2], Mac[3], Mac[4], Mac[5]);
67
68 return MacAddr;
69 }
70
71 DWORD DoFormatMessage(DWORD ErrorCode)
72 {
73 LPVOID lpMsgBuf;
74 DWORD RetVal;
75
76 if ((RetVal = FormatMessage(
77 FORMAT_MESSAGE_ALLOCATE_BUFFER |
78 FORMAT_MESSAGE_FROM_SYSTEM |
79 FORMAT_MESSAGE_IGNORE_INSERTS,
80 NULL,
81 ErrorCode,
82 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
83 (LPTSTR) &lpMsgBuf,
84 0,
85 NULL ))) {
86 _tprintf(_T("%s"), (LPTSTR)lpMsgBuf);
87
88 LocalFree(lpMsgBuf);
89 /* return number of TCHAR's stored in output buffer
90 * excluding '\0' - as FormatMessage does*/
91 return RetVal;
92 }
93 else
94 return 0;
95 }
96
97 INT ShowInfo(BOOL bAll)
98 {
99 PIP_ADAPTER_INFO pAdapterInfo = NULL;
100 PIP_ADAPTER_INFO pAdapter = NULL;
101 ULONG adaptOutBufLen;
102
103 PFIXED_INFO pFixedInfo;
104 ULONG netOutBufLen;
105 PIP_ADDR_STRING pIPAddr = NULL;
106
107 /* assign memory for call to GetNetworkParams */
108 pFixedInfo = (FIXED_INFO *) GlobalAlloc( GPTR, sizeof( FIXED_INFO ) );
109 netOutBufLen = sizeof(FIXED_INFO);
110
111 /* assign memory for call to GetAdapterInfo */
112 pAdapterInfo = (IP_ADAPTER_INFO *) malloc( sizeof(IP_ADAPTER_INFO) );
113 adaptOutBufLen = sizeof(IP_ADAPTER_INFO);
114
115 /* set required buffer size */
116 if(GetNetworkParams(pFixedInfo, &netOutBufLen) == ERROR_BUFFER_OVERFLOW)
117 {
118 GlobalFree(pFixedInfo);
119 pFixedInfo = (FIXED_INFO *) GlobalAlloc(GPTR, netOutBufLen);
120 }
121
122 /* set required buffer size */
123 if (GetAdaptersInfo( pAdapterInfo, &adaptOutBufLen) == ERROR_BUFFER_OVERFLOW)
124 {
125 free(pAdapterInfo);
126 pAdapterInfo = (IP_ADAPTER_INFO *) malloc (adaptOutBufLen);
127 }
128
129 if (! GetAdaptersInfo(pAdapterInfo, &adaptOutBufLen) == NO_ERROR)
130 {
131 _tprintf(_T("GetAdaptersInfo failed %lu\n"), GetLastError());
132 return EXIT_FAILURE;
133 }
134
135 if (! GetNetworkParams(pFixedInfo, &netOutBufLen) == NO_ERROR)
136 {
137 _tprintf(_T("GetNetworkParams failed %lu\n"), GetLastError());
138 return EXIT_FAILURE;
139 }
140
141 pAdapter = pAdapterInfo;
142 //HKEY hKey;
143 //LPCTSTR lpSubKey = _T("SYSTEM\\ControlSet\\Control\\Network");
144
145 _tprintf(_T("\nReactOS IP Configuration\n\n"));
146
147 while (pAdapter)
148 {
149 if (bAll)
150 {
151 _tprintf(_T("\tHost Name . . . . . . . . . . . . : %s\n"), pFixedInfo->HostName);
152 _tprintf(_T("\tPrimary DNS Suffix. . . . . . . . : \n"));
153 _tprintf(_T("\tNode Type . . . . . . . . . . . . : %s\n"), GetNodeTypeName(pFixedInfo->NodeType));
154 if (pFixedInfo->EnableRouting)
155 _tprintf(_T("\tIP Routing Enabled. . . . . . . . : Yes\n"));
156 else
157 _tprintf(_T("\tIP Routing Enabled. . . . . . . . : No\n"));
158 if (pAdapter->HaveWins)
159 _tprintf(_T("\tWINS Proxy enabled. . . . . . . . : Yes\n"));
160 else
161 _tprintf(_T("\tWINS Proxy enabled. . . . . . . . : No\n"));
162 _tprintf(_T("\tDNS Suffix Search List. . . . . . : %s\n"), pFixedInfo->DomainName);
163 }
164
165 _tprintf(_T("\n%s ...... : \n\n"), GetInterfaceTypeName(pAdapter->Type));
166
167 /* check if the adapter is connected to the media */
168 if (_tcscmp(pAdapter->IpAddressList.IpAddress.String, "0.0.0.0") == 0)
169 {
170 _tprintf(_T("\tMedia State . . . . . . . . . . . : Media disconnected\n"));
171 pAdapter = pAdapter->Next;
172 continue;
173 }
174
175 _tprintf(_T("\tConnection-specific DNS Suffix. . : %s\n"), pFixedInfo->DomainName);
176
177 if (bAll)
178 {
179 _tprintf(_T("\tDescription . . . . . . . . . . . : %s\n"), pAdapter->Description);
180 _tprintf(_T("\tPhysical Address. . . . . . . . . : %s\n"), PrintMacAddr(pAdapter->Address));
181 if (pAdapter->DhcpEnabled)
182 _tprintf(_T("\tDHCP Enabled. . . . . . . . . . . : Yes\n"));
183 else
184 _tprintf(_T("\tDHCP Enabled. . . . . . . . . . . : No\n"));
185 _tprintf(_T("\tAutoconfiguration Enabled . . . . : \n"));
186 }
187
188 _tprintf(_T("\tIP Address. . . . . . . . . . . . : %s\n"), pAdapter->IpAddressList.IpAddress.String);
189 _tprintf(_T("\tSubnet Mask . . . . . . . . . . . : %s\n"), pAdapter->IpAddressList.IpMask.String);
190 _tprintf(_T("\tDefault Gateway . . . . . . . . . : %s\n"), pAdapter->GatewayList.IpAddress.String);
191
192 if (bAll)
193 {
194 if (pAdapter->DhcpEnabled)
195 _tprintf(_T("\tDHCP Server . . . . . . . . . . . : %s\n"), pAdapter->DhcpServer.IpAddress.String);
196
197 _tprintf(_T("\tDNS Servers . . . . . . . . . . . : "));
198 _tprintf(_T("%s\n"), pFixedInfo->DnsServerList.IpAddress.String);
199 pIPAddr = pFixedInfo -> DnsServerList.Next;
200 while (pIPAddr)
201 {
202 _tprintf(_T("\t\t\t\t\t %s\n"), pIPAddr ->IpAddress.String );
203 pIPAddr = pIPAddr ->Next;
204 }
205 if (pAdapter->HaveWins)
206 {
207 _tprintf(_T("\tPrimary WINS Server . . . . . . . : %s\n"), pAdapter->PrimaryWinsServer.IpAddress.String);
208 _tprintf(_T("\tSecondard WINS Server . . . . . . : %s\n"), pAdapter->SecondaryWinsServer.IpAddress.String);
209 }
210 if (pAdapter->DhcpEnabled)
211 {
212 _tprintf(_T("\tLease Obtained. . . . . . . . . . : %s"), _tasctime(localtime(&pAdapter->LeaseObtained)));
213 _tprintf(_T("\tLease Expires . . . . . . . . . . : %s"), _tasctime(localtime(&pAdapter->LeaseExpires)));
214 }
215 }
216 _tprintf(_T("\n"));
217
218 pAdapter = pAdapter->Next;
219
220 }
221
222 return 0;
223 }
224
225 INT Release(TCHAR Index)
226 {
227 IP_ADAPTER_INDEX_MAP AdapterInfo;
228 DWORD dwRetVal = 0;
229
230 /* if interface is not given, query GetInterfaceInfo */
231 if (Index == (TCHAR)NULL)
232 {
233 PIP_INTERFACE_INFO pInfo;
234 pInfo = (IP_INTERFACE_INFO *) malloc(sizeof(IP_INTERFACE_INFO));
235 ULONG ulOutBufLen = 0;
236
237 /* Make an initial call to GetInterfaceInfo to get
238 * the necessary size into the ulOutBufLen variable */
239 if ( GetInterfaceInfo(pInfo, &ulOutBufLen) == ERROR_INSUFFICIENT_BUFFER)
240 {
241 GlobalFree(pInfo);
242 pInfo = (IP_INTERFACE_INFO *) malloc (ulOutBufLen);
243 }
244
245 /* Make a second call to GetInterfaceInfo to get the actual data we want */
246 if ((dwRetVal = GetInterfaceInfo(pInfo, &ulOutBufLen)) == NO_ERROR )
247 {
248 AdapterInfo = pInfo->Adapter[0];
249 _tprintf(_T("name - %S\n"), pInfo->Adapter[0].Name);
250 }
251 else
252 {
253 _tprintf(_T("\nGetInterfaceInfo failed : "));
254 DoFormatMessage(dwRetVal);
255 }
256 }
257 else
258 {
259 ;
260 /* we need to be able to release connections by name with support for globbing
261 * i.e. ipconfig /release Eth* will release all cards starting with Eth...
262 * ipconfig /release *con* will release all cards with 'con' in their name
263 */
264 }
265
266
267 /* Call IpReleaseAddress to release the IP address on the specified adapter. */
268 if ((dwRetVal = IpReleaseAddress(&AdapterInfo)) != NO_ERROR)
269 {
270 _tprintf(_T("\nAn error occured while releasing interface %s : "), _T("*name*"));
271 DoFormatMessage(dwRetVal);
272 }
273 return 0;
274 }
275
276
277
278
279 INT Renew(TCHAR Index)
280 {
281 IP_ADAPTER_INDEX_MAP AdapterInfo;
282 DWORD dwRetVal = 0;
283
284 /* if interface is not given, query GetInterfaceInfo */
285 if (Index == (TCHAR)NULL)
286 {
287 PIP_INTERFACE_INFO pInfo;
288 pInfo = (IP_INTERFACE_INFO *) malloc(sizeof(IP_INTERFACE_INFO));
289 ULONG ulOutBufLen = 0;
290
291 /* Make an initial call to GetInterfaceInfo to get
292 * the necessary size into the ulOutBufLen variable */
293 if ( GetInterfaceInfo(pInfo, &ulOutBufLen) == ERROR_INSUFFICIENT_BUFFER)
294 {
295 GlobalFree(pInfo);
296 pInfo = (IP_INTERFACE_INFO *) malloc (ulOutBufLen);
297 }
298
299 /* Make a second call to GetInterfaceInfo to get the actual data we want */
300 if ((dwRetVal = GetInterfaceInfo(pInfo, &ulOutBufLen)) == NO_ERROR )
301 {
302 AdapterInfo = pInfo->Adapter[0];
303 _tprintf(_T("name - %S\n"), pInfo->Adapter[0].Name);
304 } else {
305 _tprintf(_T("\nGetInterfaceInfo failed : "));
306 DoFormatMessage(dwRetVal);
307 }
308 }
309 else
310 {
311 ;
312 /* we need to be able to renew connections by name with support for globbing
313 * i.e. ipconfig /renew Eth* will renew all cards starting with Eth...
314 * ipconfig /renew *con* will renew all cards with 'con' in their name
315 */
316 }
317
318
319 /* Call IpRenewAddress to renew the IP address on the specified adapter. */
320 if ((dwRetVal = IpRenewAddress(&AdapterInfo)) != NO_ERROR)
321 {
322 _tprintf(_T("\nAn error occured while renew interface %s : "), _T("*name*"));
323 DoFormatMessage(dwRetVal);
324 }
325 return 0;
326 }
327
328 /* temp func for testing purposes */
329 VOID Info()
330 {
331 // Declare and initialize variables
332 PIP_INTERFACE_INFO pInfo;
333 pInfo = (IP_INTERFACE_INFO *) malloc( sizeof(IP_INTERFACE_INFO) );
334 ULONG ulOutBufLen = sizeof(IP_INTERFACE_INFO);
335 DWORD dwRetVal = 0;
336
337
338 // Make an initial call to GetInterfaceInfo to get
339 // the necessary size in the ulOutBufLen variable
340 if ( GetInterfaceInfo(pInfo, &ulOutBufLen) == ERROR_INSUFFICIENT_BUFFER)
341 {
342 free(pInfo);
343 pInfo = (IP_INTERFACE_INFO *) malloc (ulOutBufLen);
344 }
345
346 // Make a second call to GetInterfaceInfo to get
347 // the actual data we need
348 if ((dwRetVal = GetInterfaceInfo(pInfo, &ulOutBufLen)) == NO_ERROR )
349 {
350 int i;
351 for (i=0; i<pInfo->NumAdapters; i++)
352 {
353 printf("\tAdapter Name: %S\n", pInfo->Adapter[i].Name);
354 printf("\tAdapter Index: %ld\n", pInfo->Adapter[i].Index);
355 printf("\tNum Adapters: %ld\n", pInfo->NumAdapters);
356 }
357 }
358 else
359 {
360 printf("GetInterfaceInfo failed.\n");
361 DoFormatMessage(dwRetVal);
362 }
363 }
364
365
366 VOID Usage(VOID)
367 {
368 _tprintf(_T("\nUSAGE:\n"
369 " ipconfig [/? | /all | /renew [adapter] | /release [adapter] |\n"
370 " /flushdns | /displaydns | /registerdns |\n"
371 " /showclassid adapter |\n"
372 " /setclassid adapter [classid] ]\n"
373 "\n"
374 "where\n"
375 " adapter Connection name\n"
376 " (wildcard characters * and ? allowed, see examples)\n"
377 "\n"
378 " Options:\n"
379 " /? Display this help message\n"
380 " /all Display full configuration information.\n"
381 " /release Release the IP address for the specified adapter.\n"
382 " /renew Renew the IP address for the specified adapter.\n"
383 " /flushdns Purges the DNS Resolver cache.\n"
384 " /registerdns Refreshes all DHCP leases and re-registers DNS names.\n"
385 " /displaydns Display the contents of the DNS Resolver Cache.\n"
386 " /showclassid Displays all the dhcp class IDs allowed for adapter.\n"
387 " /setclassid Modifies the dhcp class id.\n"
388 "\n"
389 "The default is to display only the IP address, subnet mask and\n"
390 "default gateway for each adapter bound to TCP/IP.\n"
391 "\n"
392 "For Release and Renew, if no adapter name is specified, then the IP address\n"
393 "leases for all adapters bound to TCP/IP will be released or renewed.\n"
394 "\n"
395 "For Setclassid, if no ClassId is specified, then the ClassId is removed.\n"
396 "\n"
397 "Examples:\n"
398 " > ipconfig ... Show information.\n"
399 " > ipconfig /all ... Show detailed information\n"
400 " > ipconfig /renew ... renew all adapters\n"
401 " > ipconfig /renew EL* ... renew any connection that has its\n"
402 " name starting with EL\n"
403 " > ipconfig /release *Con* ... release all matching connections,\n"
404 " eg. \"Local Area Connection 1\" or\n"
405 " \"Local Area Connection 2\"\n"));
406 }
407
408 int main(int argc, char *argv[])
409 {
410 BOOL DoUsage=FALSE;
411 BOOL DoAll=FALSE;
412 BOOL DoRelease=FALSE;
413 BOOL DoRenew=FALSE;
414 BOOL DoFlushdns=FALSE;
415 BOOL DoRegisterdns=FALSE;
416 BOOL DoDisplaydns=FALSE;
417 BOOL DoShowclassid=FALSE;
418 BOOL DoSetclassid=FALSE;
419
420 /* Parse command line for options we have been given. */
421 if ( (argc > 1)&&(argv[1][0]=='/') )
422 {
423 if( !_tcsicmp( &argv[1][1], _T("?") ))
424 {
425 DoUsage = TRUE;
426 }
427 else if( !_tcsnicmp( &argv[1][1], _T("ALL"), _tcslen(&argv[1][1]) ))
428 {
429 DoAll = TRUE;
430 }
431 else if( !_tcsnicmp( &argv[1][1], _T("RELEASE"), _tcslen(&argv[1][1]) ))
432 {
433 DoRelease = TRUE;
434 }
435 else if( ! _tcsnicmp( &argv[1][1], _T("RENEW"), _tcslen(&argv[1][1]) ))
436 {
437 DoRenew = TRUE;
438 }
439 else if( ! _tcsnicmp( &argv[1][1], _T("FLUSHDNS"), _tcslen(&argv[1][1]) ))
440 {
441 DoFlushdns = TRUE;
442 }
443 else if( ! _tcsnicmp( &argv[1][1], _T("FLUSHREGISTERDNS"), _tcslen(&argv[1][1]) ))
444 {
445 DoRegisterdns = TRUE;
446 }
447 else if( ! _tcsnicmp( &argv[1][1], _T("DISPLAYDNS"), _tcslen(&argv[1][1]) ))
448 {
449 DoDisplaydns = TRUE;
450 }
451 else if( ! _tcsnicmp( &argv[1][1], _T("SHOWCLASSID"), _tcslen(&argv[1][1]) ))
452 {
453 DoShowclassid = TRUE;
454 }
455 else if( ! _tcsnicmp( &argv[1][1], _T("SETCLASSID"), _tcslen(&argv[1][1]) ))
456 {
457 DoSetclassid = TRUE;
458 }
459 }
460
461 switch (argc)
462 {
463 case 1: /* Default behaviour if no options are given*/
464 ShowInfo(FALSE);
465 break;
466 case 2: /* Process all the options that take no paramiters */
467 if (DoUsage)
468 Usage();
469 else if (DoAll)
470 ShowInfo(TRUE);
471 else if (DoRelease)
472 Release((TCHAR)NULL);
473 else if (DoRenew)
474 Renew((TCHAR)NULL);
475 else if (DoFlushdns)
476 _tprintf(_T("\nSorry /flushdns is not implemented yet\n"));
477 else if (DoRegisterdns)
478 _tprintf(_T("\nSorry /registerdns is not implemented yet\n"));
479 else if (DoDisplaydns)
480 _tprintf(_T("\nSorry /displaydns is not implemented yet\n"));
481 else
482 Usage();
483 break;
484 case 3: /* Process all the options that can have 1 paramiters */
485 if (DoRelease)
486 _tprintf(_T("\nSorry /release [adapter] is not implemented yet\n"));
487 //Release(argv[2]);
488 else if (DoRenew)
489 _tprintf(_T("\nSorry /renew [adapter] is not implemented yet\n"));
490 else if (DoShowclassid)
491 _tprintf(_T("\nSorry /showclassid adapter is not implemented yet\n"));
492 else if (DoSetclassid)
493 _tprintf(_T("\nSorry /setclassid adapter is not implemented yet\n"));
494 else
495 Usage();
496 break;
497 case 4: /* Process all the options that can have 2 paramiters */
498 if (DoSetclassid)
499 _tprintf(_T("\nSorry /setclassid adapter [classid]is not implemented yet\n"));
500 else
501 Usage();
502 break;
503 default:
504 Usage();
505 }
506
507 return 0;
508 }