ipconfig: Distinguish between IPv4 and IPv6 addresses in normal mode.
[wine.git] / programs / ipconfig / ipconfig.c
blob11ff56b9bd33810ed867c8129439bfe53cc8656e
1 /*
2 * IP configuration utility
4 * Copyright 2008 Andrew Riedi
5 * Copyright 2010 Andrew Nguyen
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.
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.
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
22 #include <winsock2.h>
23 #include <windows.h>
24 #include <iphlpapi.h>
25 #include <wine/unicode.h>
27 #include "ipconfig.h"
29 static int ipconfig_vprintfW(const WCHAR *msg, __ms_va_list va_args)
31 int wlen;
32 DWORD count, ret;
33 WCHAR msg_buffer[8192];
35 wlen = FormatMessageW(FORMAT_MESSAGE_FROM_STRING, msg, 0, 0, msg_buffer,
36 sizeof(msg_buffer)/sizeof(*msg_buffer), &va_args);
38 ret = WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), msg_buffer, wlen, &count, NULL);
39 if (!ret)
41 DWORD len;
42 char *msgA;
44 /* On Windows WriteConsoleW() fails if the output is redirected. So fall
45 * back to WriteFile(), assuming the console encoding is still the right
46 * one in that case.
48 len = WideCharToMultiByte(GetConsoleOutputCP(), 0, msg_buffer, wlen,
49 NULL, 0, NULL, NULL);
50 msgA = HeapAlloc(GetProcessHeap(), 0, len);
51 if (!msgA)
52 return 0;
54 WideCharToMultiByte(GetConsoleOutputCP(), 0, msg_buffer, wlen, msgA, len,
55 NULL, NULL);
56 WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), msgA, len, &count, FALSE);
57 HeapFree(GetProcessHeap(), 0, msgA);
60 return count;
63 static int CDECL ipconfig_printfW(const WCHAR *msg, ...)
65 __ms_va_list va_args;
66 int len;
68 __ms_va_start(va_args, msg);
69 len = ipconfig_vprintfW(msg, va_args);
70 __ms_va_end(va_args);
72 return len;
75 static int CDECL ipconfig_message_printfW(int msg, ...)
77 __ms_va_list va_args;
78 WCHAR msg_buffer[8192];
79 int len;
81 LoadStringW(GetModuleHandleW(NULL), msg, msg_buffer,
82 sizeof(msg_buffer)/sizeof(WCHAR));
84 __ms_va_start(va_args, msg);
85 len = ipconfig_vprintfW(msg_buffer, va_args);
86 __ms_va_end(va_args);
88 return len;
91 static int ipconfig_message(int msg)
93 static const WCHAR formatW[] = {'%','1',0};
94 WCHAR msg_buffer[8192];
96 LoadStringW(GetModuleHandleW(NULL), msg, msg_buffer,
97 sizeof(msg_buffer)/sizeof(WCHAR));
99 return ipconfig_printfW(formatW, msg_buffer);
102 static const WCHAR *iftype_to_string(DWORD type)
104 static WCHAR msg_buffer[50];
106 int msg;
108 switch (type)
110 case IF_TYPE_ETHERNET_CSMACD:
111 /* The loopback adapter appears as an Ethernet device. */
112 case IF_TYPE_SOFTWARE_LOOPBACK:
113 msg = STRING_ETHERNET;
114 break;
115 default:
116 msg = STRING_UNKNOWN;
119 LoadStringW(GetModuleHandleW(NULL), msg, msg_buffer,
120 sizeof(msg_buffer)/sizeof(WCHAR));
122 return msg_buffer;
125 static void print_field(int msg, const WCHAR *value)
127 static const WCHAR formatW[] = {' ',' ',' ',' ','%','1',':',' ','%','2','\n',0};
129 WCHAR field[] = {'.',' ','.',' ','.',' ','.',' ','.',' ','.',' ','.',' ','.',' ','.',
130 ' ','.',' ','.',' ','.',' ','.',' ','.',' ','.',' ','.',' ','.',' ',0};
131 WCHAR name_buffer[sizeof(field)/sizeof(WCHAR)];
133 LoadStringW(GetModuleHandleW(NULL), msg, name_buffer, sizeof(name_buffer)/sizeof(WCHAR));
134 memcpy(field, name_buffer, sizeof(WCHAR) * min(strlenW(name_buffer), sizeof(field)/sizeof(WCHAR) - 1));
136 ipconfig_printfW(formatW, field, value);
139 static void print_value(const WCHAR *value)
141 static const WCHAR formatW[] = {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
142 ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
143 ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
144 ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
145 '%','1','\n',0};
147 ipconfig_printfW(formatW, value);
150 static BOOL socket_address_to_string(WCHAR *buf, DWORD len, SOCKET_ADDRESS *addr)
152 return WSAAddressToStringW(addr->lpSockaddr,
153 addr->iSockaddrLength, NULL,
154 buf, &len) == 0;
157 static void print_basic_information(void)
159 IP_ADAPTER_ADDRESSES *adapters;
160 ULONG out = 0;
162 if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_ALL_GATEWAYS,
163 NULL, NULL, &out) == ERROR_BUFFER_OVERFLOW)
165 adapters = HeapAlloc(GetProcessHeap(), 0, out);
166 if (!adapters)
167 exit(1);
169 if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_ALL_GATEWAYS,
170 NULL, adapters, &out) == ERROR_SUCCESS)
172 IP_ADAPTER_ADDRESSES *p;
174 for (p = adapters; p; p = p->Next)
176 static const WCHAR newlineW[] = {'\n',0};
177 static const WCHAR emptyW[] = {0};
179 IP_ADAPTER_UNICAST_ADDRESS *addr;
180 IP_ADAPTER_GATEWAY_ADDRESS_LH *gateway;
181 WCHAR addr_buf[54];
183 ipconfig_message_printfW(STRING_ADAPTER_FRIENDLY, iftype_to_string(p->IfType), p->FriendlyName);
184 ipconfig_printfW(newlineW);
185 print_field(STRING_CONN_DNS_SUFFIX, p->DnsSuffix);
187 for (addr = p->FirstUnicastAddress; addr; addr = addr->Next)
189 if (addr->Address.lpSockaddr->sa_family == AF_INET &&
190 socket_address_to_string(addr_buf, sizeof(addr_buf)/sizeof(WCHAR), &addr->Address))
191 print_field(STRING_IP_ADDRESS, addr_buf);
192 else if (addr->Address.lpSockaddr->sa_family == AF_INET6 &&
193 socket_address_to_string(addr_buf, sizeof(addr_buf)/sizeof(WCHAR), &addr->Address))
194 print_field(STRING_IP6_ADDRESS, addr_buf);
195 /* FIXME: Output corresponding subnet mask. */
198 if (p->FirstGatewayAddress)
200 if (socket_address_to_string(addr_buf, sizeof(addr_buf)/sizeof(WCHAR), &p->FirstGatewayAddress->Address))
201 print_field(STRING_DEFAULT_GATEWAY, addr_buf);
203 for (gateway = p->FirstGatewayAddress->Next; gateway; gateway = gateway->Next)
205 if (socket_address_to_string(addr_buf, sizeof(addr_buf)/sizeof(WCHAR), &gateway->Address))
206 print_value(addr_buf);
209 else
210 print_field(STRING_DEFAULT_GATEWAY, emptyW);
212 ipconfig_printfW(newlineW);
216 HeapFree(GetProcessHeap(), 0, adapters);
220 static const WCHAR *nodetype_to_string(DWORD type)
222 static WCHAR msg_buffer[50];
224 int msg;
226 switch (type)
228 case BROADCAST_NODETYPE:
229 msg = STRING_BROADCAST;
230 break;
231 case PEER_TO_PEER_NODETYPE:
232 msg = STRING_PEER_TO_PEER;
233 break;
234 case MIXED_NODETYPE:
235 msg = STRING_MIXED;
236 break;
237 case HYBRID_NODETYPE:
238 msg = STRING_HYBRID;
239 break;
240 default:
241 msg = STRING_UNKNOWN;
244 LoadStringW(GetModuleHandleW(NULL), msg, msg_buffer,
245 sizeof(msg_buffer)/sizeof(WCHAR));
247 return msg_buffer;
250 static WCHAR *physaddr_to_string(WCHAR *buf, BYTE *addr, DWORD len)
252 static const WCHAR fmtW[] = {'%','0','2','X','-',0};
253 static const WCHAR fmt2W[] = {'%','0','2','X',0};
255 if (!len)
256 *buf = '\0';
257 else
259 WCHAR *p = buf;
260 DWORD i;
262 for (i = 0; i < len - 1; i++)
264 sprintfW(p, fmtW, addr[i]);
265 p += 3;
267 sprintfW(p, fmt2W, addr[i]);
270 return buf;
273 static const WCHAR *boolean_to_string(int value)
275 static WCHAR msg_buffer[15];
277 LoadStringW(GetModuleHandleW(NULL), value ? STRING_YES : STRING_NO,
278 msg_buffer, sizeof(msg_buffer)/sizeof(WCHAR));
280 return msg_buffer;
283 static void print_full_information(void)
285 static const WCHAR newlineW[] = {'\n',0};
286 static const WCHAR emptyW[] = {0};
288 FIXED_INFO *info;
289 IP_ADAPTER_ADDRESSES *adapters;
290 ULONG out = 0;
292 if (GetNetworkParams(NULL, &out) == ERROR_BUFFER_OVERFLOW)
294 info = HeapAlloc(GetProcessHeap(), 0, out);
295 if (!info)
296 exit(1);
298 if (GetNetworkParams(info, &out) == ERROR_SUCCESS)
300 WCHAR hostnameW[MAX_HOSTNAME_LEN + 4];
302 MultiByteToWideChar(CP_ACP, 0, info->HostName, -1, hostnameW, sizeof(hostnameW)/sizeof(hostnameW[0]));
303 print_field(STRING_HOSTNAME, hostnameW);
305 /* FIXME: Output primary DNS suffix. */
307 print_field(STRING_NODE_TYPE, nodetype_to_string(info->NodeType));
308 print_field(STRING_IP_ROUTING, boolean_to_string(info->EnableRouting));
310 /* FIXME: Output WINS proxy status and DNS suffix search list. */
312 ipconfig_printfW(newlineW);
315 HeapFree(GetProcessHeap(), 0, info);
318 if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_ALL_GATEWAYS,
319 NULL, NULL, &out) == ERROR_BUFFER_OVERFLOW)
321 adapters = HeapAlloc(GetProcessHeap(), 0, out);
322 if (!adapters)
323 exit(1);
325 if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_ALL_GATEWAYS,
326 NULL, adapters, &out) == ERROR_SUCCESS)
328 IP_ADAPTER_ADDRESSES *p;
330 for (p = adapters; p; p = p->Next)
332 IP_ADAPTER_UNICAST_ADDRESS *addr;
333 WCHAR physaddr_buf[3 * MAX_ADAPTER_ADDRESS_LENGTH];
334 IP_ADAPTER_GATEWAY_ADDRESS_LH *gateway;
335 WCHAR addr_buf[54];
337 ipconfig_message_printfW(STRING_ADAPTER_FRIENDLY, iftype_to_string(p->IfType), p->FriendlyName);
338 ipconfig_printfW(newlineW);
339 print_field(STRING_CONN_DNS_SUFFIX, p->DnsSuffix);
340 print_field(STRING_DESCRIPTION, p->Description);
341 print_field(STRING_PHYS_ADDR, physaddr_to_string(physaddr_buf, p->PhysicalAddress, p->PhysicalAddressLength));
342 print_field(STRING_DHCP_ENABLED, boolean_to_string(p->Flags & IP_ADAPTER_DHCP_ENABLED));
344 /* FIXME: Output autoconfiguration status. */
346 for (addr = p->FirstUnicastAddress; addr; addr = addr->Next)
348 if (addr->Address.lpSockaddr->sa_family == AF_INET &&
349 socket_address_to_string(addr_buf, sizeof(addr_buf)/sizeof(WCHAR), &addr->Address))
350 print_field(STRING_IP_ADDRESS, addr_buf);
351 else if (addr->Address.lpSockaddr->sa_family == AF_INET6 &&
352 socket_address_to_string(addr_buf, sizeof(addr_buf)/sizeof(WCHAR), &addr->Address))
353 print_field(STRING_IP6_ADDRESS, addr_buf);
354 /* FIXME: Output corresponding subnet mask. */
357 if (p->FirstGatewayAddress)
359 if (socket_address_to_string(addr_buf, sizeof(addr_buf)/sizeof(WCHAR), &p->FirstGatewayAddress->Address))
360 print_field(STRING_DEFAULT_GATEWAY, addr_buf);
362 for (gateway = p->FirstGatewayAddress->Next; gateway; gateway = gateway->Next)
364 if (socket_address_to_string(addr_buf, sizeof(addr_buf)/sizeof(WCHAR), &gateway->Address))
365 print_value(addr_buf);
368 else
369 print_field(STRING_DEFAULT_GATEWAY, emptyW);
371 ipconfig_printfW(newlineW);
375 HeapFree(GetProcessHeap(), 0, adapters);
379 int wmain(int argc, WCHAR *argv[])
381 static const WCHAR slashHelp[] = {'/','?',0};
382 static const WCHAR slashAll[] = {'/','a','l','l',0};
384 WSADATA data;
386 if (WSAStartup(MAKEWORD(2, 2), &data))
387 return 1;
389 if (argc > 1)
391 if (!strcmpW(slashHelp, argv[1]))
393 ipconfig_message(STRING_USAGE);
394 WSACleanup();
395 return 1;
397 else if (!strcmpiW(slashAll, argv[1]))
399 if (argv[2])
401 ipconfig_message(STRING_INVALID_CMDLINE);
402 ipconfig_message(STRING_USAGE);
403 WSACleanup();
404 return 1;
407 print_full_information();
409 else
411 ipconfig_message(STRING_INVALID_CMDLINE);
412 ipconfig_message(STRING_USAGE);
413 WSACleanup();
414 return 1;
417 else
418 print_basic_information();
420 WSACleanup();
421 return 0;