/* * IP configuration utility * * Copyright 2008 Andrew Riedi * Copyright 2010 Andrew Nguyen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #define NONAMELESSUNION #include #include #include #include #include "ipconfig.h" static int ipconfig_vprintfW(const WCHAR *msg, va_list va_args) { int wlen; DWORD count; WCHAR msg_buffer[8192]; wlen = FormatMessageW(FORMAT_MESSAGE_FROM_STRING, msg, 0, 0, msg_buffer, ARRAY_SIZE(msg_buffer), &va_args); if (!WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), msg_buffer, wlen, &count, NULL)) { DWORD len; char *msgA; /* On Windows WriteConsoleW() fails if the output is redirected. So fall * back to WriteFile() with OEM code page. */ len = WideCharToMultiByte(GetOEMCP(), 0, msg_buffer, wlen, NULL, 0, NULL, NULL); msgA = HeapAlloc(GetProcessHeap(), 0, len); if (!msgA) return 0; WideCharToMultiByte(GetOEMCP(), 0, msg_buffer, wlen, msgA, len, NULL, NULL); WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), msgA, len, &count, FALSE); HeapFree(GetProcessHeap(), 0, msgA); } return count; } static int WINAPIV ipconfig_printfW(const WCHAR *msg, ...) { va_list va_args; int len; va_start(va_args, msg); len = ipconfig_vprintfW(msg, va_args); va_end(va_args); return len; } static int WINAPIV ipconfig_message_printfW(int msg, ...) { va_list va_args; WCHAR msg_buffer[8192]; int len; LoadStringW(GetModuleHandleW(NULL), msg, msg_buffer, ARRAY_SIZE(msg_buffer)); va_start(va_args, msg); len = ipconfig_vprintfW(msg_buffer, va_args); va_end(va_args); return len; } static int ipconfig_message(int msg) { WCHAR msg_buffer[8192]; LoadStringW(GetModuleHandleW(NULL), msg, msg_buffer, ARRAY_SIZE(msg_buffer)); return ipconfig_printfW(L"%1", msg_buffer); } static const WCHAR *iftype_to_string(DWORD type) { static WCHAR msg_buffer[50]; int msg; switch (type) { case IF_TYPE_ETHERNET_CSMACD: /* The loopback adapter appears as an Ethernet device. */ case IF_TYPE_SOFTWARE_LOOPBACK: msg = STRING_ETHERNET; break; default: msg = STRING_UNKNOWN; } LoadStringW(GetModuleHandleW(NULL), msg, msg_buffer, ARRAY_SIZE(msg_buffer)); return msg_buffer; } static void print_field(int msg, const WCHAR *value) { WCHAR field[] = L". . . . . . . . . . . . . . . . . "; WCHAR name_buffer[ARRAY_SIZE(field)]; LoadStringW(GetModuleHandleW(NULL), msg, name_buffer, ARRAY_SIZE(name_buffer)); memcpy(field, name_buffer, sizeof(WCHAR) * min(lstrlenW(name_buffer), ARRAY_SIZE(field) - 1)); ipconfig_printfW(L" %1: %2\n", field, value); } static void print_value(const WCHAR *value) { ipconfig_printfW(L" %1\n", value); } static BOOL socket_address_to_string(WCHAR *buf, DWORD len, SOCKET_ADDRESS *addr) { return WSAAddressToStringW(addr->lpSockaddr, addr->iSockaddrLength, NULL, buf, &len) == 0; } static void print_basic_information(void) { IP_ADAPTER_ADDRESSES *adapters; ULONG out = 0; if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_ALL_GATEWAYS, NULL, NULL, &out) == ERROR_BUFFER_OVERFLOW) { adapters = HeapAlloc(GetProcessHeap(), 0, out); if (!adapters) exit(1); if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_ALL_GATEWAYS, NULL, adapters, &out) == ERROR_SUCCESS) { IP_ADAPTER_ADDRESSES *p; for (p = adapters; p; p = p->Next) { IP_ADAPTER_UNICAST_ADDRESS *addr; IP_ADAPTER_GATEWAY_ADDRESS_LH *gateway; WCHAR addr_buf[54]; ipconfig_message_printfW(STRING_ADAPTER_FRIENDLY, iftype_to_string(p->IfType), p->FriendlyName); ipconfig_printfW(L"\n"); print_field(STRING_CONN_DNS_SUFFIX, p->DnsSuffix); for (addr = p->FirstUnicastAddress; addr; addr = addr->Next) { if (addr->Address.lpSockaddr->sa_family == AF_INET && socket_address_to_string(addr_buf, ARRAY_SIZE(addr_buf), &addr->Address)) print_field(STRING_IP_ADDRESS, addr_buf); else if (addr->Address.lpSockaddr->sa_family == AF_INET6 && socket_address_to_string(addr_buf, ARRAY_SIZE(addr_buf), &addr->Address)) print_field(STRING_IP6_ADDRESS, addr_buf); /* FIXME: Output corresponding subnet mask. */ } if (p->FirstGatewayAddress) { if (socket_address_to_string(addr_buf, ARRAY_SIZE(addr_buf), &p->FirstGatewayAddress->Address)) print_field(STRING_DEFAULT_GATEWAY, addr_buf); for (gateway = p->FirstGatewayAddress->Next; gateway; gateway = gateway->Next) { if (socket_address_to_string(addr_buf, ARRAY_SIZE(addr_buf), &gateway->Address)) print_value(addr_buf); } } else print_field(STRING_DEFAULT_GATEWAY, L""); ipconfig_printfW(L"\n"); } } HeapFree(GetProcessHeap(), 0, adapters); } } static const WCHAR *nodetype_to_string(DWORD type) { static WCHAR msg_buffer[50]; int msg; switch (type) { case BROADCAST_NODETYPE: msg = STRING_BROADCAST; break; case PEER_TO_PEER_NODETYPE: msg = STRING_PEER_TO_PEER; break; case MIXED_NODETYPE: msg = STRING_MIXED; break; case HYBRID_NODETYPE: msg = STRING_HYBRID; break; default: msg = STRING_UNKNOWN; } LoadStringW(GetModuleHandleW(NULL), msg, msg_buffer, ARRAY_SIZE(msg_buffer)); return msg_buffer; } static WCHAR *physaddr_to_string(WCHAR *buf, BYTE *addr, DWORD len) { if (!len) *buf = '\0'; else { WCHAR *p = buf; DWORD i; for (i = 0; i < len - 1; i++) { swprintf(p, 4, L"%02X-", addr[i]); p += 3; } swprintf(p, 3, L"%02X", addr[i]); } return buf; } static const WCHAR *boolean_to_string(int value) { static WCHAR msg_buffer[15]; LoadStringW(GetModuleHandleW(NULL), value ? STRING_YES : STRING_NO, msg_buffer, ARRAY_SIZE(msg_buffer)); return msg_buffer; } static void print_full_information(void) { FIXED_INFO *info; IP_ADAPTER_ADDRESSES *adapters; ULONG out = 0; if (GetNetworkParams(NULL, &out) == ERROR_BUFFER_OVERFLOW) { info = HeapAlloc(GetProcessHeap(), 0, out); if (!info) exit(1); if (GetNetworkParams(info, &out) == ERROR_SUCCESS) { WCHAR hostnameW[MAX_HOSTNAME_LEN + 4]; WCHAR dnssuffixW[MAX_DOMAIN_NAME_LEN + 4]; MultiByteToWideChar(CP_ACP, 0, info->HostName, -1, hostnameW, ARRAY_SIZE(hostnameW)); print_field(STRING_HOSTNAME, hostnameW); MultiByteToWideChar(CP_ACP, 0, info->DomainName, -1, dnssuffixW, ARRAY_SIZE(dnssuffixW)); print_field(STRING_PRIMARY_DNS_SUFFIX, dnssuffixW); print_field(STRING_NODE_TYPE, nodetype_to_string(info->NodeType)); print_field(STRING_IP_ROUTING, boolean_to_string(info->EnableRouting)); /* FIXME: Output WINS proxy status and DNS suffix search list. */ ipconfig_printfW(L"\n"); } HeapFree(GetProcessHeap(), 0, info); } if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_ALL_GATEWAYS, NULL, NULL, &out) == ERROR_BUFFER_OVERFLOW) { adapters = HeapAlloc(GetProcessHeap(), 0, out); if (!adapters) exit(1); if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_ALL_GATEWAYS, NULL, adapters, &out) == ERROR_SUCCESS) { IP_ADAPTER_ADDRESSES *p; for (p = adapters; p; p = p->Next) { IP_ADAPTER_UNICAST_ADDRESS *addr; WCHAR physaddr_buf[3 * MAX_ADAPTER_ADDRESS_LENGTH]; IP_ADAPTER_GATEWAY_ADDRESS_LH *gateway; WCHAR addr_buf[54]; ipconfig_message_printfW(STRING_ADAPTER_FRIENDLY, iftype_to_string(p->IfType), p->FriendlyName); ipconfig_printfW(L"\n"); print_field(STRING_CONN_DNS_SUFFIX, p->DnsSuffix); print_field(STRING_DESCRIPTION, p->Description); print_field(STRING_PHYS_ADDR, physaddr_to_string(physaddr_buf, p->PhysicalAddress, p->PhysicalAddressLength)); print_field(STRING_DHCP_ENABLED, boolean_to_string(p->u1.Flags & IP_ADAPTER_DHCP_ENABLED)); /* FIXME: Output autoconfiguration status. */ for (addr = p->FirstUnicastAddress; addr; addr = addr->Next) { if (addr->Address.lpSockaddr->sa_family == AF_INET && socket_address_to_string(addr_buf, ARRAY_SIZE(addr_buf), &addr->Address)) print_field(STRING_IP_ADDRESS, addr_buf); else if (addr->Address.lpSockaddr->sa_family == AF_INET6 && socket_address_to_string(addr_buf, ARRAY_SIZE(addr_buf), &addr->Address)) print_field(STRING_IP6_ADDRESS, addr_buf); /* FIXME: Output corresponding subnet mask. */ } if (p->FirstGatewayAddress) { if (socket_address_to_string(addr_buf, ARRAY_SIZE(addr_buf), &p->FirstGatewayAddress->Address)) print_field(STRING_DEFAULT_GATEWAY, addr_buf); for (gateway = p->FirstGatewayAddress->Next; gateway; gateway = gateway->Next) { if (socket_address_to_string(addr_buf, ARRAY_SIZE(addr_buf), &gateway->Address)) print_value(addr_buf); } } else print_field(STRING_DEFAULT_GATEWAY, L""); ipconfig_printfW(L"\n"); } } HeapFree(GetProcessHeap(), 0, adapters); } } int __cdecl wmain(int argc, WCHAR *argv[]) { WSADATA data; if (WSAStartup(MAKEWORD(2, 2), &data)) return 1; if (argc > 1) { if (!lstrcmpW(L"/?", argv[1])) { ipconfig_message(STRING_USAGE); WSACleanup(); return 1; } else if (!wcsicmp(L"/all", argv[1])) { if (argv[2]) { ipconfig_message(STRING_INVALID_CMDLINE); ipconfig_message(STRING_USAGE); WSACleanup(); return 1; } print_full_information(); } else { ipconfig_message(STRING_INVALID_CMDLINE); ipconfig_message(STRING_USAGE); WSACleanup(); return 1; } } else print_basic_information(); WSACleanup(); return 0; }