wscript: Fix tests on wow64.
[wine] / programs / ipconfig / ipconfig.c
1 /*
2  * IP configuration utility
3  *
4  * Copyright 2008 Andrew Riedi
5  * Copyright 2010 Andrew Nguyen
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include <winsock2.h>
23 #include <windows.h>
24 #include <iphlpapi.h>
25 #include <wine/unicode.h>
26
27 #include "ipconfig.h"
28
29 static int ipconfig_vprintfW(const WCHAR *msg, va_list va_args)
30 {
31     int wlen;
32     DWORD count, ret;
33     WCHAR msg_buffer[8192];
34
35     wlen = vsprintfW(msg_buffer, msg, va_args);
36
37     ret = WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), msg_buffer, wlen, &count, NULL);
38     if (!ret)
39     {
40         DWORD len;
41         char *msgA;
42
43         len = WideCharToMultiByte(GetConsoleOutputCP(), 0, msg_buffer, wlen,
44             NULL, 0, NULL, NULL);
45         msgA = HeapAlloc(GetProcessHeap(), 0, len);
46         if (!msgA)
47             return 0;
48
49         WideCharToMultiByte(GetConsoleOutputCP(), 0, msg_buffer, wlen, msgA, len,
50             NULL, NULL);
51         WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), msgA, len, &count, FALSE);
52         HeapFree(GetProcessHeap(), 0, msgA);
53     }
54
55     return count;
56 }
57
58 static int ipconfig_printfW(const WCHAR *msg, ...)
59 {
60     va_list va_args;
61     int len;
62
63     va_start(va_args, msg);
64     len = ipconfig_vprintfW(msg, va_args);
65     va_end(va_args);
66
67     return len;
68 }
69
70 static int ipconfig_message_printfW(int msg, ...)
71 {
72     va_list va_args;
73     WCHAR msg_buffer[8192];
74     int len;
75
76     LoadStringW(GetModuleHandleW(NULL), msg, msg_buffer,
77         sizeof(msg_buffer)/sizeof(WCHAR));
78
79     va_start(va_args, msg);
80     len = ipconfig_vprintfW(msg_buffer, va_args);
81     va_end(va_args);
82
83     return len;
84 }
85
86 static int ipconfig_message(int msg)
87 {
88     static const WCHAR formatW[] = {'%','s',0};
89     WCHAR msg_buffer[8192];
90
91     LoadStringW(GetModuleHandleW(NULL), msg, msg_buffer,
92         sizeof(msg_buffer)/sizeof(WCHAR));
93
94     return ipconfig_printfW(formatW, msg_buffer);
95 }
96
97 static const WCHAR *iftype_to_string(DWORD type)
98 {
99     static WCHAR msg_buffer[50];
100
101     int msg;
102
103     switch (type)
104     {
105     case IF_TYPE_ETHERNET_CSMACD:
106     /* The loopback adapter appears as an Ethernet device. */
107     case IF_TYPE_SOFTWARE_LOOPBACK:
108         msg = STRING_ETHERNET;
109         break;
110     default:
111         msg = STRING_UNKNOWN;
112     }
113
114     LoadStringW(GetModuleHandleW(NULL), msg, msg_buffer,
115         sizeof(msg_buffer)/sizeof(WCHAR));
116
117     return msg_buffer;
118 }
119
120 static void print_field(int msg, const WCHAR *value)
121 {
122     static const WCHAR formatW[] = {' ',' ',' ',' ','%','s',':',' ','%','s','\n',0};
123
124     WCHAR field[] = {'.',' ','.',' ','.',' ','.',' ','.',' ','.',' ','.',' ','.',' ','.',
125                      ' ','.',' ','.',' ','.',' ','.',' ','.',' ','.',' ','.',' ','.',' ',0};
126     WCHAR name_buffer[sizeof(field)/sizeof(WCHAR)];
127
128     LoadStringW(GetModuleHandleW(NULL), msg, name_buffer, sizeof(name_buffer)/sizeof(WCHAR));
129     memcpy(field, name_buffer, sizeof(WCHAR) * min(strlenW(name_buffer), sizeof(field)/sizeof(WCHAR) - 1));
130
131     ipconfig_printfW(formatW, field, value);
132 }
133
134 static void print_value(const WCHAR *value)
135 {
136     static const WCHAR formatW[] = {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
137                                     ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
138                                     ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
139                                     ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
140                                     '%','s','\n',0};
141
142     ipconfig_printfW(formatW, value);
143 }
144
145 static BOOL socket_address_to_string(WCHAR *buf, DWORD len, SOCKET_ADDRESS *addr)
146 {
147     return WSAAddressToStringW(addr->lpSockaddr,
148                                addr->iSockaddrLength, NULL,
149                                buf, &len) == 0;
150 }
151
152 static void print_basic_information(void)
153 {
154     IP_ADAPTER_ADDRESSES *adapters;
155     ULONG out = 0;
156
157     if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_ALL_GATEWAYS,
158                              NULL, NULL, &out) == ERROR_BUFFER_OVERFLOW)
159     {
160         adapters = HeapAlloc(GetProcessHeap(), 0, out);
161         if (!adapters)
162             exit(1);
163
164         if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_ALL_GATEWAYS,
165                                  NULL, adapters, &out) == ERROR_SUCCESS)
166         {
167             IP_ADAPTER_ADDRESSES *p;
168
169             for (p = adapters; p; p = p->Next)
170             {
171                 static const WCHAR newlineW[] = {'\n',0};
172                 static const WCHAR emptyW[] = {0};
173
174                 IP_ADAPTER_UNICAST_ADDRESS *addr;
175                 IP_ADAPTER_GATEWAY_ADDRESS_LH *gateway;
176                 WCHAR addr_buf[54];
177
178                 ipconfig_message_printfW(STRING_ADAPTER_FRIENDLY, iftype_to_string(p->IfType), p->FriendlyName);
179                 ipconfig_printfW(newlineW);
180                 print_field(STRING_CONN_DNS_SUFFIX, p->DnsSuffix);
181
182                 for (addr = p->FirstUnicastAddress; addr; addr = addr->Next)
183                 {
184                     if (socket_address_to_string(addr_buf, sizeof(addr_buf)/sizeof(WCHAR), &addr->Address))
185                         print_field(STRING_IP_ADDRESS, addr_buf);
186                     /* FIXME: Output corresponding subnet mask. */
187                 }
188
189                 if (p->FirstGatewayAddress)
190                 {
191                     if (socket_address_to_string(addr_buf, sizeof(addr_buf)/sizeof(WCHAR), &p->FirstGatewayAddress->Address))
192                         print_field(STRING_DEFAULT_GATEWAY, addr_buf);
193
194                     for (gateway = p->FirstGatewayAddress->Next; gateway; gateway = gateway->Next)
195                     {
196                         if (socket_address_to_string(addr_buf, sizeof(addr_buf)/sizeof(WCHAR), &gateway->Address))
197                             print_value(addr_buf);
198                     }
199                 }
200                 else
201                     print_field(STRING_DEFAULT_GATEWAY, emptyW);
202
203                 ipconfig_printfW(newlineW);
204             }
205         }
206
207         HeapFree(GetProcessHeap(), 0, adapters);
208     }
209 }
210
211 static const WCHAR *nodetype_to_string(DWORD type)
212 {
213     static WCHAR msg_buffer[50];
214
215     int msg;
216
217     switch (type)
218     {
219     case BROADCAST_NODETYPE:
220         msg = STRING_BROADCAST;
221         break;
222     case PEER_TO_PEER_NODETYPE:
223         msg = STRING_PEER_TO_PEER;
224         break;
225     case MIXED_NODETYPE:
226         msg = STRING_MIXED;
227         break;
228     case HYBRID_NODETYPE:
229         msg = STRING_HYBRID;
230         break;
231     default:
232         msg = STRING_UNKNOWN;
233     }
234
235     LoadStringW(GetModuleHandleW(NULL), msg, msg_buffer,
236         sizeof(msg_buffer)/sizeof(WCHAR));
237
238     return msg_buffer;
239 }
240
241 static WCHAR *physaddr_to_string(WCHAR *buf, BYTE *addr, DWORD len)
242 {
243     static const WCHAR fmtW[] = {'%','0','2','X','-',0};
244     static const WCHAR fmt2W[] = {'%','0','2','X',0};
245
246     if (!len)
247         *buf = '\0';
248     else
249     {
250         WCHAR *p = buf;
251         DWORD i;
252
253         for (i = 0; i < len - 1; i++)
254         {
255             sprintfW(p, fmtW, addr[i]);
256             p += 3;
257         }
258         sprintfW(p, fmt2W, addr[i]);
259     }
260
261     return buf;
262 }
263
264 static const WCHAR *boolean_to_string(int value)
265 {
266     static WCHAR msg_buffer[15];
267
268     LoadStringW(GetModuleHandleW(NULL), value ? STRING_YES : STRING_NO,
269         msg_buffer, sizeof(msg_buffer)/sizeof(WCHAR));
270
271     return msg_buffer;
272 }
273
274 static void print_full_information(void)
275 {
276     static const WCHAR newlineW[] = {'\n',0};
277     static const WCHAR emptyW[] = {0};
278
279     FIXED_INFO *info;
280     IP_ADAPTER_ADDRESSES *adapters;
281     ULONG out = 0;
282
283     if (GetNetworkParams(NULL, &out) == ERROR_BUFFER_OVERFLOW)
284     {
285         info = HeapAlloc(GetProcessHeap(), 0, out);
286         if (!info)
287             exit(1);
288
289         if (GetNetworkParams(info, &out) == ERROR_SUCCESS)
290         {
291             WCHAR hostnameW[MAX_HOSTNAME_LEN + 4];
292
293             MultiByteToWideChar(CP_ACP, 0, info->HostName, -1, hostnameW, sizeof(hostnameW)/sizeof(hostnameW[0]));
294             print_field(STRING_HOSTNAME, hostnameW);
295
296             /* FIXME: Output primary DNS suffix. */
297
298             print_field(STRING_NODE_TYPE, nodetype_to_string(info->NodeType));
299             print_field(STRING_IP_ROUTING, boolean_to_string(info->EnableRouting));
300
301             /* FIXME: Output WINS proxy status and DNS suffix search list. */
302
303             ipconfig_printfW(newlineW);
304         }
305
306         HeapFree(GetProcessHeap(), 0, info);
307     }
308
309     if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_ALL_GATEWAYS,
310                              NULL, NULL, &out) == ERROR_BUFFER_OVERFLOW)
311     {
312         adapters = HeapAlloc(GetProcessHeap(), 0, out);
313         if (!adapters)
314             exit(1);
315
316         if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_ALL_GATEWAYS,
317                                  NULL, adapters, &out) == ERROR_SUCCESS)
318         {
319             IP_ADAPTER_ADDRESSES *p;
320
321             for (p = adapters; p; p = p->Next)
322             {
323                 IP_ADAPTER_UNICAST_ADDRESS *addr;
324                 WCHAR physaddr_buf[3 * MAX_ADAPTER_ADDRESS_LENGTH];
325                 IP_ADAPTER_GATEWAY_ADDRESS_LH *gateway;
326                 WCHAR addr_buf[54];
327
328                 ipconfig_message_printfW(STRING_ADAPTER_FRIENDLY, iftype_to_string(p->IfType), p->FriendlyName);
329                 ipconfig_printfW(newlineW);
330                 print_field(STRING_CONN_DNS_SUFFIX, p->DnsSuffix);
331                 print_field(STRING_DESCRIPTION, p->Description);
332                 print_field(STRING_PHYS_ADDR, physaddr_to_string(physaddr_buf, p->PhysicalAddress, p->PhysicalAddressLength));
333                 print_field(STRING_DHCP_ENABLED, boolean_to_string(p->Flags & IP_ADAPTER_DHCP_ENABLED));
334
335                 /* FIXME: Output autoconfiguration status. */
336
337                 for (addr = p->FirstUnicastAddress; addr; addr = addr->Next)
338                 {
339                     if (socket_address_to_string(addr_buf, sizeof(addr_buf)/sizeof(WCHAR), &addr->Address))
340                         print_field(STRING_IP_ADDRESS, addr_buf);
341                     /* FIXME: Output corresponding subnet mask. */
342                 }
343
344                 if (p->FirstGatewayAddress)
345                 {
346                     if (socket_address_to_string(addr_buf, sizeof(addr_buf)/sizeof(WCHAR), &p->FirstGatewayAddress->Address))
347                         print_field(STRING_DEFAULT_GATEWAY, addr_buf);
348
349                     for (gateway = p->FirstGatewayAddress->Next; gateway; gateway = gateway->Next)
350                     {
351                         if (socket_address_to_string(addr_buf, sizeof(addr_buf)/sizeof(WCHAR), &gateway->Address))
352                             print_value(addr_buf);
353                     }
354                 }
355                 else
356                     print_field(STRING_DEFAULT_GATEWAY, emptyW);
357
358                 ipconfig_printfW(newlineW);
359             }
360         }
361
362         HeapFree(GetProcessHeap(), 0, adapters);
363     }
364 }
365
366 int wmain(int argc, WCHAR *argv[])
367 {
368     static const WCHAR slashHelp[] = {'/','?',0};
369     static const WCHAR slashAll[] = {'/','a','l','l',0};
370
371     WSADATA data;
372
373     if (WSAStartup(MAKEWORD(2, 2), &data))
374         return 1;
375
376     if (argc > 1)
377     {
378         if (!strcmpW(slashHelp, argv[1]))
379         {
380             ipconfig_message(STRING_USAGE);
381             WSACleanup();
382             return 1;
383         }
384         else if (!strcmpiW(slashAll, argv[1]))
385         {
386             if (argv[2])
387             {
388                 ipconfig_message(STRING_INVALID_CMDLINE);
389                 ipconfig_message(STRING_USAGE);
390                 WSACleanup();
391                 return 1;
392             }
393
394             print_full_information();
395         }
396         else
397         {
398             ipconfig_message(STRING_INVALID_CMDLINE);
399             ipconfig_message(STRING_USAGE);
400             WSACleanup();
401             return 1;
402         }
403     }
404     else
405         print_basic_information();
406
407     WSACleanup();
408     return 0;
409 }