1 /*
2  * PROJECT:     ReactOS ipconfig utility
3  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:     Display IP info for net adapters
5  * COPYRIGHT:   Copyright 2005-2006 Ged Murphy <gedmurphy@gmail.com>
6  */
7 /*
8  * TODO:
9  * fix renew / release
10  * implement registerdns, showclassid, setclassid
11  */
12 
13 #define WIN32_NO_STATUS
14 #include <stdarg.h>
15 #include <windef.h>
16 #include <winbase.h>
17 #include <winnls.h>
18 #include <winuser.h>
19 #include <winreg.h>
20 #include <winnls.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 #include <strsafe.h>
30 #include <conutils.h>
31 
32 #include "resource.h"
33 
34 typedef struct _RECORDTYPE
35 {
36     WORD wRecordType;
37     LPTSTR pszRecordName;
38 } RECORDTYPE, *PRECORDTYPE;
39 
40 #define GUID_LEN 40
41 
42 HINSTANCE hInstance;
43 HANDLE ProcessHeap;
44 
45 RECORDTYPE TypeArray[] =
46 {
47     {DNS_TYPE_ZERO,    _T("ZERO")},
48     {DNS_TYPE_A,       _T("A")},
49     {DNS_TYPE_NS,      _T("NS")},
50     {DNS_TYPE_MD,      _T("MD")},
51     {DNS_TYPE_MF,      _T("MF")},
52     {DNS_TYPE_CNAME,   _T("CNAME")},
53     {DNS_TYPE_SOA,     _T("SOA")},
54     {DNS_TYPE_MB,      _T("MB")},
55     {DNS_TYPE_MG,      _T("MG")},
56     {DNS_TYPE_MR,      _T("MR")},
57     {DNS_TYPE_NULL,    _T("NULL")},
58     {DNS_TYPE_WKS,     _T("WKS")},
59     {DNS_TYPE_PTR,     _T("PTR")},
60     {DNS_TYPE_HINFO,   _T("HINFO")},
61     {DNS_TYPE_MINFO,   _T("MINFO")},
62     {DNS_TYPE_MX,      _T("MX")},
63     {DNS_TYPE_TEXT,    _T("TXT")},
64     {DNS_TYPE_RP,      _T("RP")},
65     {DNS_TYPE_AFSDB,   _T("AFSDB")},
66     {DNS_TYPE_X25,     _T("X25")},
67     {DNS_TYPE_ISDN,    _T("ISDN")},
68     {DNS_TYPE_RT,      _T("RT")},
69     {DNS_TYPE_NSAP,    _T("NSAP")},
70     {DNS_TYPE_NSAPPTR, _T("NSAPPTR")},
71     {DNS_TYPE_SIG,     _T("SIG")},
72     {DNS_TYPE_KEY,     _T("KEY")},
73     {DNS_TYPE_PX,      _T("PX")},
74     {DNS_TYPE_GPOS,    _T("GPOS")},
75     {DNS_TYPE_AAAA,    _T("AAAA")},
76     {DNS_TYPE_LOC,     _T("LOC")},
77     {DNS_TYPE_NXT,     _T("NXT")},
78     {DNS_TYPE_EID,     _T("EID")},
79     {DNS_TYPE_NIMLOC,  _T("NIMLOC")},
80     {DNS_TYPE_SRV,     _T("SRV")},
81     {DNS_TYPE_ATMA,    _T("ATMA")},
82     {DNS_TYPE_NAPTR,   _T("NAPTR")},
83     {DNS_TYPE_KX,      _T("KX")},
84     {DNS_TYPE_CERT,    _T("CERT")},
85     {DNS_TYPE_A6,      _T("A6")},
86     {DNS_TYPE_DNAME,   _T("DNAME")},
87     {DNS_TYPE_SINK,    _T("SINK")},
88     {DNS_TYPE_OPT,     _T("OPT")},
89     {DNS_TYPE_UINFO,   _T("UINFO")},
90     {DNS_TYPE_UID,     _T("UID")},
91     {DNS_TYPE_GID,     _T("GID")},
92     {DNS_TYPE_UNSPEC,  _T("UNSPEC")},
93     {DNS_TYPE_ADDRS,   _T("ADDRS")},
94     {DNS_TYPE_TKEY,    _T("TKEY")},
95     {DNS_TYPE_TSIG,    _T("TSIG")},
96     {DNS_TYPE_IXFR,    _T("IXFR")},
97     {DNS_TYPE_AXFR,    _T("AXFR")},
98     {DNS_TYPE_MAILB,   _T("MAILB")},
99     {DNS_TYPE_MAILA,   _T("MAILA")},
100     {DNS_TYPE_ALL,     _T("ALL")},
101     {0, NULL}
102 };
103 
104 LPTSTR
105 GetRecordTypeName(WORD wType)
106 {
107     static TCHAR szType[8];
108     INT i;
109 
110     for (i = 0; ; i++)
111     {
112          if (TypeArray[i].pszRecordName == NULL)
113              break;
114 
115          if (TypeArray[i].wRecordType == wType)
116              return TypeArray[i].pszRecordName;
117     }
118 
119     _stprintf(szType, _T("%hu"), wType);
120 
121     return szType;
122 }
123 
124 /* print MAC address */
125 PCHAR PrintMacAddr(PBYTE Mac)
126 {
127     static CHAR MacAddr[20];
128 
129     sprintf(MacAddr, "%02X-%02X-%02X-%02X-%02X-%02X",
130         Mac[0], Mac[1], Mac[2], Mac[3], Mac[4],  Mac[5]);
131 
132     return MacAddr;
133 }
134 
135 
136 /* convert time_t to localized string */
137 _Ret_opt_z_ PTSTR timeToStr(_In_ time_t TimeStamp)
138 {
139     struct tm* ptm;
140     SYSTEMTIME SystemTime;
141     INT DateCchSize, TimeCchSize, TotalCchSize, i;
142     PTSTR DateTimeString, psz;
143 
144     /* Convert Unix time to SYSTEMTIME */
145     /* localtime_s may be preferred if available */
146     ptm = localtime(&TimeStamp);
147     if (!ptm)
148     {
149         return NULL;
150     }
151     SystemTime.wYear = ptm->tm_year + 1900;
152     SystemTime.wMonth = ptm->tm_mon + 1;
153     SystemTime.wDay = ptm->tm_mday;
154     SystemTime.wHour = ptm->tm_hour;
155     SystemTime.wMinute = ptm->tm_min;
156     SystemTime.wSecond = ptm->tm_sec;
157 
158     /* Get total size in characters required of buffer */
159     DateCchSize = GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &SystemTime, NULL, NULL, 0);
160     if (!DateCchSize)
161     {
162         return NULL;
163     }
164     TimeCchSize = GetTimeFormat(LOCALE_USER_DEFAULT, 0, &SystemTime, NULL, NULL, 0);
165     if (!TimeCchSize)
166     {
167         return NULL;
168     }
169     /* Two terminating null are included, the first one will be replaced by space */
170     TotalCchSize = DateCchSize + TimeCchSize;
171 
172     /* Allocate buffer and format datetime string */
173     DateTimeString = (PTSTR)HeapAlloc(ProcessHeap, 0, TotalCchSize * sizeof(TCHAR));
174     if (!DateTimeString)
175     {
176         return NULL;
177     }
178 
179     /* Get date string */
180     i = GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &SystemTime, NULL, DateTimeString, TotalCchSize);
181     if (i)
182     {
183         /* Append space and move pointer */
184         DateTimeString[i - 1] = _T(' ');
185         psz = DateTimeString + i;
186         TotalCchSize -= i;
187 
188         /* Get time string */
189         if (GetTimeFormat(LOCALE_USER_DEFAULT, 0, &SystemTime, NULL, psz, TotalCchSize))
190         {
191             return DateTimeString;
192         }
193     }
194 
195     HeapFree(ProcessHeap, 0, DateTimeString);
196     return NULL;
197 }
198 
199 
200 VOID DoFormatMessage(LONG ErrorCode)
201 {
202     LPVOID lpMsgBuf;
203     //DWORD ErrorCode;
204 
205     if (ErrorCode == 0)
206         ErrorCode = GetLastError();
207 
208     if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
209                         FORMAT_MESSAGE_FROM_SYSTEM |
210                         FORMAT_MESSAGE_IGNORE_INSERTS,
211                       NULL,
212                       ErrorCode,
213                       MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
214                       (LPTSTR) &lpMsgBuf,
215                       0,
216                       NULL))
217     {
218         _tprintf(_T("%s"), (LPTSTR)lpMsgBuf);
219         LocalFree(lpMsgBuf);
220     }
221 }
222 
223 VOID
224 GetAdapterFriendlyName(
225     _In_ LPSTR lpClass,
226     _In_ DWORD cchFriendlyNameLength,
227     _Out_ LPWSTR pszFriendlyName)
228 {
229     HKEY hKey = NULL;
230     CHAR Path[256];
231     LPSTR PrePath  = "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\";
232     LPSTR PostPath = "\\Connection";
233     DWORD PathSize;
234     DWORD dwType;
235     DWORD dwDataSize;
236 
237     /* don't overflow the buffer */
238     PathSize = strlen(PrePath) + strlen(lpClass) + strlen(PostPath) + 1;
239     if (PathSize >= 255)
240         return;
241 
242     sprintf(Path, "%s%s%s", PrePath, lpClass, PostPath);
243 
244     if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,
245                       Path,
246                       0,
247                       KEY_READ,
248                       &hKey) == ERROR_SUCCESS)
249     {
250         dwDataSize = cchFriendlyNameLength * sizeof(WCHAR);
251         RegQueryValueExW(hKey,
252                          L"Name",
253                          NULL,
254                          &dwType,
255                          (PBYTE)pszFriendlyName,
256                          &dwDataSize);
257     }
258 
259     if (hKey != NULL)
260         RegCloseKey(hKey);
261 }
262 
263 VOID
264 GetInterfaceFriendlyName(
265     _In_ LPWSTR lpDeviceName,
266     _In_ DWORD cchFriendlyNameLength,
267     _Out_ LPWSTR pszFriendlyName)
268 {
269     HKEY hKey = NULL;
270     WCHAR Path[256];
271     LPWSTR PrePath  = L"SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\";
272     LPWSTR PostPath = L"\\Connection";
273     LPWSTR DevicePrefix = L"\\DEVICE\\TCPIP_";
274     DWORD PathSize;
275     DWORD dwType;
276     DWORD dwDataSize;
277 
278     DWORD dwPrefixLength = wcslen(DevicePrefix);
279 
280     /* don't overflow the buffer */
281     PathSize = wcslen(PrePath) + wcslen(lpDeviceName) - dwPrefixLength + wcslen(PostPath) + 1;
282     if (PathSize >= 255)
283         return;
284 
285     swprintf(Path, L"%s%s%s", PrePath, &lpDeviceName[dwPrefixLength], PostPath);
286 
287     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
288                       Path,
289                       0,
290                       KEY_READ,
291                       &hKey) == ERROR_SUCCESS)
292     {
293         dwDataSize = cchFriendlyNameLength * sizeof(WCHAR);
294         RegQueryValueExW(hKey,
295                          L"Name",
296                          NULL,
297                          &dwType,
298                          (PBYTE)pszFriendlyName,
299                          &dwDataSize);
300     }
301 
302     if (hKey != NULL)
303         RegCloseKey(hKey);
304 }
305 
306 static
307 VOID
308 PrintAdapterDescription(LPSTR lpClass)
309 {
310     HKEY hBaseKey = NULL;
311     HKEY hClassKey = NULL;
312     LPSTR lpKeyClass = NULL;
313     LPSTR lpConDesc = NULL;
314     LPTSTR lpPath = NULL;
315     TCHAR szPrePath[] = _T("SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002bE10318}\\");
316     DWORD dwType;
317     DWORD dwDataSize;
318     INT i;
319 
320     if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
321                      szPrePath,
322                      0,
323                      KEY_READ,
324                      &hBaseKey) != ERROR_SUCCESS)
325     {
326         return;
327     }
328 
329     for (i = 0; ; i++)
330     {
331         DWORD PathSize;
332         LONG Status;
333         TCHAR szName[10];
334         DWORD NameLen = 9;
335 
336         if ((Status = RegEnumKeyEx(hBaseKey,
337                                    i,
338                                    szName,
339                                    &NameLen,
340                                    NULL,
341                                    NULL,
342                                    NULL,
343                                    NULL)) != ERROR_SUCCESS)
344         {
345             if (Status == ERROR_NO_MORE_ITEMS)
346             {
347                 DoFormatMessage(Status);
348                 lpConDesc = NULL;
349                 goto CLEANUP;
350             }
351             else
352                 continue;
353         }
354 
355         PathSize = lstrlen(szPrePath) + lstrlen(szName) + 1;
356         lpPath = (LPTSTR)HeapAlloc(ProcessHeap,
357                                    0,
358                                    PathSize * sizeof(TCHAR));
359         if (lpPath == NULL)
360             goto CLEANUP;
361 
362         wsprintf(lpPath, _T("%s%s"), szPrePath, szName);
363 
364         //MessageBox(NULL, lpPath, NULL, 0);
365 
366         if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
367                          lpPath,
368                          0,
369                          KEY_READ,
370                          &hClassKey) != ERROR_SUCCESS)
371         {
372             goto CLEANUP;
373         }
374 
375         HeapFree(ProcessHeap, 0, lpPath);
376         lpPath = NULL;
377 
378         if (RegQueryValueExA(hClassKey,
379                              "NetCfgInstanceId",
380                              NULL,
381                              &dwType,
382                              NULL,
383                              &dwDataSize) == ERROR_SUCCESS)
384         {
385             lpKeyClass = (LPSTR)HeapAlloc(ProcessHeap,
386                                           0,
387                                           dwDataSize);
388             if (lpKeyClass == NULL)
389                 goto CLEANUP;
390 
391             if (RegQueryValueExA(hClassKey,
392                                  "NetCfgInstanceId",
393                                  NULL,
394                                  &dwType,
395                                  (PBYTE)lpKeyClass,
396                                  &dwDataSize) != ERROR_SUCCESS)
397             {
398                 HeapFree(ProcessHeap, 0, lpKeyClass);
399                 lpKeyClass = NULL;
400                 continue;
401             }
402         }
403         else
404             continue;
405 
406         if (!strcmp(lpClass, lpKeyClass))
407         {
408             HeapFree(ProcessHeap, 0, lpKeyClass);
409             lpKeyClass = NULL;
410 
411             if (RegQueryValueExA(hClassKey,
412                                  "DriverDesc",
413                                  NULL,
414                                  &dwType,
415                                  NULL,
416                                  &dwDataSize) == ERROR_SUCCESS)
417             {
418                 lpConDesc = (LPSTR)HeapAlloc(ProcessHeap,
419                                              0,
420                                              dwDataSize);
421                 if (lpConDesc != NULL)
422                 {
423                     if (RegQueryValueExA(hClassKey,
424                                          "DriverDesc",
425                                          NULL,
426                                          &dwType,
427                                          (PBYTE)lpConDesc,
428                                          &dwDataSize) == ERROR_SUCCESS)
429                     {
430                         printf("%s", lpConDesc);
431                     }
432 
433                     HeapFree(ProcessHeap, 0, lpConDesc);
434                     lpConDesc = NULL;
435                 }
436             }
437 
438             break;
439         }
440     }
441 
442 CLEANUP:
443     if (hBaseKey != NULL)
444         RegCloseKey(hBaseKey);
445     if (hClassKey != NULL)
446         RegCloseKey(hClassKey);
447     if (lpPath != NULL)
448         HeapFree(ProcessHeap, 0, lpPath);
449     if (lpKeyClass != NULL)
450         HeapFree(ProcessHeap, 0, lpKeyClass);
451 }
452 
453 static
454 VOID
455 PrintNodeType(
456     _In_ UINT NodeType)
457 {
458     switch (NodeType)
459     {
460         case BROADCAST_NODETYPE:
461             ConResPrintf(StdOut, IDS_NODETYPEBCAST);
462             break;
463 
464         case PEER_TO_PEER_NODETYPE:
465             ConResPrintf(StdOut, IDS_NODETYPEP2P);
466             break;
467 
468         case MIXED_NODETYPE:
469             ConResPrintf(StdOut, IDS_NODETYPEMIXED);
470             break;
471 
472         case HYBRID_NODETYPE:
473             ConResPrintf(StdOut, IDS_NODETYPEHYBRID);
474             break;
475 
476         default :
477             ConResPrintf(StdOut, IDS_NODETYPEUNKNOWN);
478             break;
479     }
480 }
481 
482 static
483 VOID
484 PrintAdapterTypeAndName(
485     PIP_ADAPTER_INFO pAdapterInfo)
486 {
487     WCHAR szFriendlyName[MAX_PATH];
488 
489     GetAdapterFriendlyName(pAdapterInfo->AdapterName, MAX_PATH, szFriendlyName);
490 
491     switch (pAdapterInfo->Type)
492     {
493         case MIB_IF_TYPE_OTHER:
494             ConResPrintf(StdOut, IDS_OTHER, szFriendlyName);
495             break;
496 
497         case MIB_IF_TYPE_ETHERNET:
498             ConResPrintf(StdOut, IDS_ETH, szFriendlyName);
499             break;
500 
501         case MIB_IF_TYPE_TOKENRING:
502             ConResPrintf(StdOut, IDS_TOKEN, szFriendlyName);
503             break;
504 
505         case MIB_IF_TYPE_FDDI:
506             ConResPrintf(StdOut, IDS_FDDI, szFriendlyName);
507             break;
508 
509         case MIB_IF_TYPE_PPP:
510             ConResPrintf(StdOut, IDS_PPP, szFriendlyName);
511             break;
512 
513         case MIB_IF_TYPE_LOOPBACK:
514             ConResPrintf(StdOut, IDS_LOOP, szFriendlyName);
515             break;
516 
517         case MIB_IF_TYPE_SLIP:
518             ConResPrintf(StdOut, IDS_SLIP, szFriendlyName);
519             break;
520 
521         case IF_TYPE_IEEE80211:
522             ConResPrintf(StdOut, IDS_WIFI, szFriendlyName);
523             break;
524 
525         default:
526             ConResPrintf(StdOut, IDS_UNKNOWNADAPTER, szFriendlyName);
527             break;
528     }
529 }
530 
531 VOID
532 ShowInfo(
533     BOOL bShowHeader,
534     BOOL bAll)
535 {
536     MIB_IFROW mibEntry;
537     PIP_ADAPTER_INFO pAdapterInfo = NULL;
538     PIP_ADAPTER_INFO pAdapter = NULL;
539     ULONG adaptOutBufLen = 0;
540     PFIXED_INFO pFixedInfo = NULL;
541     ULONG netOutBufLen = 0;
542     PIP_PER_ADAPTER_INFO pPerAdapterInfo = NULL;
543     ULONG ulPerAdapterInfoLength = 0;
544     PSTR pszDomainName = NULL;
545     DWORD dwDomainNameSize = 0;
546     ULONG ret = 0;
547 
548     GetComputerNameExA(ComputerNameDnsDomain,
549                        NULL,
550                        &dwDomainNameSize);
551     if (dwDomainNameSize > 0)
552     {
553         pszDomainName = HeapAlloc(ProcessHeap,
554                                   0,
555                                   dwDomainNameSize * sizeof(TCHAR));
556         if (pszDomainName != NULL)
557             GetComputerNameExA(ComputerNameDnsDomain,
558                                pszDomainName,
559                                &dwDomainNameSize);
560     }
561 
562     /* call GetAdaptersInfo to obtain the adapter info */
563     ret = GetAdaptersInfo(pAdapterInfo, &adaptOutBufLen);
564     if (ret == ERROR_BUFFER_OVERFLOW)
565     {
566         pAdapterInfo = (IP_ADAPTER_INFO *)HeapAlloc(ProcessHeap, 0, adaptOutBufLen);
567         if (pAdapterInfo == NULL)
568             goto done;
569 
570         ret = GetAdaptersInfo(pAdapterInfo, &adaptOutBufLen);
571         if (ret != NO_ERROR)
572         {
573             DoFormatMessage(0);
574             goto done;
575         }
576     }
577     else
578     {
579         if (ret != ERROR_NO_DATA)
580         {
581             DoFormatMessage(0);
582             goto done;
583         }
584     }
585 
586     /* call GetNetworkParams to obtain the network info */
587     if (GetNetworkParams(pFixedInfo, &netOutBufLen) == ERROR_BUFFER_OVERFLOW)
588     {
589         pFixedInfo = (FIXED_INFO *)HeapAlloc(ProcessHeap, 0, netOutBufLen);
590         if (pFixedInfo == NULL)
591         {
592             goto done;
593         }
594         if (GetNetworkParams(pFixedInfo, &netOutBufLen) != NO_ERROR)
595         {
596             DoFormatMessage(0);
597             goto done;
598         }
599     }
600     else
601     {
602         DoFormatMessage(0);
603         goto done;
604     }
605 
606     pAdapter = pAdapterInfo;
607 
608     if (bShowHeader)
609         ConResPrintf(StdOut, IDS_HEADER);
610 
611     if (bAll)
612     {
613         ConResPrintf(StdOut, IDS_HOSTNAME, pFixedInfo->HostName);
614         ConResPrintf(StdOut, IDS_PRIMARYDNSSUFFIX, (pszDomainName != NULL) ? pszDomainName : "");
615 
616         PrintNodeType(pFixedInfo->NodeType);
617 
618         if (pFixedInfo->EnableRouting)
619             ConResPrintf(StdOut, IDS_IPROUTINGYES);
620         else
621             ConResPrintf(StdOut, IDS_IPROUTINGNO);
622 
623         if (pAdapter && pAdapter->HaveWins)
624             ConResPrintf(StdOut, IDS_WINSPROXYYES);
625         else
626             ConResPrintf(StdOut, IDS_WINSPROXYNO);
627 
628         if (pszDomainName != NULL && pszDomainName[0] != 0)
629         {
630             ConResPrintf(StdOut, IDS_DNSSUFFIXLIST, pszDomainName);
631             ConResPrintf(StdOut, IDS_EMPTYLINE, pFixedInfo->DomainName);
632         }
633         else
634         {
635             ConResPrintf(StdOut, IDS_DNSSUFFIXLIST, pFixedInfo->DomainName);
636         }
637     }
638 
639     while (pAdapter)
640     {
641         BOOLEAN bConnected = TRUE;
642 
643         mibEntry.dwIndex = pAdapter->Index;
644         GetIfEntry(&mibEntry);
645 
646         PrintAdapterTypeAndName(pAdapter);
647 
648         if (GetPerAdapterInfo(pAdapter->Index, pPerAdapterInfo, &ulPerAdapterInfoLength) == ERROR_BUFFER_OVERFLOW)
649         {
650             pPerAdapterInfo = (PIP_PER_ADAPTER_INFO)HeapAlloc(ProcessHeap, 0, ulPerAdapterInfoLength);
651             if (pPerAdapterInfo != NULL)
652             {
653                 GetPerAdapterInfo(pAdapter->Index, pPerAdapterInfo, &ulPerAdapterInfoLength);
654             }
655         }
656 
657         /* check if the adapter is connected to the media */
658         if (mibEntry.dwOperStatus != MIB_IF_OPER_STATUS_CONNECTED && mibEntry.dwOperStatus != MIB_IF_OPER_STATUS_OPERATIONAL)
659         {
660             bConnected = FALSE;
661             ConResPrintf(StdOut, IDS_MEDIADISCONNECTED);
662         }
663         else
664         {
665             ConResPrintf(StdOut, IDS_CONNECTIONDNSSUFFIX, pFixedInfo->DomainName);
666         }
667 
668         if (bAll)
669         {
670             ConResPrintf(StdOut, IDS_DESCRIPTION);
671             PrintAdapterDescription(pAdapter->AdapterName);
672             printf("\n");
673 
674             ConResPrintf(StdOut, IDS_PHYSICALADDRESS, PrintMacAddr(pAdapter->Address));
675 
676             if (bConnected)
677             {
678                 if (pAdapter->DhcpEnabled)
679                 {
680                     ConResPrintf(StdOut, IDS_DHCPYES);
681 
682                     if (pPerAdapterInfo != NULL)
683                     {
684                         if (pPerAdapterInfo->AutoconfigEnabled)
685                             ConResPrintf(StdOut, IDS_AUTOCONFIGYES);
686                         else
687                             ConResPrintf(StdOut, IDS_AUTOCONFIGNO);
688                     }
689                 }
690                 else
691                 {
692                     ConResPrintf(StdOut, IDS_DHCPNO);
693                 }
694             }
695         }
696 
697         if (!bConnected)
698         {
699             pAdapter = pAdapter->Next;
700             continue;
701         }
702 
703         ConResPrintf(StdOut, IDS_IPADDRESS, pAdapter->IpAddressList.IpAddress.String);
704         ConResPrintf(StdOut, IDS_SUBNETMASK, pAdapter->IpAddressList.IpMask.String);
705 
706         if (strcmp(pAdapter->GatewayList.IpAddress.String, "0.0.0.0"))
707             ConResPrintf(StdOut, IDS_DEFAULTGATEWAY, pAdapter->GatewayList.IpAddress.String);
708         else
709             ConResPrintf(StdOut, IDS_DEFAULTGATEWAY, "");
710 
711         if (bAll)
712         {
713             PIP_ADDR_STRING pIPAddr;
714 
715             if (pAdapter->DhcpEnabled)
716                 ConResPrintf(StdOut, IDS_DHCPSERVER, pAdapter->DhcpServer.IpAddress.String);
717 
718             ConResPrintf(StdOut, IDS_DNSSERVERS, pFixedInfo->DnsServerList.IpAddress.String);
719             pIPAddr = pFixedInfo->DnsServerList.Next;
720             while (pIPAddr)
721             {
722                 ConResPrintf(StdOut, IDS_EMPTYLINE, pIPAddr ->IpAddress.String);
723                 pIPAddr = pIPAddr->Next;
724             }
725 
726             if (pAdapter->HaveWins)
727             {
728                 ConResPrintf(StdOut, IDS_PRIMARYWINSSERVER, pAdapter->PrimaryWinsServer.IpAddress.String);
729                 ConResPrintf(StdOut, IDS_SECONDARYWINSSERVER, pAdapter->SecondaryWinsServer.IpAddress.String);
730             }
731 
732             if (pAdapter->DhcpEnabled && strcmp(pAdapter->DhcpServer.IpAddress.String, "255.255.255.255"))
733             {
734                 PTSTR DateTimeString;
735                 DateTimeString = timeToStr(pAdapter->LeaseObtained);
736                 ConResPrintf(StdOut, IDS_LEASEOBTAINED, DateTimeString ? DateTimeString : _T("N/A"));
737                 if (DateTimeString)
738                 {
739                     HeapFree(ProcessHeap, 0, DateTimeString);
740                 }
741                 DateTimeString = timeToStr(pAdapter->LeaseExpires);
742                 ConResPrintf(StdOut, IDS_LEASEEXPIRES, DateTimeString ? DateTimeString : _T("N/A"));
743                 if (DateTimeString)
744                 {
745                     HeapFree(ProcessHeap, 0, DateTimeString);
746                 }
747             }
748         }
749 
750         HeapFree(ProcessHeap, 0, pPerAdapterInfo);
751         pPerAdapterInfo = NULL;
752 
753         pAdapter = pAdapter->Next;
754     }
755 
756 done:
757     if (pszDomainName)
758         HeapFree(ProcessHeap, 0, pszDomainName);
759     if (pFixedInfo)
760         HeapFree(ProcessHeap, 0, pFixedInfo);
761     if (pAdapterInfo)
762         HeapFree(ProcessHeap, 0, pAdapterInfo);
763 }
764 
765 static
766 BOOL
767 MatchWildcard(
768     _In_ PWSTR pszExpression,
769     _In_ PWSTR pszName)
770 {
771     WCHAR *pCharE, *pCharN, charE, charN;
772 
773     if (pszExpression == NULL)
774         return TRUE;
775 
776     if (pszName == NULL)
777         return FALSE;
778 
779     pCharE = pszExpression;
780     pCharN = pszName;
781     while (*pCharE != UNICODE_NULL)
782     {
783         charE = towlower(*pCharE);
784         charN = towlower(*pCharN);
785 
786         if (charE == L'*')
787         {
788             if (*(pCharE + 1) != charN)
789                 pCharN++;
790             else
791                 pCharE++;
792         }
793         else if (charE == L'?')
794         {
795             pCharE++;
796             pCharN++;
797         }
798         else if (charE == charN)
799         {
800             pCharE++;
801             pCharN++;
802         }
803         else
804         {
805             return FALSE;
806         }
807     }
808 
809     return TRUE;
810 }
811 
812 static
813 VOID
814 BuildAdapterMap(
815     PIP_ADAPTER_INDEX_MAP pAdapterMap,
816     PIP_ADAPTER_INFO pAdapterInfo)
817 {
818     int i, l1, l2;
819 
820     pAdapterMap->Index = pAdapterInfo->Index;
821 
822     wcscpy(pAdapterMap->Name, L"\\DEVICE\\TCPIP_");
823     l1 = wcslen(pAdapterMap->Name);
824     l2 = strlen(pAdapterInfo->AdapterName);
825     for (i = 0; i < l2; i++)
826         pAdapterMap->Name[i + l1] = (WCHAR)pAdapterInfo->AdapterName[i];
827     pAdapterMap->Name[i + l1] = UNICODE_NULL;
828 }
829 
830 VOID
831 Release(
832     LPWSTR pszAdapterName)
833 {
834     PIP_ADAPTER_INFO pAdapterInfo = NULL;
835     PIP_ADAPTER_INFO pAdapter = NULL;
836     ULONG adaptOutBufLen = 0;
837     ULONG ret = 0;
838     WCHAR szFriendlyName[MAX_PATH];
839     MIB_IFROW mibEntry;
840     IP_ADAPTER_INDEX_MAP AdapterMap;
841     BOOL bFoundAdapter = FALSE;
842 
843     ConResPrintf(StdOut, IDS_HEADER);
844 
845     /* call GetAdaptersInfo to obtain the adapter info */
846     ret = GetAdaptersInfo(pAdapterInfo, &adaptOutBufLen);
847     if (ret != ERROR_BUFFER_OVERFLOW)
848     {
849         DoFormatMessage(ret);
850         return;
851     }
852 
853     pAdapterInfo = (IP_ADAPTER_INFO *)HeapAlloc(ProcessHeap, 0, adaptOutBufLen);
854     if (pAdapterInfo == NULL)
855     {
856         _tprintf(_T("memory allocation error"));
857         return;
858     }
859 
860     ret = GetAdaptersInfo(pAdapterInfo, &adaptOutBufLen);
861     if (ret != NO_ERROR)
862     {
863         DoFormatMessage(0);
864         goto done;
865     }
866 
867     pAdapter = pAdapterInfo;
868 
869     while (pAdapter)
870     {
871         GetAdapterFriendlyName(pAdapter->AdapterName, MAX_PATH, szFriendlyName);
872 
873         if ((pszAdapterName == NULL) || MatchWildcard(pszAdapterName, szFriendlyName))
874         {
875             bFoundAdapter = TRUE;
876 
877             mibEntry.dwIndex = pAdapter->Index;
878             GetIfEntry(&mibEntry);
879 
880             if (mibEntry.dwOperStatus == MIB_IF_OPER_STATUS_CONNECTED ||
881                 mibEntry.dwOperStatus == MIB_IF_OPER_STATUS_OPERATIONAL)
882             {
883                 if (pAdapter->DhcpEnabled)
884                 {
885                     if (strcmp(pAdapter->IpAddressList.IpAddress.String, "0.0.0.0"))
886                     {
887                         BuildAdapterMap(&AdapterMap, pAdapter);
888 
889                         /* Call IpReleaseAddress to release the IP address on the specified adapter. */
890                         ret = IpReleaseAddress(&AdapterMap);
891                         if (ret != NO_ERROR)
892                         {
893                             ConResPrintf(StdOut, IDS_DHCPRELEASEERROR, szFriendlyName);
894                             DoFormatMessage(ret);
895                         }
896                     }
897                     else
898                     {
899                         ConResPrintf(StdOut, IDS_DHCPRELEASED);
900                     }
901                 }
902                 else
903                 {
904                     ConResPrintf(StdOut, IDS_DHCPNOTENABLED, szFriendlyName);
905                 }
906             }
907             else
908             {
909                 ConResPrintf(StdOut, IDS_DHCPNOTCONNECTED, szFriendlyName);
910             }
911         }
912 
913         pAdapter = pAdapter->Next;
914     }
915 
916     if (bFoundAdapter == FALSE)
917     {
918         ConResPrintf(StdOut, IDS_DHCPNOADAPTER);
919     }
920     else
921     {
922         ShowInfo(FALSE, FALSE);
923     }
924 
925 done:
926     if (pAdapterInfo)
927         HeapFree(ProcessHeap, 0, pAdapterInfo);
928 }
929 
930 VOID
931 Renew(
932     LPWSTR pszAdapterName)
933 {
934     PIP_ADAPTER_INFO pAdapterInfo = NULL;
935     PIP_ADAPTER_INFO pAdapter = NULL;
936     ULONG adaptOutBufLen = 0;
937     ULONG ret = 0;
938     WCHAR szFriendlyName[MAX_PATH];
939     MIB_IFROW mibEntry;
940     IP_ADAPTER_INDEX_MAP AdapterMap;
941     BOOL bFoundAdapter = FALSE;
942 
943     ConResPrintf(StdOut, IDS_HEADER);
944 
945     /* call GetAdaptersInfo to obtain the adapter info */
946     ret = GetAdaptersInfo(pAdapterInfo, &adaptOutBufLen);
947     if (ret != ERROR_BUFFER_OVERFLOW)
948     {
949         DoFormatMessage(ret);
950         return;
951     }
952 
953     pAdapterInfo = (IP_ADAPTER_INFO *)HeapAlloc(ProcessHeap, 0, adaptOutBufLen);
954     if (pAdapterInfo == NULL)
955     {
956         _tprintf(_T("memory allocation error"));
957         return;
958     }
959 
960     ret = GetAdaptersInfo(pAdapterInfo, &adaptOutBufLen);
961     if (ret != NO_ERROR)
962     {
963         DoFormatMessage(0);
964         goto done;
965     }
966 
967     pAdapter = pAdapterInfo;
968 
969     while (pAdapter)
970     {
971         GetAdapterFriendlyName(pAdapter->AdapterName, MAX_PATH, szFriendlyName);
972 
973         if ((pszAdapterName == NULL) || MatchWildcard(pszAdapterName, szFriendlyName))
974         {
975             bFoundAdapter = TRUE;
976 
977             mibEntry.dwIndex = pAdapter->Index;
978             GetIfEntry(&mibEntry);
979 
980             if (mibEntry.dwOperStatus == MIB_IF_OPER_STATUS_CONNECTED ||
981                 mibEntry.dwOperStatus == MIB_IF_OPER_STATUS_OPERATIONAL)
982             {
983                 if (pAdapter->DhcpEnabled)
984                 {
985                     BuildAdapterMap(&AdapterMap, pAdapter);
986 
987                     /* Call IpRenewAddress to renew the IP address on the specified adapter. */
988                     ret = IpRenewAddress(&AdapterMap);
989                     if (ret != NO_ERROR)
990                     {
991                         ConResPrintf(StdOut, IDS_DHCPRENEWERROR, szFriendlyName);
992                         DoFormatMessage(ret);
993                     }
994                 }
995                 else
996                 {
997                     ConResPrintf(StdOut, IDS_DHCPNOTENABLED, szFriendlyName);
998                 }
999             }
1000             else
1001             {
1002                 ConResPrintf(StdOut, IDS_DHCPNOTCONNECTED, szFriendlyName);
1003             }
1004         }
1005 
1006         pAdapter = pAdapter->Next;
1007     }
1008 
1009     if (bFoundAdapter == FALSE)
1010     {
1011         ConResPrintf(StdOut, IDS_DHCPNOADAPTER);
1012     }
1013     else
1014     {
1015         ShowInfo(FALSE, FALSE);
1016     }
1017 
1018 done:
1019     if (pAdapterInfo)
1020         HeapFree(ProcessHeap, 0, pAdapterInfo);
1021 }
1022 
1023 VOID
1024 FlushDns(VOID)
1025 {
1026     ConResPrintf(StdOut, IDS_HEADER);
1027 
1028     if (DnsFlushResolverCache())
1029     {
1030         ConResPrintf(StdOut, IDS_DNSFLUSHSUCCESS);
1031     }
1032     else
1033     {
1034         ConResPrintf(StdOut, IDS_DNSFLUSHERROR);
1035         DoFormatMessage(GetLastError());
1036     }
1037 }
1038 
1039 VOID
1040 RegisterDns(VOID)
1041 {
1042     /* FIXME */
1043     _tprintf(_T("\nSorry /registerdns is not implemented yet\n"));
1044 }
1045 
1046 static
1047 VOID
1048 DisplayDnsRecord(
1049     PWSTR pszName,
1050     WORD wType)
1051 {
1052     PDNS_RECORDW pQueryResults = NULL, pThisRecord, pNextRecord;
1053     WCHAR szBuffer[48];
1054     IN_ADDR Addr4;
1055     IN6_ADDR Addr6;
1056     DNS_STATUS Status;
1057 
1058     ConResPrintf(StdOut, IDS_DNSNAME, pszName);
1059     ConResPrintf(StdOut, IDS_DNSLINE);
1060 
1061     pQueryResults = NULL;
1062     Status = DnsQuery_W(pszName,
1063                         wType,
1064                         DNS_QUERY_NO_WIRE_QUERY,
1065                         NULL,
1066                         (PDNS_RECORD *)&pQueryResults,
1067                         NULL);
1068     if (Status != ERROR_SUCCESS)
1069     {
1070         if (Status == DNS_ERROR_RCODE_NAME_ERROR)
1071         {
1072             ConResPrintf(StdOut, IDS_DNSNONAME);
1073         }
1074         else if (Status == DNS_INFO_NO_RECORDS)
1075         {
1076             ConResPrintf(StdOut, IDS_DNSNORECORD, GetRecordTypeName(wType));
1077         }
1078         return;
1079     }
1080 
1081     pThisRecord = pQueryResults;
1082     while (pThisRecord != NULL)
1083     {
1084         pNextRecord = pThisRecord->pNext;
1085 
1086         ConResPrintf(StdOut, IDS_DNSRECORDNAME, pThisRecord->pName);
1087         ConResPrintf(StdOut, IDS_DNSRECORDTYPE, pThisRecord->wType);
1088         ConResPrintf(StdOut, IDS_DNSRECORDTTL, pThisRecord->dwTtl);
1089         ConResPrintf(StdOut, IDS_DNSRECORDLENGTH, pThisRecord->wDataLength);
1090 
1091         switch (pThisRecord->Flags.S.Section)
1092         {
1093             case DnsSectionQuestion:
1094                 ConResPrintf(StdOut, IDS_DNSSECTIONQUESTION);
1095                 break;
1096 
1097             case DnsSectionAnswer:
1098                 ConResPrintf(StdOut, IDS_DNSSECTIONANSWER);
1099                 break;
1100 
1101             case DnsSectionAuthority:
1102                 ConResPrintf(StdOut, IDS_DNSSECTIONAUTHORITY);
1103                 break;
1104 
1105             case DnsSectionAdditional:
1106                 ConResPrintf(StdOut, IDS_DNSSECTIONADDITIONAL);
1107                 break;
1108         }
1109 
1110         switch (pThisRecord->wType)
1111         {
1112             case DNS_TYPE_A:
1113                 Addr4.S_un.S_addr = pThisRecord->Data.A.IpAddress;
1114                 RtlIpv4AddressToStringW(&Addr4, szBuffer);
1115                 ConResPrintf(StdOut, IDS_DNSTYPEA, szBuffer);
1116                 break;
1117 
1118             case DNS_TYPE_NS:
1119                 ConResPrintf(StdOut, IDS_DNSTYPENS, pThisRecord->Data.NS.pNameHost);
1120                 break;
1121 
1122             case DNS_TYPE_CNAME:
1123                 ConResPrintf(StdOut, IDS_DNSTYPECNAME, pThisRecord->Data.CNAME.pNameHost);
1124                 break;
1125 
1126             case DNS_TYPE_SOA:
1127                 ConResPrintf(StdOut, IDS_DNSTYPESOA1,
1128                              pThisRecord->Data.SOA.pNamePrimaryServer,
1129                              pThisRecord->Data.SOA.pNameAdministrator,
1130                              pThisRecord->Data.SOA.dwSerialNo);
1131                 ConResPrintf(StdOut, IDS_DNSTYPESOA2,
1132                              pThisRecord->Data.SOA.dwRefresh,
1133                              pThisRecord->Data.SOA.dwRetry,
1134                              pThisRecord->Data.SOA.dwExpire,
1135                              pThisRecord->Data.SOA.dwDefaultTtl);
1136                 break;
1137 
1138             case DNS_TYPE_PTR:
1139                 ConResPrintf(StdOut, IDS_DNSTYPEPTR, pThisRecord->Data.PTR.pNameHost);
1140                 break;
1141 
1142             case DNS_TYPE_MX:
1143                 ConResPrintf(StdOut, IDS_DNSTYPEMX,
1144                              pThisRecord->Data.MX.pNameExchange,
1145                              pThisRecord->Data.MX.wPreference,
1146                              pThisRecord->Data.MX.Pad);
1147                 break;
1148 
1149             case DNS_TYPE_AAAA:
1150                 RtlCopyMemory(&Addr6, &pThisRecord->Data.AAAA.Ip6Address, sizeof(IN6_ADDR));
1151                 RtlIpv6AddressToStringW(&Addr6, szBuffer);
1152                 ConResPrintf(StdOut, IDS_DNSTYPEAAAA, szBuffer);
1153                 break;
1154 
1155             case DNS_TYPE_ATMA:
1156                 ConResPrintf(StdOut, IDS_DNSTYPEATMA);
1157                 break;
1158 
1159             case DNS_TYPE_SRV:
1160                 ConResPrintf(StdOut, IDS_DNSTYPESRV,
1161                              pThisRecord->Data.SRV.pNameTarget,
1162                              pThisRecord->Data.SRV.wPriority,
1163                              pThisRecord->Data.SRV.wWeight,
1164                              pThisRecord->Data.SRV.wPort);
1165                 break;
1166         }
1167         ConPuts(StdOut, L"\n\n");
1168 
1169         pThisRecord = pNextRecord;
1170     }
1171 
1172     DnsRecordListFree((PDNS_RECORD)pQueryResults, DnsFreeRecordList);
1173 }
1174 
1175 VOID
1176 DisplayDns(VOID)
1177 {
1178     PDNS_CACHE_ENTRY DnsEntry = NULL, pThisEntry, pNextEntry;
1179 
1180     ConResPrintf(StdOut, IDS_HEADER);
1181 
1182     if (!DnsGetCacheDataTable(&DnsEntry))
1183     {
1184         DoFormatMessage(GetLastError());
1185         return;
1186     }
1187 
1188     if (DnsEntry == NULL)
1189         return;
1190 
1191     pThisEntry = DnsEntry;
1192     while (pThisEntry != NULL)
1193     {
1194         pNextEntry = pThisEntry->pNext;
1195 
1196         if (pThisEntry->wType1 != DNS_TYPE_ZERO)
1197             DisplayDnsRecord(pThisEntry->pszName, pThisEntry->wType1);
1198 
1199         if (pThisEntry->wType2 != DNS_TYPE_ZERO)
1200             DisplayDnsRecord(pThisEntry->pszName, pThisEntry->wType2);
1201 
1202         if (pThisEntry->pszName)
1203             LocalFree(pThisEntry->pszName);
1204         LocalFree(pThisEntry);
1205 
1206         pThisEntry = pNextEntry;
1207     }
1208 }
1209 
1210 VOID Usage(VOID)
1211 {
1212     ConResPrintf(StdOut, IDS_USAGE);
1213 }
1214 
1215 int wmain(int argc, wchar_t *argv[])
1216 {
1217     BOOL DoUsage=FALSE;
1218     BOOL DoAll=FALSE;
1219     BOOL DoRelease=FALSE;
1220     BOOL DoRenew=FALSE;
1221     BOOL DoFlushdns=FALSE;
1222     BOOL DoRegisterdns=FALSE;
1223     BOOL DoDisplaydns=FALSE;
1224     BOOL DoShowclassid=FALSE;
1225     BOOL DoSetclassid=FALSE;
1226 
1227     /* Initialize the Console Standard Streams */
1228     ConInitStdStreams();
1229 
1230     hInstance = GetModuleHandle(NULL);
1231     ProcessHeap = GetProcessHeap();
1232 
1233     /* Parse command line for options we have been given. */
1234     if ((argc > 1) && (argv[1][0]=='/' || argv[1][0]=='-'))
1235     {
1236         if (!_tcsicmp(&argv[1][1], _T("?")))
1237         {
1238             DoUsage = TRUE;
1239         }
1240         else if (!_tcsnicmp(&argv[1][1], _T("ALL"), _tcslen(&argv[1][1])))
1241         {
1242            DoAll = TRUE;
1243         }
1244         else if (!_tcsnicmp(&argv[1][1], _T("RELEASE"), _tcslen(&argv[1][1])))
1245         {
1246             DoRelease = TRUE;
1247         }
1248         else if (!_tcsnicmp(&argv[1][1], _T("RENEW"), _tcslen(&argv[1][1])))
1249         {
1250             DoRenew = TRUE;
1251         }
1252         else if (!_tcsnicmp(&argv[1][1], _T("FLUSHDNS"), _tcslen(&argv[1][1])))
1253         {
1254             DoFlushdns = TRUE;
1255         }
1256         else if (!_tcsnicmp(&argv[1][1], _T("FLUSHREGISTERDNS"), _tcslen(&argv[1][1])))
1257         {
1258             DoRegisterdns = TRUE;
1259         }
1260         else if (!_tcsnicmp(&argv[1][1], _T("DISPLAYDNS"), _tcslen(&argv[1][1])))
1261         {
1262             DoDisplaydns = TRUE;
1263         }
1264         else if (!_tcsnicmp(&argv[1][1], _T("SHOWCLASSID"), _tcslen(&argv[1][1])))
1265         {
1266             DoShowclassid = TRUE;
1267         }
1268         else if (!_tcsnicmp(&argv[1][1], _T("SETCLASSID"), _tcslen(&argv[1][1])))
1269         {
1270             DoSetclassid = TRUE;
1271         }
1272     }
1273 
1274     switch (argc)
1275     {
1276         case 1:  /* Default behaviour if no options are given*/
1277             ShowInfo(TRUE, FALSE);
1278             break;
1279         case 2:  /* Process all the options that take no parameters */
1280             if (DoUsage)
1281                 Usage();
1282             else if (DoAll)
1283                 ShowInfo(TRUE, TRUE);
1284             else if (DoRelease)
1285                 Release(NULL);
1286             else if (DoRenew)
1287                 Renew(NULL);
1288             else if (DoFlushdns)
1289                 FlushDns();
1290             else if (DoRegisterdns)
1291                 RegisterDns();
1292             else if (DoDisplaydns)
1293                 DisplayDns();
1294             else
1295                 Usage();
1296             break;
1297         case 3: /* Process all the options that can have 1 parameter */
1298             if (DoRelease)
1299                 Release(argv[2]);
1300             else if (DoRenew)
1301                 Renew(argv[2]);
1302             else if (DoShowclassid)
1303                 _tprintf(_T("\nSorry /showclassid adapter is not implemented yet\n"));
1304             else if (DoSetclassid)
1305                 _tprintf(_T("\nSorry /setclassid adapter is not implemented yet\n"));
1306             else
1307                 Usage();
1308             break;
1309         case 4:  /* Process all the options that can have 2 parameters */
1310             if (DoSetclassid)
1311                 _tprintf(_T("\nSorry /setclassid adapter [classid]is not implemented yet\n"));
1312             else
1313                 Usage();
1314             break;
1315         default:
1316             Usage();
1317     }
1318 
1319     return 0;
1320 }
1321