ipconfig.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  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. #define NONAMELESSUNION
  22. #include <stdio.h>
  23. #include <winsock2.h>
  24. #include <windows.h>
  25. #include <iphlpapi.h>
  26. #include "ipconfig.h"
  27. static int ipconfig_vprintfW(const WCHAR *msg, va_list va_args)
  28. {
  29. int wlen;
  30. DWORD count, ret;
  31. WCHAR msg_buffer[8192];
  32. wlen = FormatMessageW(FORMAT_MESSAGE_FROM_STRING, msg, 0, 0, msg_buffer,
  33. ARRAY_SIZE(msg_buffer), &va_args);
  34. ret = WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), msg_buffer, wlen, &count, NULL);
  35. if (!ret)
  36. {
  37. DWORD len;
  38. char *msgA;
  39. /* On Windows WriteConsoleW() fails if the output is redirected. So fall
  40. * back to WriteFile(), assuming the console encoding is still the right
  41. * one in that case.
  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. WideCharToMultiByte(GetConsoleOutputCP(), 0, msg_buffer, wlen, msgA, len,
  49. NULL, NULL);
  50. WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), msgA, len, &count, FALSE);
  51. HeapFree(GetProcessHeap(), 0, msgA);
  52. }
  53. return count;
  54. }
  55. static int WINAPIV ipconfig_printfW(const WCHAR *msg, ...)
  56. {
  57. va_list va_args;
  58. int len;
  59. va_start(va_args, msg);
  60. len = ipconfig_vprintfW(msg, va_args);
  61. va_end(va_args);
  62. return len;
  63. }
  64. static int WINAPIV ipconfig_message_printfW(int msg, ...)
  65. {
  66. va_list va_args;
  67. WCHAR msg_buffer[8192];
  68. int len;
  69. LoadStringW(GetModuleHandleW(NULL), msg, msg_buffer, ARRAY_SIZE(msg_buffer));
  70. va_start(va_args, msg);
  71. len = ipconfig_vprintfW(msg_buffer, va_args);
  72. va_end(va_args);
  73. return len;
  74. }
  75. static int ipconfig_message(int msg)
  76. {
  77. WCHAR msg_buffer[8192];
  78. LoadStringW(GetModuleHandleW(NULL), msg, msg_buffer, ARRAY_SIZE(msg_buffer));
  79. return ipconfig_printfW(L"%1", msg_buffer);
  80. }
  81. static const WCHAR *iftype_to_string(DWORD type)
  82. {
  83. static WCHAR msg_buffer[50];
  84. int msg;
  85. switch (type)
  86. {
  87. case IF_TYPE_ETHERNET_CSMACD:
  88. /* The loopback adapter appears as an Ethernet device. */
  89. case IF_TYPE_SOFTWARE_LOOPBACK:
  90. msg = STRING_ETHERNET;
  91. break;
  92. default:
  93. msg = STRING_UNKNOWN;
  94. }
  95. LoadStringW(GetModuleHandleW(NULL), msg, msg_buffer, ARRAY_SIZE(msg_buffer));
  96. return msg_buffer;
  97. }
  98. static void print_field(int msg, const WCHAR *value)
  99. {
  100. WCHAR field[] = L". . . . . . . . . . . . . . . . . ";
  101. WCHAR name_buffer[ARRAY_SIZE(field)];
  102. LoadStringW(GetModuleHandleW(NULL), msg, name_buffer, ARRAY_SIZE(name_buffer));
  103. memcpy(field, name_buffer, sizeof(WCHAR) * min(lstrlenW(name_buffer), ARRAY_SIZE(field) - 1));
  104. ipconfig_printfW(L" %1: %2\n", field, value);
  105. }
  106. static void print_value(const WCHAR *value)
  107. {
  108. ipconfig_printfW(L" %1\n", value);
  109. }
  110. static BOOL socket_address_to_string(WCHAR *buf, DWORD len, SOCKET_ADDRESS *addr)
  111. {
  112. return WSAAddressToStringW(addr->lpSockaddr,
  113. addr->iSockaddrLength, NULL,
  114. buf, &len) == 0;
  115. }
  116. static void print_basic_information(void)
  117. {
  118. IP_ADAPTER_ADDRESSES *adapters;
  119. ULONG out = 0;
  120. if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_ALL_GATEWAYS,
  121. NULL, NULL, &out) == ERROR_BUFFER_OVERFLOW)
  122. {
  123. adapters = HeapAlloc(GetProcessHeap(), 0, out);
  124. if (!adapters)
  125. exit(1);
  126. if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_ALL_GATEWAYS,
  127. NULL, adapters, &out) == ERROR_SUCCESS)
  128. {
  129. IP_ADAPTER_ADDRESSES *p;
  130. for (p = adapters; p; p = p->Next)
  131. {
  132. IP_ADAPTER_UNICAST_ADDRESS *addr;
  133. IP_ADAPTER_GATEWAY_ADDRESS_LH *gateway;
  134. WCHAR addr_buf[54];
  135. ipconfig_message_printfW(STRING_ADAPTER_FRIENDLY, iftype_to_string(p->IfType), p->FriendlyName);
  136. ipconfig_printfW(L"\n");
  137. print_field(STRING_CONN_DNS_SUFFIX, p->DnsSuffix);
  138. for (addr = p->FirstUnicastAddress; addr; addr = addr->Next)
  139. {
  140. if (addr->Address.lpSockaddr->sa_family == AF_INET &&
  141. socket_address_to_string(addr_buf, ARRAY_SIZE(addr_buf), &addr->Address))
  142. print_field(STRING_IP_ADDRESS, addr_buf);
  143. else if (addr->Address.lpSockaddr->sa_family == AF_INET6 &&
  144. socket_address_to_string(addr_buf, ARRAY_SIZE(addr_buf), &addr->Address))
  145. print_field(STRING_IP6_ADDRESS, addr_buf);
  146. /* FIXME: Output corresponding subnet mask. */
  147. }
  148. if (p->FirstGatewayAddress)
  149. {
  150. if (socket_address_to_string(addr_buf, ARRAY_SIZE(addr_buf), &p->FirstGatewayAddress->Address))
  151. print_field(STRING_DEFAULT_GATEWAY, addr_buf);
  152. for (gateway = p->FirstGatewayAddress->Next; gateway; gateway = gateway->Next)
  153. {
  154. if (socket_address_to_string(addr_buf, ARRAY_SIZE(addr_buf), &gateway->Address))
  155. print_value(addr_buf);
  156. }
  157. }
  158. else
  159. print_field(STRING_DEFAULT_GATEWAY, L"");
  160. ipconfig_printfW(L"\n");
  161. }
  162. }
  163. HeapFree(GetProcessHeap(), 0, adapters);
  164. }
  165. }
  166. static const WCHAR *nodetype_to_string(DWORD type)
  167. {
  168. static WCHAR msg_buffer[50];
  169. int msg;
  170. switch (type)
  171. {
  172. case BROADCAST_NODETYPE:
  173. msg = STRING_BROADCAST;
  174. break;
  175. case PEER_TO_PEER_NODETYPE:
  176. msg = STRING_PEER_TO_PEER;
  177. break;
  178. case MIXED_NODETYPE:
  179. msg = STRING_MIXED;
  180. break;
  181. case HYBRID_NODETYPE:
  182. msg = STRING_HYBRID;
  183. break;
  184. default:
  185. msg = STRING_UNKNOWN;
  186. }
  187. LoadStringW(GetModuleHandleW(NULL), msg, msg_buffer, ARRAY_SIZE(msg_buffer));
  188. return msg_buffer;
  189. }
  190. static WCHAR *physaddr_to_string(WCHAR *buf, BYTE *addr, DWORD len)
  191. {
  192. if (!len)
  193. *buf = '\0';
  194. else
  195. {
  196. WCHAR *p = buf;
  197. DWORD i;
  198. for (i = 0; i < len - 1; i++)
  199. {
  200. swprintf(p, 4, L"%02X-", addr[i]);
  201. p += 3;
  202. }
  203. swprintf(p, 3, L"%02X", addr[i]);
  204. }
  205. return buf;
  206. }
  207. static const WCHAR *boolean_to_string(int value)
  208. {
  209. static WCHAR msg_buffer[15];
  210. LoadStringW(GetModuleHandleW(NULL), value ? STRING_YES : STRING_NO,
  211. msg_buffer, ARRAY_SIZE(msg_buffer));
  212. return msg_buffer;
  213. }
  214. static void print_full_information(void)
  215. {
  216. FIXED_INFO *info;
  217. IP_ADAPTER_ADDRESSES *adapters;
  218. ULONG out = 0;
  219. if (GetNetworkParams(NULL, &out) == ERROR_BUFFER_OVERFLOW)
  220. {
  221. info = HeapAlloc(GetProcessHeap(), 0, out);
  222. if (!info)
  223. exit(1);
  224. if (GetNetworkParams(info, &out) == ERROR_SUCCESS)
  225. {
  226. WCHAR hostnameW[MAX_HOSTNAME_LEN + 4];
  227. WCHAR dnssuffixW[MAX_DOMAIN_NAME_LEN + 4];
  228. MultiByteToWideChar(CP_ACP, 0, info->HostName, -1, hostnameW, ARRAY_SIZE(hostnameW));
  229. print_field(STRING_HOSTNAME, hostnameW);
  230. MultiByteToWideChar(CP_ACP, 0, info->DomainName, -1, dnssuffixW, ARRAY_SIZE(dnssuffixW));
  231. print_field(STRING_PRIMARY_DNS_SUFFIX, dnssuffixW);
  232. print_field(STRING_NODE_TYPE, nodetype_to_string(info->NodeType));
  233. print_field(STRING_IP_ROUTING, boolean_to_string(info->EnableRouting));
  234. /* FIXME: Output WINS proxy status and DNS suffix search list. */
  235. ipconfig_printfW(L"\n");
  236. }
  237. HeapFree(GetProcessHeap(), 0, info);
  238. }
  239. if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_ALL_GATEWAYS,
  240. NULL, NULL, &out) == ERROR_BUFFER_OVERFLOW)
  241. {
  242. adapters = HeapAlloc(GetProcessHeap(), 0, out);
  243. if (!adapters)
  244. exit(1);
  245. if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_ALL_GATEWAYS,
  246. NULL, adapters, &out) == ERROR_SUCCESS)
  247. {
  248. IP_ADAPTER_ADDRESSES *p;
  249. for (p = adapters; p; p = p->Next)
  250. {
  251. IP_ADAPTER_UNICAST_ADDRESS *addr;
  252. WCHAR physaddr_buf[3 * MAX_ADAPTER_ADDRESS_LENGTH];
  253. IP_ADAPTER_GATEWAY_ADDRESS_LH *gateway;
  254. WCHAR addr_buf[54];
  255. ipconfig_message_printfW(STRING_ADAPTER_FRIENDLY, iftype_to_string(p->IfType), p->FriendlyName);
  256. ipconfig_printfW(L"\n");
  257. print_field(STRING_CONN_DNS_SUFFIX, p->DnsSuffix);
  258. print_field(STRING_DESCRIPTION, p->Description);
  259. print_field(STRING_PHYS_ADDR, physaddr_to_string(physaddr_buf, p->PhysicalAddress, p->PhysicalAddressLength));
  260. print_field(STRING_DHCP_ENABLED, boolean_to_string(p->u1.Flags & IP_ADAPTER_DHCP_ENABLED));
  261. /* FIXME: Output autoconfiguration status. */
  262. for (addr = p->FirstUnicastAddress; addr; addr = addr->Next)
  263. {
  264. if (addr->Address.lpSockaddr->sa_family == AF_INET &&
  265. socket_address_to_string(addr_buf, ARRAY_SIZE(addr_buf), &addr->Address))
  266. print_field(STRING_IP_ADDRESS, addr_buf);
  267. else if (addr->Address.lpSockaddr->sa_family == AF_INET6 &&
  268. socket_address_to_string(addr_buf, ARRAY_SIZE(addr_buf), &addr->Address))
  269. print_field(STRING_IP6_ADDRESS, addr_buf);
  270. /* FIXME: Output corresponding subnet mask. */
  271. }
  272. if (p->FirstGatewayAddress)
  273. {
  274. if (socket_address_to_string(addr_buf, ARRAY_SIZE(addr_buf), &p->FirstGatewayAddress->Address))
  275. print_field(STRING_DEFAULT_GATEWAY, addr_buf);
  276. for (gateway = p->FirstGatewayAddress->Next; gateway; gateway = gateway->Next)
  277. {
  278. if (socket_address_to_string(addr_buf, ARRAY_SIZE(addr_buf), &gateway->Address))
  279. print_value(addr_buf);
  280. }
  281. }
  282. else
  283. print_field(STRING_DEFAULT_GATEWAY, L"");
  284. ipconfig_printfW(L"\n");
  285. }
  286. }
  287. HeapFree(GetProcessHeap(), 0, adapters);
  288. }
  289. }
  290. int __cdecl wmain(int argc, WCHAR *argv[])
  291. {
  292. WSADATA data;
  293. if (WSAStartup(MAKEWORD(2, 2), &data))
  294. return 1;
  295. if (argc > 1)
  296. {
  297. if (!lstrcmpW(L"/?", argv[1]))
  298. {
  299. ipconfig_message(STRING_USAGE);
  300. WSACleanup();
  301. return 1;
  302. }
  303. else if (!wcsicmp(L"/all", argv[1]))
  304. {
  305. if (argv[2])
  306. {
  307. ipconfig_message(STRING_INVALID_CMDLINE);
  308. ipconfig_message(STRING_USAGE);
  309. WSACleanup();
  310. return 1;
  311. }
  312. print_full_information();
  313. }
  314. else
  315. {
  316. ipconfig_message(STRING_INVALID_CMDLINE);
  317. ipconfig_message(STRING_USAGE);
  318. WSACleanup();
  319. return 1;
  320. }
  321. }
  322. else
  323. print_basic_information();
  324. WSACleanup();
  325. return 0;
  326. }