ipconfig.c 13 KB

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