1 /*
2  * PROJECT:     ReactOS ipconfig utility
3  * LICENSE:     GPL - See COPYING in the top level directory
4  * FILE:        base/applications/network/ipconfig/ipconfig.c
5  * PURPOSE:     Display IP info for net adapters
6  * PROGRAMMERS: Copyright 2005 - 2006 Ged Murphy (gedmurphy@gmail.com)
7  */
8 /*
9  * TODO:
10  * fix renew / release
11  * implement registerdns, showclassid, setclassid
12  * allow globbing on adapter names
13  */
14 
15 #define WIN32_NO_STATUS
16 #include <stdarg.h>
17 #include <windef.h>
18 #include <winbase.h>
19 #include <winuser.h>
20 #include <winreg.h>
21 #include <stdio.h>
22 #include <tchar.h>
23 #include <time.h>
24 #include <iphlpapi.h>
25 #include <ndk/rtlfuncs.h>
26 #include <inaddr.h>
27 #include <windns.h>
28 #include <windns_undoc.h>
29 
30 #include "resource.h"
31 
32 #define GUID_LEN 40
33 
34 HINSTANCE hInstance;
35 HANDLE ProcessHeap;
36 
37 int LoadStringAndOem(HINSTANCE hInst,
38                      UINT uID,
39                      LPTSTR szNode,
40                      int byteSize)
41 {
42     TCHAR *szTmp;
43     int res;
44 
45     szTmp = (LPTSTR)HeapAlloc(ProcessHeap, 0, byteSize);
46     if (szTmp == NULL)
47     {
48         return 0;
49     }
50 
51     res = LoadString(hInst, uID, szTmp, byteSize);
52     CharToOem(szTmp, szNode);
53     HeapFree(ProcessHeap, 0, szTmp);
54     return res;
55 }
56 
57 LPTSTR GetNodeTypeName(UINT NodeType)
58 {
59     static TCHAR szNode[14];
60 
61     switch (NodeType)
62     {
63         case 1:
64             if (!LoadStringAndOem(hInstance, IDS_BCAST, szNode,  sizeof(szNode)))
65                 return NULL;
66             break;
67 
68         case 2:
69             if (!LoadStringAndOem(hInstance, IDS_P2P, szNode,  sizeof(szNode)))
70                 return NULL;
71             break;
72 
73         case 4:
74             if (!LoadStringAndOem(hInstance, IDS_MIXED, szNode,  sizeof(szNode)))
75                 return NULL;
76             break;
77 
78         case 8:
79             if (!LoadStringAndOem(hInstance, IDS_HYBRID, szNode,  sizeof(szNode)))
80                 return NULL;
81             break;
82 
83         default :
84             if (!LoadStringAndOem(hInstance, IDS_UNKNOWN, szNode,  sizeof(szNode)))
85                 return NULL;
86             break;
87     }
88 
89     return szNode;
90 }
91 
92 
93 LPTSTR GetInterfaceTypeName(UINT InterfaceType)
94 {
95     static TCHAR szIntType[25];
96 
97     switch (InterfaceType)
98     {
99         case MIB_IF_TYPE_OTHER:
100             if (!LoadStringAndOem(hInstance, IDS_OTHER, szIntType, sizeof(szIntType)))
101                 return NULL;
102             break;
103 
104         case MIB_IF_TYPE_ETHERNET:
105             if (!LoadStringAndOem(hInstance, IDS_ETH, szIntType, sizeof(szIntType)))
106                 return NULL;
107             break;
108 
109         case MIB_IF_TYPE_TOKENRING:
110             if (!LoadStringAndOem(hInstance, IDS_TOKEN, szIntType, sizeof(szIntType)))
111                 return NULL;
112             break;
113 
114         case MIB_IF_TYPE_FDDI:
115             if (!LoadStringAndOem(hInstance, IDS_FDDI, szIntType, sizeof(szIntType)))
116                 return NULL;
117             break;
118 
119         case MIB_IF_TYPE_PPP:
120             if (!LoadStringAndOem(hInstance, IDS_PPP, szIntType, sizeof(szIntType)))
121                 return NULL;
122             break;
123 
124         case MIB_IF_TYPE_LOOPBACK:
125             if (!LoadStringAndOem(hInstance, IDS_LOOP, szIntType, sizeof(szIntType)))
126                 return NULL;
127             break;
128 
129         case MIB_IF_TYPE_SLIP:
130             if (!LoadStringAndOem(hInstance, IDS_SLIP, szIntType, sizeof(szIntType)))
131                 return NULL;
132             break;
133 
134         default:
135             if (!LoadStringAndOem(hInstance, IDS_UNKNOWN, szIntType, sizeof(szIntType)))
136                 return NULL;
137             break;
138     }
139 
140     return szIntType;
141 }
142 
143 
144 /* print MAC address */
145 PTCHAR PrintMacAddr(PBYTE Mac)
146 {
147     static TCHAR MacAddr[20];
148 
149     _stprintf(MacAddr, _T("%02x-%02x-%02x-%02x-%02x-%02x"),
150         Mac[0], Mac[1], Mac[2], Mac[3], Mac[4],  Mac[5]);
151 
152     return MacAddr;
153 }
154 
155 
156 VOID DoFormatMessage(LONG ErrorCode)
157 {
158     LPVOID lpMsgBuf;
159     //DWORD ErrorCode;
160 
161     if (ErrorCode == 0)
162         ErrorCode = GetLastError();
163 
164     if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
165                         FORMAT_MESSAGE_FROM_SYSTEM |
166                         FORMAT_MESSAGE_IGNORE_INSERTS,
167                       NULL,
168                       ErrorCode,
169                       MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
170                       (LPTSTR) &lpMsgBuf,
171                       0,
172                       NULL))
173     {
174         _tprintf(_T("%s"), (LPTSTR)lpMsgBuf);
175         LocalFree(lpMsgBuf);
176     }
177 }
178 
179 
180 LPTSTR GetConnectionType(LPTSTR lpClass)
181 {
182     HKEY hKey = NULL;
183     LPTSTR ConType = NULL;
184     LPTSTR ConTypeTmp = NULL;
185     TCHAR Path[256];
186     LPTSTR PrePath  = _T("SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\");
187     LPTSTR PostPath = _T("\\Connection");
188     DWORD PathSize;
189     DWORD dwType;
190     DWORD dwDataSize;
191 
192     /* don't overflow the buffer */
193     PathSize = lstrlen(PrePath) + lstrlen(lpClass) + lstrlen(PostPath) + 1;
194     if (PathSize >= 255)
195         return NULL;
196 
197     wsprintf(Path, _T("%s%s%s"), PrePath, lpClass, PostPath);
198 
199     if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
200                      Path,
201                      0,
202                      KEY_READ,
203                      &hKey) == ERROR_SUCCESS)
204     {
205         if (RegQueryValueEx(hKey,
206                             _T("Name"),
207                             NULL,
208                             &dwType,
209                             NULL,
210                             &dwDataSize) == ERROR_SUCCESS)
211         {
212             ConTypeTmp = (LPTSTR)HeapAlloc(ProcessHeap,
213                                            0,
214                                            dwDataSize);
215 
216             if (ConTypeTmp == NULL)
217                 return NULL;
218 
219             ConType = (LPTSTR)HeapAlloc(ProcessHeap,
220                                         0,
221                                         dwDataSize);
222 
223             if (ConType == NULL)
224             {
225                 HeapFree(ProcessHeap, 0, ConTypeTmp);
226                 return NULL;
227             }
228 
229             if (RegQueryValueEx(hKey,
230                                 _T("Name"),
231                                 NULL,
232                                 &dwType,
233                                 (PBYTE)ConTypeTmp,
234                                 &dwDataSize) != ERROR_SUCCESS)
235             {
236                 HeapFree(ProcessHeap,
237                          0,
238                          ConType);
239 
240                 ConType = NULL;
241             }
242 
243             if (ConType)
244                 CharToOem(ConTypeTmp, ConType);
245             HeapFree(ProcessHeap, 0, ConTypeTmp);
246         }
247     }
248 
249     if (hKey != NULL)
250         RegCloseKey(hKey);
251 
252     return ConType;
253 }
254 
255 
256 LPTSTR GetConnectionDescription(LPTSTR lpClass)
257 {
258     HKEY hBaseKey = NULL;
259     HKEY hClassKey = NULL;
260     LPTSTR lpKeyClass = NULL;
261     LPTSTR lpConDesc = NULL;
262     LPTSTR lpPath = NULL;
263     TCHAR szPrePath[] = _T("SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002bE10318}\\");
264     DWORD dwType;
265     DWORD dwDataSize;
266     INT i;
267 
268     if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
269                      szPrePath,
270                      0,
271                      KEY_READ,
272                      &hBaseKey) != ERROR_SUCCESS)
273     {
274         return NULL;
275     }
276 
277     for (i = 0; ; i++)
278     {
279         DWORD PathSize;
280         LONG Status;
281         TCHAR szName[10];
282         DWORD NameLen = 9;
283 
284         if ((Status = RegEnumKeyEx(hBaseKey,
285                                    i,
286                                    szName,
287                                    &NameLen,
288                                    NULL,
289                                    NULL,
290                                    NULL,
291                                    NULL)) != ERROR_SUCCESS)
292         {
293             if (Status == ERROR_NO_MORE_ITEMS)
294             {
295                 DoFormatMessage(Status);
296                 lpConDesc = NULL;
297                 goto CLEANUP;
298             }
299             else
300                 continue;
301         }
302 
303         PathSize = lstrlen(szPrePath) + lstrlen(szName) + 1;
304         lpPath = (LPTSTR)HeapAlloc(ProcessHeap,
305                                    0,
306                                    PathSize * sizeof(TCHAR));
307         if (lpPath == NULL)
308             goto CLEANUP;
309 
310         wsprintf(lpPath, _T("%s%s"), szPrePath, szName);
311 
312         //MessageBox(NULL, lpPath, NULL, 0);
313 
314         if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
315                          lpPath,
316                          0,
317                          KEY_READ,
318                          &hClassKey) != ERROR_SUCCESS)
319         {
320             goto CLEANUP;
321         }
322 
323         HeapFree(ProcessHeap, 0, lpPath);
324         lpPath = NULL;
325 
326         if (RegQueryValueEx(hClassKey,
327                             _T("NetCfgInstanceId"),
328                             NULL,
329                             &dwType,
330                             NULL,
331                             &dwDataSize) == ERROR_SUCCESS)
332         {
333             lpKeyClass = (LPTSTR)HeapAlloc(ProcessHeap,
334                                            0,
335                                            dwDataSize);
336             if (lpKeyClass == NULL)
337                 goto CLEANUP;
338 
339             if (RegQueryValueEx(hClassKey,
340                                 _T("NetCfgInstanceId"),
341                                 NULL,
342                                 &dwType,
343                                 (PBYTE)lpKeyClass,
344                                 &dwDataSize) != ERROR_SUCCESS)
345             {
346                 HeapFree(ProcessHeap, 0, lpKeyClass);
347                 lpKeyClass = NULL;
348                 continue;
349             }
350         }
351         else
352             continue;
353 
354         if (!lstrcmp(lpClass, lpKeyClass))
355         {
356             HeapFree(ProcessHeap, 0, lpKeyClass);
357             lpKeyClass = NULL;
358 
359             if (RegQueryValueEx(hClassKey,
360                                 _T("DriverDesc"),
361                                 NULL,
362                                 &dwType,
363                                 NULL,
364                                 &dwDataSize) == ERROR_SUCCESS)
365             {
366                 lpConDesc = (LPTSTR)HeapAlloc(ProcessHeap,
367                                               0,
368                                               dwDataSize);
369                 if (lpConDesc == NULL)
370                     goto CLEANUP;
371 
372                 if (RegQueryValueEx(hClassKey,
373                                     _T("DriverDesc"),
374                                     NULL,
375                                     &dwType,
376                                     (PBYTE)lpConDesc,
377                                     &dwDataSize) != ERROR_SUCCESS)
378                 {
379                     HeapFree(ProcessHeap, 0, lpConDesc);
380                     lpConDesc = NULL;
381                     goto CLEANUP;
382                 }
383             }
384             else
385             {
386                 lpConDesc = NULL;
387             }
388 
389             break;
390         }
391     }
392 
393 CLEANUP:
394     if (hBaseKey != NULL)
395         RegCloseKey(hBaseKey);
396     if (hClassKey != NULL)
397         RegCloseKey(hClassKey);
398     if (lpPath != NULL)
399         HeapFree(ProcessHeap, 0, lpPath);
400     if (lpKeyClass != NULL)
401         HeapFree(ProcessHeap, 0, lpKeyClass);
402 
403     return lpConDesc;
404 }
405 
406 
407 VOID ShowInfo(BOOL bAll)
408 {
409     MIB_IFROW mibEntry;
410     PIP_ADAPTER_INFO pAdapterInfo = NULL;
411     PIP_ADAPTER_INFO pAdapter = NULL;
412     ULONG adaptOutBufLen = 0;
413     PFIXED_INFO pFixedInfo = NULL;
414     ULONG netOutBufLen = 0;
415     PIP_PER_ADAPTER_INFO pPerAdapterInfo = NULL;
416     ULONG ulPerAdapterInfoLength = 0;
417     ULONG ret = 0;
418 
419     /* call GetAdaptersInfo to obtain the adapter info */
420     ret = GetAdaptersInfo(pAdapterInfo, &adaptOutBufLen);
421     if (ret == ERROR_BUFFER_OVERFLOW)
422     {
423         pAdapterInfo = (IP_ADAPTER_INFO *)HeapAlloc(ProcessHeap, 0, adaptOutBufLen);
424         if (pAdapterInfo == NULL)
425             return;
426 
427         ret = GetAdaptersInfo(pAdapterInfo, &adaptOutBufLen);
428         if (ret != NO_ERROR)
429         {
430             DoFormatMessage(0);
431             HeapFree(ProcessHeap, 0, pAdapterInfo);
432             return;
433         }
434     }
435     else
436     {
437         if (ret != ERROR_NO_DATA)
438         {
439             DoFormatMessage(0);
440             return;
441         }
442     }
443 
444     /* call GetNetworkParams to obtain the network info */
445     if (GetNetworkParams(pFixedInfo, &netOutBufLen) == ERROR_BUFFER_OVERFLOW)
446     {
447         pFixedInfo = (FIXED_INFO *)HeapAlloc(ProcessHeap, 0, netOutBufLen);
448         if (pFixedInfo == NULL)
449         {
450             if (pAdapterInfo)
451                 HeapFree(ProcessHeap, 0, pAdapterInfo);
452             return;
453         }
454         if (GetNetworkParams(pFixedInfo, &netOutBufLen) != NO_ERROR)
455         {
456             DoFormatMessage(0);
457             if (pAdapterInfo)
458                 HeapFree(ProcessHeap, 0, pAdapterInfo);
459             HeapFree(ProcessHeap, 0, pFixedInfo);
460             return;
461         }
462     }
463     else
464     {
465         if (pAdapterInfo)
466             HeapFree(ProcessHeap, 0, pAdapterInfo);
467         DoFormatMessage(0);
468         return;
469     }
470 
471     pAdapter = pAdapterInfo;
472 
473     _tprintf(_T("\nReactOS IP Configuration\n\n"));
474     if (bAll)
475     {
476         _tprintf(_T("\tHost Name . . . . . . . . . . . . : %s\n"), pFixedInfo->HostName);
477         _tprintf(_T("\tPrimary DNS Suffix. . . . . . . . : \n"));
478         _tprintf(_T("\tNode Type . . . . . . . . . . . . : %s\n"), GetNodeTypeName(pFixedInfo->NodeType));
479         if (pFixedInfo->EnableRouting)
480             _tprintf(_T("\tIP Routing Enabled. . . . . . . . : Yes\n"));
481         else
482             _tprintf(_T("\tIP Routing Enabled. . . . . . . . : No\n"));
483         if (pAdapter && pAdapter->HaveWins)
484             _tprintf(_T("\tWINS Proxy enabled. . . . . . . . : Yes\n"));
485         else
486             _tprintf(_T("\tWINS Proxy enabled. . . . . . . . : No\n"));
487         _tprintf(_T("\tDNS Suffix Search List. . . . . . : %s\n"), pFixedInfo->DomainName);
488     }
489 
490     while (pAdapter)
491     {
492         LPTSTR IntType, myConType;
493         BOOLEAN bConnected = TRUE;
494 
495         mibEntry.dwIndex = pAdapter->Index;
496         GetIfEntry(&mibEntry);
497 
498         IntType = GetInterfaceTypeName(pAdapter->Type);
499         myConType = GetConnectionType(pAdapter->AdapterName);
500 
501         _tprintf(_T("\n%s %s: \n\n"), IntType , myConType);
502 
503         if (myConType != NULL) HeapFree(ProcessHeap, 0, myConType);
504 
505         if (GetPerAdapterInfo(pAdapter->Index, pPerAdapterInfo, &ulPerAdapterInfoLength) == ERROR_BUFFER_OVERFLOW)
506         {
507             pPerAdapterInfo = (PIP_PER_ADAPTER_INFO)HeapAlloc(ProcessHeap, 0, ulPerAdapterInfoLength);
508             if (pPerAdapterInfo != NULL)
509             {
510                 GetPerAdapterInfo(pAdapter->Index, pPerAdapterInfo, &ulPerAdapterInfoLength);
511             }
512         }
513 
514         /* check if the adapter is connected to the media */
515         if (mibEntry.dwOperStatus != MIB_IF_OPER_STATUS_CONNECTED && mibEntry.dwOperStatus != MIB_IF_OPER_STATUS_OPERATIONAL)
516         {
517             bConnected = FALSE;
518             _tprintf(_T("\tMedia State . . . . . . . . . . . : Media disconnected\n"));
519         }
520         else
521         {
522             _tprintf(_T("\tConnection-specific DNS Suffix. . : %s\n"), pFixedInfo->DomainName);
523         }
524 
525         if (bAll)
526         {
527             LPTSTR lpDesc = GetConnectionDescription(pAdapter->AdapterName);
528             _tprintf(_T("\tDescription . . . . . . . . . . . : %s\n"), lpDesc);
529             HeapFree(ProcessHeap, 0, lpDesc);
530             _tprintf(_T("\tPhysical Address. . . . . . . . . : %s\n"), PrintMacAddr(pAdapter->Address));
531             if (bConnected)
532             {
533                 if (pAdapter->DhcpEnabled)
534                 {
535                     _tprintf(_T("\tDHCP Enabled. . . . . . . . . . . : Yes\n"));
536                     if (pPerAdapterInfo != NULL)
537                     {
538                         if (pPerAdapterInfo->AutoconfigEnabled)
539                             _tprintf(_T("\tAutoconfiguration Enabled . . . . : Yes\n"));
540                         else
541                             _tprintf(_T("\tAutoconfiguration Enabled . . . . : No\n"));
542                     }
543                 }
544                 else
545                 {
546                     _tprintf(_T("\tDHCP Enabled. . . . . . . . . . . : No\n"));
547                 }
548             }
549         }
550 
551         if (!bConnected)
552         {
553             pAdapter = pAdapter->Next;
554             continue;
555         }
556 
557         _tprintf(_T("\tIP Address. . . . . . . . . . . . : %s\n"), pAdapter->IpAddressList.IpAddress.String);
558         _tprintf(_T("\tSubnet Mask . . . . . . . . . . . : %s\n"), pAdapter->IpAddressList.IpMask.String);
559         if (pAdapter->GatewayList.IpAddress.String[0] != '0')
560             _tprintf(_T("\tDefault Gateway . . . . . . . . . : %s\n"), pAdapter->GatewayList.IpAddress.String);
561         else
562             _tprintf(_T("\tDefault Gateway . . . . . . . . . :\n"));
563 
564         if (bAll)
565         {
566             PIP_ADDR_STRING pIPAddr;
567 
568             if (pAdapter->DhcpEnabled)
569                _tprintf(_T("\tDHCP Server . . . . . . . . . . . : %s\n"), pAdapter->DhcpServer.IpAddress.String);
570 
571             _tprintf(_T("\tDNS Servers . . . . . . . . . . . : "));
572             _tprintf(_T("%s\n"), pFixedInfo->DnsServerList.IpAddress.String);
573             pIPAddr = pFixedInfo->DnsServerList.Next;
574             while (pIPAddr)
575             {
576                 _tprintf(_T("\t\t\t\t\t    %s\n"), pIPAddr ->IpAddress.String );
577                 pIPAddr = pIPAddr->Next;
578             }
579 
580             if (pAdapter->HaveWins)
581             {
582                 _tprintf(_T("\tPrimary WINS Server . . . . . . . : %s\n"), pAdapter->PrimaryWinsServer.IpAddress.String);
583                 _tprintf(_T("\tSecondary WINS Server . . . . . . : %s\n"), pAdapter->SecondaryWinsServer.IpAddress.String);
584             }
585 
586             if (pAdapter->DhcpEnabled && _tcscmp(pAdapter->DhcpServer.IpAddress.String, _T("255.255.255.255")))
587             {
588                 _tprintf(_T("\tLease Obtained. . . . . . . . . . : %s"), _tasctime(localtime(&pAdapter->LeaseObtained)));
589                 _tprintf(_T("\tLease Expires . . . . . . . . . . : %s"), _tasctime(localtime(&pAdapter->LeaseExpires)));
590             }
591         }
592         _tprintf(_T("\n"));
593 
594         HeapFree(ProcessHeap, 0, pPerAdapterInfo);
595         pPerAdapterInfo = NULL;
596 
597         pAdapter = pAdapter->Next;
598     }
599 
600     HeapFree(ProcessHeap, 0, pFixedInfo);
601     if (pAdapterInfo)
602         HeapFree(ProcessHeap, 0, pAdapterInfo);
603 }
604 
605 VOID Release(LPTSTR Index)
606 {
607     IP_ADAPTER_INDEX_MAP AdapterInfo;
608     DWORD ret;
609     DWORD i;
610 
611     /* if interface is not given, query GetInterfaceInfo */
612     if (Index == NULL)
613     {
614         PIP_INTERFACE_INFO pInfo = NULL;
615         ULONG ulOutBufLen = 0;
616 
617         if (GetInterfaceInfo(pInfo, &ulOutBufLen) == ERROR_INSUFFICIENT_BUFFER)
618         {
619             pInfo = (IP_INTERFACE_INFO *)HeapAlloc(ProcessHeap, 0, ulOutBufLen);
620             if (pInfo == NULL)
621                 return;
622 
623             if (GetInterfaceInfo(pInfo, &ulOutBufLen) == NO_ERROR )
624             {
625                 for (i = 0; i < pInfo->NumAdapters; i++)
626                 {
627                     CopyMemory(&AdapterInfo, &pInfo->Adapter[i], sizeof(IP_ADAPTER_INDEX_MAP));
628                     _tprintf(_T("name - %ls\n"), pInfo->Adapter[i].Name);
629 
630                     /* Call IpReleaseAddress to release the IP address on the specified adapter. */
631                     if ((ret = IpReleaseAddress(&AdapterInfo)) != NO_ERROR)
632                     {
633                         _tprintf(_T("\nAn error occured while releasing interface %ls : \n"), AdapterInfo.Name);
634                         DoFormatMessage(ret);
635                     }
636                 }
637 
638                 HeapFree(ProcessHeap, 0, pInfo);
639             }
640             else
641             {
642                 DoFormatMessage(0);
643                 HeapFree(ProcessHeap, 0, pInfo);
644                 return;
645             }
646         }
647         else
648         {
649             DoFormatMessage(0);
650             return;
651         }
652     }
653     else
654     {
655         ;
656         /* FIXME:
657          * we need to be able to release connections by name with support for globbing
658          * i.e. ipconfig /release Eth* will release all cards starting with Eth...
659          *      ipconfig /release *con* will release all cards with 'con' in their name
660          */
661     }
662 }
663 
664 
665 
666 
667 VOID Renew(LPTSTR Index)
668 {
669     IP_ADAPTER_INDEX_MAP AdapterInfo;
670     DWORD i;
671 
672     /* if interface is not given, query GetInterfaceInfo */
673     if (Index == NULL)
674     {
675         PIP_INTERFACE_INFO pInfo;
676         ULONG ulOutBufLen = 0;
677 
678         pInfo = (IP_INTERFACE_INFO *)HeapAlloc(ProcessHeap, 0, sizeof(IP_INTERFACE_INFO));
679         if (pInfo == NULL)
680         {
681             _tprintf(_T("memory allocation error"));
682             return;
683         }
684 
685         /* Make an initial call to GetInterfaceInfo to get
686          * the necessary size into the ulOutBufLen variable */
687         if (GetInterfaceInfo(pInfo, &ulOutBufLen) == ERROR_INSUFFICIENT_BUFFER)
688         {
689             HeapFree(ProcessHeap, 0, pInfo);
690             pInfo = (IP_INTERFACE_INFO *)HeapAlloc(ProcessHeap, 0, ulOutBufLen);
691             if (pInfo == NULL)
692             {
693                 _tprintf(_T("memory allocation error"));
694                 return;
695             }
696         }
697 
698         /* Make a second call to GetInterfaceInfo to get the actual data we want */
699         if (GetInterfaceInfo(pInfo, &ulOutBufLen) == NO_ERROR)
700         {
701             for (i = 0; i < pInfo->NumAdapters; i++)
702             {
703                 CopyMemory(&AdapterInfo, &pInfo->Adapter[i], sizeof(IP_ADAPTER_INDEX_MAP));
704                 _tprintf(_T("name - %ls\n"), pInfo->Adapter[i].Name);
705 
706                 /* Call IpRenewAddress to renew the IP address on the specified adapter. */
707                 if (IpRenewAddress(&AdapterInfo) != NO_ERROR)
708                 {
709                     _tprintf(_T("\nAn error occured while renew interface %s : "), _T("*name*"));
710                     DoFormatMessage(0);
711                 }
712             }
713         }
714         else
715         {
716             _tprintf(_T("\nGetInterfaceInfo failed : "));
717             DoFormatMessage(0);
718         }
719 
720         HeapFree(ProcessHeap, 0, pInfo);
721     }
722     else
723     {
724         ;
725         /* FIXME:
726          * we need to be able to renew connections by name with support for globbing
727          * i.e. ipconfig /renew Eth* will renew all cards starting with Eth...
728          *      ipconfig /renew *con* will renew all cards with 'con' in their name
729          */
730     }
731 }
732 
733 VOID
734 FlushDns(VOID)
735 {
736     _tprintf(_T("\nReactOS IP Configuration\n\n"));
737 
738     if (DnsFlushResolverCache())
739         _tprintf(_T("The DNS Resolver Cache has been deleted.\n"));
740     else
741         DoFormatMessage(GetLastError());
742 }
743 
744 
745 static
746 VOID
747 DisplayDnsRecord(
748     PWSTR pszName,
749     WORD wType)
750 {
751     PDNS_RECORDW pQueryResults = NULL, pThisRecord, pNextRecord;
752     WCHAR szBuffer[48];
753     IN_ADDR Addr4;
754     IN6_ADDR Addr6;
755     DNS_STATUS Status;
756 
757     pQueryResults = NULL;
758     Status = DnsQuery_W(pszName,
759                         wType,
760                         DNS_QUERY_NO_WIRE_QUERY,
761                         NULL,
762                         (PDNS_RECORD *)&pQueryResults,
763                         NULL);
764     if (Status != ERROR_SUCCESS)
765     {
766 #if 0
767         if (wType != 0)
768         {
769             _tprintf(_T("\t%S\n"), pszName);
770             _tprintf(_T("\t----------------------------------------\n"));
771             _tprintf(_T("\tNo records of type %hu\n\n"), wType);
772         }
773 #endif
774         return;
775     }
776 
777     _tprintf(_T("\t%S\n"), pszName);
778     _tprintf(_T("\t----------------------------------------\n"));
779 
780     pThisRecord = pQueryResults;
781     while (pThisRecord != NULL)
782     {
783         pNextRecord = pThisRecord->pNext;
784 
785         _tprintf(_T("\tRecord Name . . . . . : %S\n"), pThisRecord->pName);
786         _tprintf(_T("\tRecord Type . . . . . : %hu\n"), pThisRecord->wType);
787         _tprintf(_T("\tTime To Live. . . . . : %lu\n"), pThisRecord->dwTtl);
788         _tprintf(_T("\tData Length . . . . . : %hu\n"), pThisRecord->wDataLength);
789 
790         switch (pThisRecord->Flags.S.Section)
791         {
792             case DnsSectionQuestion:
793                 _tprintf(_T("\tSection . . . . . . . : Question\n"));
794                 break;
795 
796             case DnsSectionAnswer:
797                 _tprintf(_T("\tSection . . . . . . . : Answer\n"));
798                 break;
799 
800             case DnsSectionAuthority:
801                 _tprintf(_T("\tSection . . . . . . . : Authority\n"));
802                 break;
803 
804             case DnsSectionAdditional:
805                 _tprintf(_T("\tSection . . . . . . . : Additional\n"));
806                 break;
807         }
808 
809         switch (pThisRecord->wType)
810         {
811             case DNS_TYPE_A:
812                 Addr4.S_un.S_addr = pThisRecord->Data.A.IpAddress;
813                 RtlIpv4AddressToStringW(&Addr4, szBuffer);
814                 _tprintf(_T("\tA (Host) Record . . . : %S\n"), szBuffer);
815                 break;
816 
817             case DNS_TYPE_PTR:
818                 _tprintf(_T("\tPTR Record. . . . . . : %S\n"), pThisRecord->Data.PTR.pNameHost);
819                 break;
820 
821             case DNS_TYPE_NS:
822                 _tprintf(_T("\tNS Record . . . . . . : %S\n"), pThisRecord->Data.NS.pNameHost);
823                 break;
824 
825             case DNS_TYPE_CNAME:
826                 _tprintf(_T("\tCNAME Record. . . . . : %S\n"), pThisRecord->Data.CNAME.pNameHost);
827                 break;
828 
829             case DNS_TYPE_AAAA:
830                 RtlCopyMemory(&Addr6, &pThisRecord->Data.AAAA.Ip6Address, sizeof(IN6_ADDR));
831                 RtlIpv6AddressToStringW(&Addr6, szBuffer);
832                 _tprintf(_T("\tAAAA Record . . . . . : %S\n"), szBuffer);
833                 break;
834         }
835         _tprintf(_T("\n\n"));
836 
837         pThisRecord = pNextRecord;
838     }
839 
840     DnsRecordListFree((PDNS_RECORD)pQueryResults, DnsFreeRecordList);
841 }
842 
843 
844 VOID
845 DisplayDns(VOID)
846 {
847     PDNS_CACHE_ENTRY DnsEntry = NULL, pThisEntry, pNextEntry;
848 
849     _tprintf(_T("\nReactOS IP Configuration\n\n"));
850 
851     if (!DnsGetCacheDataTable(&DnsEntry))
852     {
853         DoFormatMessage(GetLastError());
854         return;
855     }
856 
857     if (DnsEntry == NULL)
858         return;
859 
860     pThisEntry = DnsEntry;
861     while (pThisEntry != NULL)
862     {
863         pNextEntry = pThisEntry->pNext;
864 
865         DisplayDnsRecord(pThisEntry->pszName, pThisEntry->wType1);
866         if (pThisEntry->wType2 != 0)
867             DisplayDnsRecord(pThisEntry->pszName, pThisEntry->wType2);
868 
869         if (pThisEntry->pszName)
870             LocalFree(pThisEntry->pszName);
871         LocalFree(pThisEntry);
872 
873         pThisEntry = pNextEntry;
874     }
875 }
876 
877 VOID Usage(VOID)
878 {
879     HRSRC hRes;
880     LPTSTR lpUsage;
881     DWORD Size;
882 
883     LPTSTR lpName = (LPTSTR)MAKEINTRESOURCE((IDS_USAGE >> 4) + 1);
884 
885     hRes = FindResource(hInstance,
886                         lpName,
887                         RT_STRING);
888     if (hRes != NULL)
889     {
890         if ((Size = SizeofResource(hInstance,
891                                    hRes)))
892         {
893             lpUsage = (LPTSTR)HeapAlloc(ProcessHeap,
894                                         0,
895                                         Size);
896             if (lpUsage == NULL)
897                 return;
898 
899             if (LoadStringAndOem(hInstance,
900                            IDS_USAGE,
901                            lpUsage,
902                            Size))
903             {
904                 _tprintf(_T("%s"), lpUsage);
905             }
906 
907             HeapFree(ProcessHeap, 0, lpUsage);
908         }
909     }
910 }
911 
912 int main(int argc, char *argv[])
913 {
914     BOOL DoUsage=FALSE;
915     BOOL DoAll=FALSE;
916     BOOL DoRelease=FALSE;
917     BOOL DoRenew=FALSE;
918     BOOL DoFlushdns=FALSE;
919     BOOL DoRegisterdns=FALSE;
920     BOOL DoDisplaydns=FALSE;
921     BOOL DoShowclassid=FALSE;
922     BOOL DoSetclassid=FALSE;
923 
924     hInstance = GetModuleHandle(NULL);
925     ProcessHeap = GetProcessHeap();
926 
927     /* Parse command line for options we have been given. */
928     if ((argc > 1) && (argv[1][0]=='/' || argv[1][0]=='-'))
929     {
930         if (!_tcsicmp(&argv[1][1], _T("?")))
931         {
932             DoUsage = TRUE;
933         }
934         else if (!_tcsnicmp(&argv[1][1], _T("ALL"), _tcslen(&argv[1][1])))
935         {
936            DoAll = TRUE;
937         }
938         else if (!_tcsnicmp(&argv[1][1], _T("RELEASE"), _tcslen(&argv[1][1])))
939         {
940             DoRelease = TRUE;
941         }
942         else if (!_tcsnicmp(&argv[1][1], _T("RENEW"), _tcslen(&argv[1][1])))
943         {
944             DoRenew = TRUE;
945         }
946         else if (!_tcsnicmp(&argv[1][1], _T("FLUSHDNS"), _tcslen(&argv[1][1])))
947         {
948             DoFlushdns = TRUE;
949         }
950         else if (!_tcsnicmp(&argv[1][1], _T("FLUSHREGISTERDNS"), _tcslen(&argv[1][1])))
951         {
952             DoRegisterdns = TRUE;
953         }
954         else if (!_tcsnicmp(&argv[1][1], _T("DISPLAYDNS"), _tcslen(&argv[1][1])))
955         {
956             DoDisplaydns = TRUE;
957         }
958         else if (!_tcsnicmp(&argv[1][1], _T("SHOWCLASSID"), _tcslen(&argv[1][1])))
959         {
960             DoShowclassid = TRUE;
961         }
962         else if (!_tcsnicmp(&argv[1][1], _T("SETCLASSID"), _tcslen(&argv[1][1])))
963         {
964             DoSetclassid = TRUE;
965         }
966     }
967 
968     switch (argc)
969     {
970         case 1:  /* Default behaviour if no options are given*/
971             ShowInfo(FALSE);
972             break;
973         case 2:  /* Process all the options that take no parameters */
974             if (DoUsage)
975                 Usage();
976             else if (DoAll)
977                 ShowInfo(TRUE);
978             else if (DoRelease)
979                 Release(NULL);
980             else if (DoRenew)
981                 Renew(NULL);
982             else if (DoFlushdns)
983                 FlushDns();
984             else if (DoRegisterdns)
985                 _tprintf(_T("\nSorry /registerdns is not implemented yet\n"));
986             else if (DoDisplaydns)
987                 DisplayDns();
988             else
989                 Usage();
990             break;
991         case 3: /* Process all the options that can have 1 parameter */
992             if (DoRelease)
993                 _tprintf(_T("\nSorry /release [adapter] is not implemented yet\n"));
994                 //Release(argv[2]);
995             else if (DoRenew)
996                 _tprintf(_T("\nSorry /renew [adapter] is not implemented yet\n"));
997             else if (DoShowclassid)
998                 _tprintf(_T("\nSorry /showclassid adapter is not implemented yet\n"));
999             else if (DoSetclassid)
1000                 _tprintf(_T("\nSorry /setclassid adapter is not implemented yet\n"));
1001             else
1002                 Usage();
1003             break;
1004         case 4:  /* Process all the options that can have 2 parameters */
1005             if (DoSetclassid)
1006                 _tprintf(_T("\nSorry /setclassid adapter [classid]is not implemented yet\n"));
1007             else
1008                 Usage();
1009             break;
1010         default:
1011             Usage();
1012     }
1013 
1014     return 0;
1015 }
1016