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 <winnls.h>
20 #include <winuser.h>
21 #include <winreg.h>
22 #include <stdio.h>
23 #include <tchar.h>
24 #include <time.h>
25 #include <iphlpapi.h>
26 #include <ndk/rtlfuncs.h>
27 #include <inaddr.h>
28 #include <windns.h>
29 #include <windns_undoc.h>
30 
31 #include "resource.h"
32 
33 typedef struct _RECORDTYPE
34 {
35     WORD wRecordType;
36     LPTSTR pszRecordName;
37 } RECORDTYPE, *PRECORDTYPE;
38 
39 #define GUID_LEN 40
40 
41 HINSTANCE hInstance;
42 HANDLE ProcessHeap;
43 
44 RECORDTYPE TypeArray[] =
45 {
46     {DNS_TYPE_ZERO,    _T("ZERO")},
47     {DNS_TYPE_A,       _T("A")},
48     {DNS_TYPE_NS,      _T("NS")},
49     {DNS_TYPE_MD,      _T("MD")},
50     {DNS_TYPE_MF,      _T("MF")},
51     {DNS_TYPE_CNAME,   _T("CNAME")},
52     {DNS_TYPE_SOA,     _T("SOA")},
53     {DNS_TYPE_MB,      _T("MB")},
54     {DNS_TYPE_MG,      _T("MG")},
55     {DNS_TYPE_MR,      _T("MR")},
56     {DNS_TYPE_NULL,    _T("NULL")},
57     {DNS_TYPE_WKS,     _T("WKS")},
58     {DNS_TYPE_PTR,     _T("PTR")},
59     {DNS_TYPE_HINFO,   _T("HINFO")},
60     {DNS_TYPE_MINFO,   _T("MINFO")},
61     {DNS_TYPE_MX,      _T("MX")},
62     {DNS_TYPE_TEXT,    _T("TXT")},
63     {DNS_TYPE_RP,      _T("RP")},
64     {DNS_TYPE_AFSDB,   _T("AFSDB")},
65     {DNS_TYPE_X25,     _T("X25")},
66     {DNS_TYPE_ISDN,    _T("ISDN")},
67     {DNS_TYPE_RT,      _T("RT")},
68     {DNS_TYPE_NSAP,    _T("NSAP")},
69     {DNS_TYPE_NSAPPTR, _T("NSAPPTR")},
70     {DNS_TYPE_SIG,     _T("SIG")},
71     {DNS_TYPE_KEY,     _T("KEY")},
72     {DNS_TYPE_PX,      _T("PX")},
73     {DNS_TYPE_GPOS,    _T("GPOS")},
74     {DNS_TYPE_AAAA,    _T("AAAA")},
75     {DNS_TYPE_LOC,     _T("LOC")},
76     {DNS_TYPE_NXT,     _T("NXT")},
77     {DNS_TYPE_EID,     _T("EID")},
78     {DNS_TYPE_NIMLOC,  _T("NIMLOC")},
79     {DNS_TYPE_SRV,     _T("SRV")},
80     {DNS_TYPE_ATMA,    _T("ATMA")},
81     {DNS_TYPE_NAPTR,   _T("NAPTR")},
82     {DNS_TYPE_KX,      _T("KX")},
83     {DNS_TYPE_CERT,    _T("CERT")},
84     {DNS_TYPE_A6,      _T("A6")},
85     {DNS_TYPE_DNAME,   _T("DNAME")},
86     {DNS_TYPE_SINK,    _T("SINK")},
87     {DNS_TYPE_OPT,     _T("OPT")},
88     {DNS_TYPE_UINFO,   _T("UINFO")},
89     {DNS_TYPE_UID,     _T("UID")},
90     {DNS_TYPE_GID,     _T("GID")},
91     {DNS_TYPE_UNSPEC,  _T("UNSPEC")},
92     {DNS_TYPE_ADDRS,   _T("ADDRS")},
93     {DNS_TYPE_TKEY,    _T("TKEY")},
94     {DNS_TYPE_TSIG,    _T("TSIG")},
95     {DNS_TYPE_IXFR,    _T("IXFR")},
96     {DNS_TYPE_AXFR,    _T("AXFR")},
97     {DNS_TYPE_MAILB,   _T("MAILB")},
98     {DNS_TYPE_MAILA,   _T("MAILA")},
99     {DNS_TYPE_ALL,     _T("ALL")},
100     {0, NULL}
101 };
102 
103 LPTSTR
104 GetRecordTypeName(WORD wType)
105 {
106     static TCHAR szType[8];
107     INT i;
108 
109     for (i = 0; ; i++)
110     {
111          if (TypeArray[i].pszRecordName == NULL)
112              break;
113 
114          if (TypeArray[i].wRecordType == wType)
115              return TypeArray[i].pszRecordName;
116     }
117 
118     _stprintf(szType, _T("%hu"), wType);
119 
120     return szType;
121 }
122 
123 int LoadStringAndOem(HINSTANCE hInst,
124                      UINT uID,
125                      LPTSTR szNode,
126                      int byteSize)
127 {
128     TCHAR *szTmp;
129     int res;
130 
131     szTmp = (LPTSTR)HeapAlloc(ProcessHeap, 0, byteSize);
132     if (szTmp == NULL)
133     {
134         return 0;
135     }
136 
137     res = LoadString(hInst, uID, szTmp, byteSize);
138     CharToOem(szTmp, szNode);
139     HeapFree(ProcessHeap, 0, szTmp);
140     return res;
141 }
142 
143 LPTSTR GetNodeTypeName(UINT NodeType)
144 {
145     static TCHAR szNode[14];
146 
147     switch (NodeType)
148     {
149         case 1:
150             if (!LoadStringAndOem(hInstance, IDS_BCAST, szNode,  sizeof(szNode)))
151                 return NULL;
152             break;
153 
154         case 2:
155             if (!LoadStringAndOem(hInstance, IDS_P2P, szNode,  sizeof(szNode)))
156                 return NULL;
157             break;
158 
159         case 4:
160             if (!LoadStringAndOem(hInstance, IDS_MIXED, szNode,  sizeof(szNode)))
161                 return NULL;
162             break;
163 
164         case 8:
165             if (!LoadStringAndOem(hInstance, IDS_HYBRID, szNode,  sizeof(szNode)))
166                 return NULL;
167             break;
168 
169         default :
170             if (!LoadStringAndOem(hInstance, IDS_UNKNOWN, szNode,  sizeof(szNode)))
171                 return NULL;
172             break;
173     }
174 
175     return szNode;
176 }
177 
178 
179 LPTSTR GetInterfaceTypeName(UINT InterfaceType)
180 {
181     static TCHAR szIntType[25];
182 
183     switch (InterfaceType)
184     {
185         case MIB_IF_TYPE_OTHER:
186             if (!LoadStringAndOem(hInstance, IDS_OTHER, szIntType, sizeof(szIntType)))
187                 return NULL;
188             break;
189 
190         case MIB_IF_TYPE_ETHERNET:
191             if (!LoadStringAndOem(hInstance, IDS_ETH, szIntType, sizeof(szIntType)))
192                 return NULL;
193             break;
194 
195         case MIB_IF_TYPE_TOKENRING:
196             if (!LoadStringAndOem(hInstance, IDS_TOKEN, szIntType, sizeof(szIntType)))
197                 return NULL;
198             break;
199 
200         case MIB_IF_TYPE_FDDI:
201             if (!LoadStringAndOem(hInstance, IDS_FDDI, szIntType, sizeof(szIntType)))
202                 return NULL;
203             break;
204 
205         case MIB_IF_TYPE_PPP:
206             if (!LoadStringAndOem(hInstance, IDS_PPP, szIntType, sizeof(szIntType)))
207                 return NULL;
208             break;
209 
210         case MIB_IF_TYPE_LOOPBACK:
211             if (!LoadStringAndOem(hInstance, IDS_LOOP, szIntType, sizeof(szIntType)))
212                 return NULL;
213             break;
214 
215         case MIB_IF_TYPE_SLIP:
216             if (!LoadStringAndOem(hInstance, IDS_SLIP, szIntType, sizeof(szIntType)))
217                 return NULL;
218             break;
219 
220         default:
221             if (!LoadStringAndOem(hInstance, IDS_UNKNOWN, szIntType, sizeof(szIntType)))
222                 return NULL;
223             break;
224     }
225 
226     return szIntType;
227 }
228 
229 
230 /* print MAC address */
231 PTCHAR PrintMacAddr(PBYTE Mac)
232 {
233     static TCHAR MacAddr[20];
234 
235     _stprintf(MacAddr, _T("%02x-%02x-%02x-%02x-%02x-%02x"),
236         Mac[0], Mac[1], Mac[2], Mac[3], Mac[4],  Mac[5]);
237 
238     return MacAddr;
239 }
240 
241 
242 /* convert time_t to localized string */
243 _Ret_opt_z_ PTSTR timeToStr(_In_ time_t TimeStamp)
244 {
245     struct tm* ptm;
246     SYSTEMTIME SystemTime;
247     INT DateCchSize, TimeCchSize, TotalCchSize, i;
248     PTSTR DateTimeString, psz;
249 
250     /* Convert Unix time to SYSTEMTIME */
251     /* localtime_s may be preferred if available */
252     ptm = localtime(&TimeStamp);
253     if (!ptm)
254     {
255         return NULL;
256     }
257     SystemTime.wYear = ptm->tm_year + 1900;
258     SystemTime.wMonth = ptm->tm_mon + 1;
259     SystemTime.wDay = ptm->tm_mday;
260     SystemTime.wHour = ptm->tm_hour;
261     SystemTime.wMinute = ptm->tm_min;
262     SystemTime.wSecond = ptm->tm_sec;
263 
264     /* Get total size in characters required of buffer */
265     DateCchSize = GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &SystemTime, NULL, NULL, 0);
266     if (!DateCchSize)
267     {
268         return NULL;
269     }
270     TimeCchSize = GetTimeFormat(LOCALE_USER_DEFAULT, 0, &SystemTime, NULL, NULL, 0);
271     if (!TimeCchSize)
272     {
273         return NULL;
274     }
275     /* Two terminating null are included, the first one will be replaced by space */
276     TotalCchSize = DateCchSize + TimeCchSize;
277 
278     /* Allocate buffer and format datetime string */
279     DateTimeString = (PTSTR)HeapAlloc(ProcessHeap, 0, TotalCchSize * sizeof(TCHAR));
280     if (!DateTimeString)
281     {
282         return NULL;
283     }
284 
285     /* Get date string */
286     i = GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &SystemTime, NULL, DateTimeString, TotalCchSize);
287     if (i)
288     {
289         /* Append space and move pointer */
290         DateTimeString[i - 1] = _T(' ');
291         psz = DateTimeString + i;
292         TotalCchSize -= i;
293 
294         /* Get time string */
295         if (GetTimeFormat(LOCALE_USER_DEFAULT, 0, &SystemTime, NULL, psz, TotalCchSize))
296         {
297             return DateTimeString;
298         }
299     }
300 
301     HeapFree(ProcessHeap, 0, DateTimeString);
302     return NULL;
303 }
304 
305 
306 VOID DoFormatMessage(LONG ErrorCode)
307 {
308     LPVOID lpMsgBuf;
309     //DWORD ErrorCode;
310 
311     if (ErrorCode == 0)
312         ErrorCode = GetLastError();
313 
314     if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
315                         FORMAT_MESSAGE_FROM_SYSTEM |
316                         FORMAT_MESSAGE_IGNORE_INSERTS,
317                       NULL,
318                       ErrorCode,
319                       MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
320                       (LPTSTR) &lpMsgBuf,
321                       0,
322                       NULL))
323     {
324         _tprintf(_T("%s"), (LPTSTR)lpMsgBuf);
325         LocalFree(lpMsgBuf);
326     }
327 }
328 
329 
330 LPTSTR GetConnectionType(LPTSTR lpClass)
331 {
332     HKEY hKey = NULL;
333     LPTSTR ConType = NULL;
334     LPTSTR ConTypeTmp = NULL;
335     TCHAR Path[256];
336     LPTSTR PrePath  = _T("SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\");
337     LPTSTR PostPath = _T("\\Connection");
338     DWORD PathSize;
339     DWORD dwType;
340     DWORD dwDataSize;
341 
342     /* don't overflow the buffer */
343     PathSize = lstrlen(PrePath) + lstrlen(lpClass) + lstrlen(PostPath) + 1;
344     if (PathSize >= 255)
345         return NULL;
346 
347     wsprintf(Path, _T("%s%s%s"), PrePath, lpClass, PostPath);
348 
349     if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
350                      Path,
351                      0,
352                      KEY_READ,
353                      &hKey) == ERROR_SUCCESS)
354     {
355         if (RegQueryValueEx(hKey,
356                             _T("Name"),
357                             NULL,
358                             &dwType,
359                             NULL,
360                             &dwDataSize) == ERROR_SUCCESS)
361         {
362             ConTypeTmp = (LPTSTR)HeapAlloc(ProcessHeap,
363                                            0,
364                                            dwDataSize);
365 
366             if (ConTypeTmp == NULL)
367                 return NULL;
368 
369             ConType = (LPTSTR)HeapAlloc(ProcessHeap,
370                                         0,
371                                         dwDataSize);
372 
373             if (ConType == NULL)
374             {
375                 HeapFree(ProcessHeap, 0, ConTypeTmp);
376                 return NULL;
377             }
378 
379             if (RegQueryValueEx(hKey,
380                                 _T("Name"),
381                                 NULL,
382                                 &dwType,
383                                 (PBYTE)ConTypeTmp,
384                                 &dwDataSize) != ERROR_SUCCESS)
385             {
386                 HeapFree(ProcessHeap,
387                          0,
388                          ConType);
389 
390                 ConType = NULL;
391             }
392 
393             if (ConType)
394                 CharToOem(ConTypeTmp, ConType);
395             HeapFree(ProcessHeap, 0, ConTypeTmp);
396         }
397     }
398 
399     if (hKey != NULL)
400         RegCloseKey(hKey);
401 
402     return ConType;
403 }
404 
405 
406 LPTSTR GetConnectionDescription(LPTSTR lpClass)
407 {
408     HKEY hBaseKey = NULL;
409     HKEY hClassKey = NULL;
410     LPTSTR lpKeyClass = NULL;
411     LPTSTR lpConDesc = NULL;
412     LPTSTR lpPath = NULL;
413     TCHAR szPrePath[] = _T("SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002bE10318}\\");
414     DWORD dwType;
415     DWORD dwDataSize;
416     INT i;
417 
418     if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
419                      szPrePath,
420                      0,
421                      KEY_READ,
422                      &hBaseKey) != ERROR_SUCCESS)
423     {
424         return NULL;
425     }
426 
427     for (i = 0; ; i++)
428     {
429         DWORD PathSize;
430         LONG Status;
431         TCHAR szName[10];
432         DWORD NameLen = 9;
433 
434         if ((Status = RegEnumKeyEx(hBaseKey,
435                                    i,
436                                    szName,
437                                    &NameLen,
438                                    NULL,
439                                    NULL,
440                                    NULL,
441                                    NULL)) != ERROR_SUCCESS)
442         {
443             if (Status == ERROR_NO_MORE_ITEMS)
444             {
445                 DoFormatMessage(Status);
446                 lpConDesc = NULL;
447                 goto CLEANUP;
448             }
449             else
450                 continue;
451         }
452 
453         PathSize = lstrlen(szPrePath) + lstrlen(szName) + 1;
454         lpPath = (LPTSTR)HeapAlloc(ProcessHeap,
455                                    0,
456                                    PathSize * sizeof(TCHAR));
457         if (lpPath == NULL)
458             goto CLEANUP;
459 
460         wsprintf(lpPath, _T("%s%s"), szPrePath, szName);
461 
462         //MessageBox(NULL, lpPath, NULL, 0);
463 
464         if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
465                          lpPath,
466                          0,
467                          KEY_READ,
468                          &hClassKey) != ERROR_SUCCESS)
469         {
470             goto CLEANUP;
471         }
472 
473         HeapFree(ProcessHeap, 0, lpPath);
474         lpPath = NULL;
475 
476         if (RegQueryValueEx(hClassKey,
477                             _T("NetCfgInstanceId"),
478                             NULL,
479                             &dwType,
480                             NULL,
481                             &dwDataSize) == ERROR_SUCCESS)
482         {
483             lpKeyClass = (LPTSTR)HeapAlloc(ProcessHeap,
484                                            0,
485                                            dwDataSize);
486             if (lpKeyClass == NULL)
487                 goto CLEANUP;
488 
489             if (RegQueryValueEx(hClassKey,
490                                 _T("NetCfgInstanceId"),
491                                 NULL,
492                                 &dwType,
493                                 (PBYTE)lpKeyClass,
494                                 &dwDataSize) != ERROR_SUCCESS)
495             {
496                 HeapFree(ProcessHeap, 0, lpKeyClass);
497                 lpKeyClass = NULL;
498                 continue;
499             }
500         }
501         else
502             continue;
503 
504         if (!lstrcmp(lpClass, lpKeyClass))
505         {
506             HeapFree(ProcessHeap, 0, lpKeyClass);
507             lpKeyClass = NULL;
508 
509             if (RegQueryValueEx(hClassKey,
510                                 _T("DriverDesc"),
511                                 NULL,
512                                 &dwType,
513                                 NULL,
514                                 &dwDataSize) == ERROR_SUCCESS)
515             {
516                 lpConDesc = (LPTSTR)HeapAlloc(ProcessHeap,
517                                               0,
518                                               dwDataSize);
519                 if (lpConDesc == NULL)
520                     goto CLEANUP;
521 
522                 if (RegQueryValueEx(hClassKey,
523                                     _T("DriverDesc"),
524                                     NULL,
525                                     &dwType,
526                                     (PBYTE)lpConDesc,
527                                     &dwDataSize) != ERROR_SUCCESS)
528                 {
529                     HeapFree(ProcessHeap, 0, lpConDesc);
530                     lpConDesc = NULL;
531                     goto CLEANUP;
532                 }
533             }
534             else
535             {
536                 lpConDesc = NULL;
537             }
538 
539             break;
540         }
541     }
542 
543 CLEANUP:
544     if (hBaseKey != NULL)
545         RegCloseKey(hBaseKey);
546     if (hClassKey != NULL)
547         RegCloseKey(hClassKey);
548     if (lpPath != NULL)
549         HeapFree(ProcessHeap, 0, lpPath);
550     if (lpKeyClass != NULL)
551         HeapFree(ProcessHeap, 0, lpKeyClass);
552 
553     return lpConDesc;
554 }
555 
556 
557 VOID ShowInfo(BOOL bAll)
558 {
559     MIB_IFROW mibEntry;
560     PIP_ADAPTER_INFO pAdapterInfo = NULL;
561     PIP_ADAPTER_INFO pAdapter = NULL;
562     ULONG adaptOutBufLen = 0;
563     PFIXED_INFO pFixedInfo = NULL;
564     ULONG netOutBufLen = 0;
565     PIP_PER_ADAPTER_INFO pPerAdapterInfo = NULL;
566     ULONG ulPerAdapterInfoLength = 0;
567     PSTR pszDomainName = NULL;
568     DWORD dwDomainNameSize = 0;
569     ULONG ret = 0;
570 
571     GetComputerNameExA(ComputerNameDnsDomain,
572                        NULL,
573                        &dwDomainNameSize);
574     if (dwDomainNameSize > 0)
575     {
576         pszDomainName = HeapAlloc(ProcessHeap,
577                                   0,
578                                   dwDomainNameSize * sizeof(TCHAR));
579         if (pszDomainName != NULL)
580             GetComputerNameExA(ComputerNameDnsDomain,
581                                pszDomainName,
582                                &dwDomainNameSize);
583     }
584 
585     /* call GetAdaptersInfo to obtain the adapter info */
586     ret = GetAdaptersInfo(pAdapterInfo, &adaptOutBufLen);
587     if (ret == ERROR_BUFFER_OVERFLOW)
588     {
589         pAdapterInfo = (IP_ADAPTER_INFO *)HeapAlloc(ProcessHeap, 0, adaptOutBufLen);
590         if (pAdapterInfo == NULL)
591             goto done;
592 
593         ret = GetAdaptersInfo(pAdapterInfo, &adaptOutBufLen);
594         if (ret != NO_ERROR)
595         {
596             DoFormatMessage(0);
597             goto done;
598         }
599     }
600     else
601     {
602         if (ret != ERROR_NO_DATA)
603         {
604             DoFormatMessage(0);
605             goto done;
606         }
607     }
608 
609     /* call GetNetworkParams to obtain the network info */
610     if (GetNetworkParams(pFixedInfo, &netOutBufLen) == ERROR_BUFFER_OVERFLOW)
611     {
612         pFixedInfo = (FIXED_INFO *)HeapAlloc(ProcessHeap, 0, netOutBufLen);
613         if (pFixedInfo == NULL)
614         {
615             goto done;
616         }
617         if (GetNetworkParams(pFixedInfo, &netOutBufLen) != NO_ERROR)
618         {
619             DoFormatMessage(0);
620             goto done;
621         }
622     }
623     else
624     {
625         DoFormatMessage(0);
626         goto done;
627     }
628 
629     pAdapter = pAdapterInfo;
630 
631     _tprintf(_T("\nReactOS IP Configuration\n\n"));
632     if (bAll)
633     {
634         _tprintf(_T("\tHost Name . . . . . . . . . . . . : %s\n"), pFixedInfo->HostName);
635         _tprintf(_T("\tPrimary DNS Suffix. . . . . . . . : %s\n"), (pszDomainName != NULL) ? pszDomainName : "");
636         _tprintf(_T("\tNode Type . . . . . . . . . . . . : %s\n"), GetNodeTypeName(pFixedInfo->NodeType));
637         if (pFixedInfo->EnableRouting)
638             _tprintf(_T("\tIP Routing Enabled. . . . . . . . : Yes\n"));
639         else
640             _tprintf(_T("\tIP Routing Enabled. . . . . . . . : No\n"));
641         if (pAdapter && pAdapter->HaveWins)
642             _tprintf(_T("\tWINS Proxy enabled. . . . . . . . : Yes\n"));
643         else
644             _tprintf(_T("\tWINS Proxy enabled. . . . . . . . : No\n"));
645         if (pszDomainName != NULL && pszDomainName[0] != 0)
646         {
647             _tprintf(_T("\tDNS Suffix Search List. . . . . . : %s\n"), pszDomainName);
648             _tprintf(_T("\t                                    %s\n"), pFixedInfo->DomainName);
649         }
650         else
651         {
652             _tprintf(_T("\tDNS Suffix Search List. . . . . . : %s\n"), pFixedInfo->DomainName);
653         }
654     }
655 
656     while (pAdapter)
657     {
658         LPTSTR IntType, myConType;
659         BOOLEAN bConnected = TRUE;
660 
661         mibEntry.dwIndex = pAdapter->Index;
662         GetIfEntry(&mibEntry);
663 
664         IntType = GetInterfaceTypeName(pAdapter->Type);
665         myConType = GetConnectionType(pAdapter->AdapterName);
666 
667         _tprintf(_T("\n%s %s: \n\n"), IntType , myConType);
668 
669         if (myConType != NULL) HeapFree(ProcessHeap, 0, myConType);
670 
671         if (GetPerAdapterInfo(pAdapter->Index, pPerAdapterInfo, &ulPerAdapterInfoLength) == ERROR_BUFFER_OVERFLOW)
672         {
673             pPerAdapterInfo = (PIP_PER_ADAPTER_INFO)HeapAlloc(ProcessHeap, 0, ulPerAdapterInfoLength);
674             if (pPerAdapterInfo != NULL)
675             {
676                 GetPerAdapterInfo(pAdapter->Index, pPerAdapterInfo, &ulPerAdapterInfoLength);
677             }
678         }
679 
680         /* check if the adapter is connected to the media */
681         if (mibEntry.dwOperStatus != MIB_IF_OPER_STATUS_CONNECTED && mibEntry.dwOperStatus != MIB_IF_OPER_STATUS_OPERATIONAL)
682         {
683             bConnected = FALSE;
684             _tprintf(_T("\tMedia State . . . . . . . . . . . : Media disconnected\n"));
685         }
686         else
687         {
688             _tprintf(_T("\tConnection-specific DNS Suffix. . : %s\n"), pFixedInfo->DomainName);
689         }
690 
691         if (bAll)
692         {
693             LPTSTR lpDesc = GetConnectionDescription(pAdapter->AdapterName);
694             _tprintf(_T("\tDescription . . . . . . . . . . . : %s\n"), lpDesc);
695             HeapFree(ProcessHeap, 0, lpDesc);
696             _tprintf(_T("\tPhysical Address. . . . . . . . . : %s\n"), PrintMacAddr(pAdapter->Address));
697             if (bConnected)
698             {
699                 if (pAdapter->DhcpEnabled)
700                 {
701                     _tprintf(_T("\tDHCP Enabled. . . . . . . . . . . : Yes\n"));
702                     if (pPerAdapterInfo != NULL)
703                     {
704                         if (pPerAdapterInfo->AutoconfigEnabled)
705                             _tprintf(_T("\tAutoconfiguration Enabled . . . . : Yes\n"));
706                         else
707                             _tprintf(_T("\tAutoconfiguration Enabled . . . . : No\n"));
708                     }
709                 }
710                 else
711                 {
712                     _tprintf(_T("\tDHCP Enabled. . . . . . . . . . . : No\n"));
713                 }
714             }
715         }
716 
717         if (!bConnected)
718         {
719             pAdapter = pAdapter->Next;
720             continue;
721         }
722 
723         _tprintf(_T("\tIP Address. . . . . . . . . . . . : %s\n"), pAdapter->IpAddressList.IpAddress.String);
724         _tprintf(_T("\tSubnet Mask . . . . . . . . . . . : %s\n"), pAdapter->IpAddressList.IpMask.String);
725         if (pAdapter->GatewayList.IpAddress.String[0] != '0')
726             _tprintf(_T("\tDefault Gateway . . . . . . . . . : %s\n"), pAdapter->GatewayList.IpAddress.String);
727         else
728             _tprintf(_T("\tDefault Gateway . . . . . . . . . :\n"));
729 
730         if (bAll)
731         {
732             PIP_ADDR_STRING pIPAddr;
733 
734             if (pAdapter->DhcpEnabled)
735                _tprintf(_T("\tDHCP Server . . . . . . . . . . . : %s\n"), pAdapter->DhcpServer.IpAddress.String);
736 
737             _tprintf(_T("\tDNS Servers . . . . . . . . . . . : "));
738             _tprintf(_T("%s\n"), pFixedInfo->DnsServerList.IpAddress.String);
739             pIPAddr = pFixedInfo->DnsServerList.Next;
740             while (pIPAddr)
741             {
742                 _tprintf(_T("\t\t\t\t\t    %s\n"), pIPAddr ->IpAddress.String );
743                 pIPAddr = pIPAddr->Next;
744             }
745 
746             if (pAdapter->HaveWins)
747             {
748                 _tprintf(_T("\tPrimary WINS Server . . . . . . . : %s\n"), pAdapter->PrimaryWinsServer.IpAddress.String);
749                 _tprintf(_T("\tSecondary WINS Server . . . . . . : %s\n"), pAdapter->SecondaryWinsServer.IpAddress.String);
750             }
751 
752             if (pAdapter->DhcpEnabled && _tcscmp(pAdapter->DhcpServer.IpAddress.String, _T("255.255.255.255")))
753             {
754                 PTSTR DateTimeString;
755                 DateTimeString = timeToStr(pAdapter->LeaseObtained);
756                 _tprintf(_T("\tLease Obtained. . . . . . . . . . : %s\n"), DateTimeString ? DateTimeString : _T("N/A"));
757                 if (DateTimeString)
758                 {
759                     HeapFree(ProcessHeap, 0, DateTimeString);
760                 }
761                 DateTimeString = timeToStr(pAdapter->LeaseExpires);
762                 _tprintf(_T("\tLease Expires . . . . . . . . . . : %s\n"), DateTimeString ? DateTimeString : _T("N/A"));
763                 if (DateTimeString)
764                 {
765                     HeapFree(ProcessHeap, 0, DateTimeString);
766                 }
767             }
768         }
769         _tprintf(_T("\n"));
770 
771         HeapFree(ProcessHeap, 0, pPerAdapterInfo);
772         pPerAdapterInfo = NULL;
773 
774         pAdapter = pAdapter->Next;
775     }
776 
777 done:
778     if (pszDomainName)
779         HeapFree(ProcessHeap, 0, pszDomainName);
780     if (pFixedInfo)
781         HeapFree(ProcessHeap, 0, pFixedInfo);
782     if (pAdapterInfo)
783         HeapFree(ProcessHeap, 0, pAdapterInfo);
784 }
785 
786 VOID Release(LPTSTR Index)
787 {
788     IP_ADAPTER_INDEX_MAP AdapterInfo;
789     DWORD ret;
790     DWORD i;
791 
792     /* if interface is not given, query GetInterfaceInfo */
793     if (Index == NULL)
794     {
795         PIP_INTERFACE_INFO pInfo = NULL;
796         ULONG ulOutBufLen = 0;
797 
798         if (GetInterfaceInfo(pInfo, &ulOutBufLen) == ERROR_INSUFFICIENT_BUFFER)
799         {
800             pInfo = (IP_INTERFACE_INFO *)HeapAlloc(ProcessHeap, 0, ulOutBufLen);
801             if (pInfo == NULL)
802                 return;
803 
804             if (GetInterfaceInfo(pInfo, &ulOutBufLen) == NO_ERROR )
805             {
806                 for (i = 0; i < pInfo->NumAdapters; i++)
807                 {
808                     CopyMemory(&AdapterInfo, &pInfo->Adapter[i], sizeof(IP_ADAPTER_INDEX_MAP));
809                     _tprintf(_T("name - %ls\n"), pInfo->Adapter[i].Name);
810 
811                     /* Call IpReleaseAddress to release the IP address on the specified adapter. */
812                     if ((ret = IpReleaseAddress(&AdapterInfo)) != NO_ERROR)
813                     {
814                         _tprintf(_T("\nAn error occured while releasing interface %ls : \n"), AdapterInfo.Name);
815                         DoFormatMessage(ret);
816                     }
817                 }
818 
819                 HeapFree(ProcessHeap, 0, pInfo);
820             }
821             else
822             {
823                 DoFormatMessage(0);
824                 HeapFree(ProcessHeap, 0, pInfo);
825                 return;
826             }
827         }
828         else
829         {
830             DoFormatMessage(0);
831             return;
832         }
833     }
834     else
835     {
836         ;
837         /* FIXME:
838          * we need to be able to release connections by name with support for globbing
839          * i.e. ipconfig /release Eth* will release all cards starting with Eth...
840          *      ipconfig /release *con* will release all cards with 'con' in their name
841          */
842     }
843 }
844 
845 
846 
847 
848 VOID Renew(LPTSTR Index)
849 {
850     IP_ADAPTER_INDEX_MAP AdapterInfo;
851     DWORD i;
852 
853     /* if interface is not given, query GetInterfaceInfo */
854     if (Index == NULL)
855     {
856         PIP_INTERFACE_INFO pInfo;
857         ULONG ulOutBufLen = 0;
858 
859         pInfo = (IP_INTERFACE_INFO *)HeapAlloc(ProcessHeap, 0, sizeof(IP_INTERFACE_INFO));
860         if (pInfo == NULL)
861         {
862             _tprintf(_T("memory allocation error"));
863             return;
864         }
865 
866         /* Make an initial call to GetInterfaceInfo to get
867          * the necessary size into the ulOutBufLen variable */
868         if (GetInterfaceInfo(pInfo, &ulOutBufLen) == ERROR_INSUFFICIENT_BUFFER)
869         {
870             HeapFree(ProcessHeap, 0, pInfo);
871             pInfo = (IP_INTERFACE_INFO *)HeapAlloc(ProcessHeap, 0, ulOutBufLen);
872             if (pInfo == NULL)
873             {
874                 _tprintf(_T("memory allocation error"));
875                 return;
876             }
877         }
878 
879         /* Make a second call to GetInterfaceInfo to get the actual data we want */
880         if (GetInterfaceInfo(pInfo, &ulOutBufLen) == NO_ERROR)
881         {
882             for (i = 0; i < pInfo->NumAdapters; i++)
883             {
884                 CopyMemory(&AdapterInfo, &pInfo->Adapter[i], sizeof(IP_ADAPTER_INDEX_MAP));
885                 _tprintf(_T("name - %ls\n"), pInfo->Adapter[i].Name);
886 
887                 /* Call IpRenewAddress to renew the IP address on the specified adapter. */
888                 if (IpRenewAddress(&AdapterInfo) != NO_ERROR)
889                 {
890                     _tprintf(_T("\nAn error occured while renew interface %s : "), _T("*name*"));
891                     DoFormatMessage(0);
892                 }
893             }
894         }
895         else
896         {
897             _tprintf(_T("\nGetInterfaceInfo failed : "));
898             DoFormatMessage(0);
899         }
900 
901         HeapFree(ProcessHeap, 0, pInfo);
902     }
903     else
904     {
905         ;
906         /* FIXME:
907          * we need to be able to renew connections by name with support for globbing
908          * i.e. ipconfig /renew Eth* will renew all cards starting with Eth...
909          *      ipconfig /renew *con* will renew all cards with 'con' in their name
910          */
911     }
912 }
913 
914 VOID
915 FlushDns(VOID)
916 {
917     _tprintf(_T("\nReactOS IP Configuration\n\n"));
918 
919     if (DnsFlushResolverCache())
920         _tprintf(_T("The DNS Resolver Cache has been deleted.\n"));
921     else
922         DoFormatMessage(GetLastError());
923 }
924 
925 VOID
926 RegisterDns(VOID)
927 {
928     /* FIXME */
929     _tprintf(_T("\nSorry /registerdns is not implemented yet\n"));
930 }
931 
932 static
933 VOID
934 DisplayDnsRecord(
935     PWSTR pszName,
936     WORD wType)
937 {
938     PDNS_RECORDW pQueryResults = NULL, pThisRecord, pNextRecord;
939     WCHAR szBuffer[48];
940     IN_ADDR Addr4;
941     IN6_ADDR Addr6;
942     DNS_STATUS Status;
943 
944     pQueryResults = NULL;
945     Status = DnsQuery_W(pszName,
946                         wType,
947                         DNS_QUERY_NO_WIRE_QUERY,
948                         NULL,
949                         (PDNS_RECORD *)&pQueryResults,
950                         NULL);
951     if (Status != ERROR_SUCCESS)
952     {
953         if (Status == DNS_ERROR_RCODE_NAME_ERROR)
954         {
955             _tprintf(_T("\t%S\n"), pszName);
956             _tprintf(_T("\t----------------------------------------\n"));
957             _tprintf(_T("\tName does not exist\n\n"));
958         }
959         else if (Status == DNS_INFO_NO_RECORDS)
960         {
961             _tprintf(_T("\t%S\n"), pszName);
962             _tprintf(_T("\t----------------------------------------\n"));
963             _tprintf(_T("\tNo records of type %s\n\n"), GetRecordTypeName(wType));
964         }
965         return;
966     }
967 
968     _tprintf(_T("\t%S\n"), pszName);
969     _tprintf(_T("\t----------------------------------------\n"));
970 
971     pThisRecord = pQueryResults;
972     while (pThisRecord != NULL)
973     {
974         pNextRecord = pThisRecord->pNext;
975 
976         _tprintf(_T("\tRecord Name . . . . . : %S\n"), pThisRecord->pName);
977         _tprintf(_T("\tRecord Type . . . . . : %hu\n"), pThisRecord->wType);
978         _tprintf(_T("\tTime To Live. . . . . : %lu\n"), pThisRecord->dwTtl);
979         _tprintf(_T("\tData Length . . . . . : %hu\n"), pThisRecord->wDataLength);
980 
981         switch (pThisRecord->Flags.S.Section)
982         {
983             case DnsSectionQuestion:
984                 _tprintf(_T("\tSection . . . . . . . : Question\n"));
985                 break;
986 
987             case DnsSectionAnswer:
988                 _tprintf(_T("\tSection . . . . . . . : Answer\n"));
989                 break;
990 
991             case DnsSectionAuthority:
992                 _tprintf(_T("\tSection . . . . . . . : Authority\n"));
993                 break;
994 
995             case DnsSectionAdditional:
996                 _tprintf(_T("\tSection . . . . . . . : Additional\n"));
997                 break;
998         }
999 
1000         switch (pThisRecord->wType)
1001         {
1002             case DNS_TYPE_A:
1003                 Addr4.S_un.S_addr = pThisRecord->Data.A.IpAddress;
1004                 RtlIpv4AddressToStringW(&Addr4, szBuffer);
1005                 _tprintf(_T("\tA (Host) Record . . . : %S\n"), szBuffer);
1006                 break;
1007 
1008             case DNS_TYPE_NS:
1009                 _tprintf(_T("\tNS Record . . . . . . : %S\n"), pThisRecord->Data.NS.pNameHost);
1010                 break;
1011 
1012             case DNS_TYPE_CNAME:
1013                 _tprintf(_T("\tCNAME Record. . . . . : %S\n"), pThisRecord->Data.CNAME.pNameHost);
1014                 break;
1015 
1016             case DNS_TYPE_SOA:
1017                 _tprintf(_T("\tSOA Record. . . . . . : \n"));
1018                 break;
1019 
1020             case DNS_TYPE_PTR:
1021                 _tprintf(_T("\tPTR Record. . . . . . : %S\n"), pThisRecord->Data.PTR.pNameHost);
1022                 break;
1023 
1024             case DNS_TYPE_MX:
1025                 _tprintf(_T("\tMX Record . . . . . . : \n"));
1026                 break;
1027 
1028             case DNS_TYPE_AAAA:
1029                 RtlCopyMemory(&Addr6, &pThisRecord->Data.AAAA.Ip6Address, sizeof(IN6_ADDR));
1030                 RtlIpv6AddressToStringW(&Addr6, szBuffer);
1031                 _tprintf(_T("\tAAAA Record . . . . . : %S\n"), szBuffer);
1032                 break;
1033 
1034             case DNS_TYPE_ATMA:
1035                 _tprintf(_T("\tATMA Record . . . . . : \n"));
1036                 break;
1037 
1038             case DNS_TYPE_SRV:
1039                 _tprintf(_T("\tSRV Record. . . . . . : \n"));
1040                 break;
1041         }
1042         _tprintf(_T("\n\n"));
1043 
1044         pThisRecord = pNextRecord;
1045     }
1046 
1047     DnsRecordListFree((PDNS_RECORD)pQueryResults, DnsFreeRecordList);
1048 }
1049 
1050 
1051 VOID
1052 DisplayDns(VOID)
1053 {
1054     PDNS_CACHE_ENTRY DnsEntry = NULL, pThisEntry, pNextEntry;
1055 
1056     _tprintf(_T("\nReactOS IP Configuration\n\n"));
1057 
1058     if (!DnsGetCacheDataTable(&DnsEntry))
1059     {
1060         DoFormatMessage(GetLastError());
1061         return;
1062     }
1063 
1064     if (DnsEntry == NULL)
1065         return;
1066 
1067     pThisEntry = DnsEntry;
1068     while (pThisEntry != NULL)
1069     {
1070         pNextEntry = pThisEntry->pNext;
1071 
1072         if (pThisEntry->wType1 != 0)
1073             DisplayDnsRecord(pThisEntry->pszName, pThisEntry->wType1);
1074 
1075         if (pThisEntry->wType2 != 0)
1076             DisplayDnsRecord(pThisEntry->pszName, pThisEntry->wType2);
1077 
1078         if (pThisEntry->pszName)
1079             LocalFree(pThisEntry->pszName);
1080         LocalFree(pThisEntry);
1081 
1082         pThisEntry = pNextEntry;
1083     }
1084 }
1085 
1086 VOID Usage(VOID)
1087 {
1088     HRSRC hRes;
1089     LPTSTR lpUsage;
1090     DWORD Size;
1091 
1092     LPTSTR lpName = (LPTSTR)MAKEINTRESOURCE((IDS_USAGE >> 4) + 1);
1093 
1094     hRes = FindResource(hInstance,
1095                         lpName,
1096                         RT_STRING);
1097     if (hRes != NULL)
1098     {
1099         if ((Size = SizeofResource(hInstance,
1100                                    hRes)))
1101         {
1102             lpUsage = (LPTSTR)HeapAlloc(ProcessHeap,
1103                                         0,
1104                                         Size);
1105             if (lpUsage == NULL)
1106                 return;
1107 
1108             if (LoadStringAndOem(hInstance,
1109                            IDS_USAGE,
1110                            lpUsage,
1111                            Size))
1112             {
1113                 _tprintf(_T("%s"), lpUsage);
1114             }
1115 
1116             HeapFree(ProcessHeap, 0, lpUsage);
1117         }
1118     }
1119 }
1120 
1121 int main(int argc, char *argv[])
1122 {
1123     BOOL DoUsage=FALSE;
1124     BOOL DoAll=FALSE;
1125     BOOL DoRelease=FALSE;
1126     BOOL DoRenew=FALSE;
1127     BOOL DoFlushdns=FALSE;
1128     BOOL DoRegisterdns=FALSE;
1129     BOOL DoDisplaydns=FALSE;
1130     BOOL DoShowclassid=FALSE;
1131     BOOL DoSetclassid=FALSE;
1132 
1133     hInstance = GetModuleHandle(NULL);
1134     ProcessHeap = GetProcessHeap();
1135 
1136     /* Parse command line for options we have been given. */
1137     if ((argc > 1) && (argv[1][0]=='/' || argv[1][0]=='-'))
1138     {
1139         if (!_tcsicmp(&argv[1][1], _T("?")))
1140         {
1141             DoUsage = TRUE;
1142         }
1143         else if (!_tcsnicmp(&argv[1][1], _T("ALL"), _tcslen(&argv[1][1])))
1144         {
1145            DoAll = TRUE;
1146         }
1147         else if (!_tcsnicmp(&argv[1][1], _T("RELEASE"), _tcslen(&argv[1][1])))
1148         {
1149             DoRelease = TRUE;
1150         }
1151         else if (!_tcsnicmp(&argv[1][1], _T("RENEW"), _tcslen(&argv[1][1])))
1152         {
1153             DoRenew = TRUE;
1154         }
1155         else if (!_tcsnicmp(&argv[1][1], _T("FLUSHDNS"), _tcslen(&argv[1][1])))
1156         {
1157             DoFlushdns = TRUE;
1158         }
1159         else if (!_tcsnicmp(&argv[1][1], _T("FLUSHREGISTERDNS"), _tcslen(&argv[1][1])))
1160         {
1161             DoRegisterdns = TRUE;
1162         }
1163         else if (!_tcsnicmp(&argv[1][1], _T("DISPLAYDNS"), _tcslen(&argv[1][1])))
1164         {
1165             DoDisplaydns = TRUE;
1166         }
1167         else if (!_tcsnicmp(&argv[1][1], _T("SHOWCLASSID"), _tcslen(&argv[1][1])))
1168         {
1169             DoShowclassid = TRUE;
1170         }
1171         else if (!_tcsnicmp(&argv[1][1], _T("SETCLASSID"), _tcslen(&argv[1][1])))
1172         {
1173             DoSetclassid = TRUE;
1174         }
1175     }
1176 
1177     switch (argc)
1178     {
1179         case 1:  /* Default behaviour if no options are given*/
1180             ShowInfo(FALSE);
1181             break;
1182         case 2:  /* Process all the options that take no parameters */
1183             if (DoUsage)
1184                 Usage();
1185             else if (DoAll)
1186                 ShowInfo(TRUE);
1187             else if (DoRelease)
1188                 Release(NULL);
1189             else if (DoRenew)
1190                 Renew(NULL);
1191             else if (DoFlushdns)
1192                 FlushDns();
1193             else if (DoRegisterdns)
1194                 RegisterDns();
1195             else if (DoDisplaydns)
1196                 DisplayDns();
1197             else
1198                 Usage();
1199             break;
1200         case 3: /* Process all the options that can have 1 parameter */
1201             if (DoRelease)
1202                 _tprintf(_T("\nSorry /release [adapter] is not implemented yet\n"));
1203                 //Release(argv[2]);
1204             else if (DoRenew)
1205                 _tprintf(_T("\nSorry /renew [adapter] is not implemented yet\n"));
1206             else if (DoShowclassid)
1207                 _tprintf(_T("\nSorry /showclassid adapter is not implemented yet\n"));
1208             else if (DoSetclassid)
1209                 _tprintf(_T("\nSorry /setclassid adapter is not implemented yet\n"));
1210             else
1211                 Usage();
1212             break;
1213         case 4:  /* Process all the options that can have 2 parameters */
1214             if (DoSetclassid)
1215                 _tprintf(_T("\nSorry /setclassid adapter [classid]is not implemented yet\n"));
1216             else
1217                 Usage();
1218             break;
1219         default:
1220             Usage();
1221     }
1222 
1223     return 0;
1224 }
1225