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