Sweden-Number/programs/ipconfig/ipconfig.c

415 lines
12 KiB
C

/*
* 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
*/
#include <winsock2.h>
#include <windows.h>
#include <iphlpapi.h>
#include <wine/unicode.h>
#include "ipconfig.h"
static int ipconfig_vprintfW(const WCHAR *msg, __ms_va_list va_args)
{
int wlen;
DWORD count, ret;
WCHAR msg_buffer[8192];
wlen = FormatMessageW(FORMAT_MESSAGE_FROM_STRING, msg, 0, 0, msg_buffer,
sizeof(msg_buffer)/sizeof(*msg_buffer), &va_args);
ret = WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), msg_buffer, wlen, &count, NULL);
if (!ret)
{
DWORD len;
char *msgA;
/* On Windows WriteConsoleW() fails if the output is redirected. So fall
* back to WriteFile(), assuming the console encoding is still the right
* one in that case.
*/
len = WideCharToMultiByte(GetConsoleOutputCP(), 0, msg_buffer, wlen,
NULL, 0, NULL, NULL);
msgA = HeapAlloc(GetProcessHeap(), 0, len);
if (!msgA)
return 0;
WideCharToMultiByte(GetConsoleOutputCP(), 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 CDECL ipconfig_printfW(const WCHAR *msg, ...)
{
__ms_va_list va_args;
int len;
__ms_va_start(va_args, msg);
len = ipconfig_vprintfW(msg, va_args);
__ms_va_end(va_args);
return len;
}
static int CDECL ipconfig_message_printfW(int msg, ...)
{
__ms_va_list va_args;
WCHAR msg_buffer[8192];
int len;
LoadStringW(GetModuleHandleW(NULL), msg, msg_buffer,
sizeof(msg_buffer)/sizeof(WCHAR));
__ms_va_start(va_args, msg);
len = ipconfig_vprintfW(msg_buffer, va_args);
__ms_va_end(va_args);
return len;
}
static int ipconfig_message(int msg)
{
static const WCHAR formatW[] = {'%','1',0};
WCHAR msg_buffer[8192];
LoadStringW(GetModuleHandleW(NULL), msg, msg_buffer,
sizeof(msg_buffer)/sizeof(WCHAR));
return ipconfig_printfW(formatW, 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,
sizeof(msg_buffer)/sizeof(WCHAR));
return msg_buffer;
}
static void print_field(int msg, const WCHAR *value)
{
static const WCHAR formatW[] = {' ',' ',' ',' ','%','1',':',' ','%','2','\n',0};
WCHAR field[] = {'.',' ','.',' ','.',' ','.',' ','.',' ','.',' ','.',' ','.',' ','.',
' ','.',' ','.',' ','.',' ','.',' ','.',' ','.',' ','.',' ','.',' ',0};
WCHAR name_buffer[sizeof(field)/sizeof(WCHAR)];
LoadStringW(GetModuleHandleW(NULL), msg, name_buffer, sizeof(name_buffer)/sizeof(WCHAR));
memcpy(field, name_buffer, sizeof(WCHAR) * min(strlenW(name_buffer), sizeof(field)/sizeof(WCHAR) - 1));
ipconfig_printfW(formatW, field, value);
}
static void print_value(const WCHAR *value)
{
static const WCHAR formatW[] = {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
'%','1','\n',0};
ipconfig_printfW(formatW, 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)
{
static const WCHAR newlineW[] = {'\n',0};
static const WCHAR emptyW[] = {0};
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(newlineW);
print_field(STRING_CONN_DNS_SUFFIX, p->DnsSuffix);
for (addr = p->FirstUnicastAddress; addr; addr = addr->Next)
{
if (socket_address_to_string(addr_buf, sizeof(addr_buf)/sizeof(WCHAR), &addr->Address))
print_field(STRING_IP_ADDRESS, addr_buf);
/* FIXME: Output corresponding subnet mask. */
}
if (p->FirstGatewayAddress)
{
if (socket_address_to_string(addr_buf, sizeof(addr_buf)/sizeof(WCHAR), &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, sizeof(addr_buf)/sizeof(WCHAR), &gateway->Address))
print_value(addr_buf);
}
}
else
print_field(STRING_DEFAULT_GATEWAY, emptyW);
ipconfig_printfW(newlineW);
}
}
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,
sizeof(msg_buffer)/sizeof(WCHAR));
return msg_buffer;
}
static WCHAR *physaddr_to_string(WCHAR *buf, BYTE *addr, DWORD len)
{
static const WCHAR fmtW[] = {'%','0','2','X','-',0};
static const WCHAR fmt2W[] = {'%','0','2','X',0};
if (!len)
*buf = '\0';
else
{
WCHAR *p = buf;
DWORD i;
for (i = 0; i < len - 1; i++)
{
sprintfW(p, fmtW, addr[i]);
p += 3;
}
sprintfW(p, fmt2W, 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, sizeof(msg_buffer)/sizeof(WCHAR));
return msg_buffer;
}
static void print_full_information(void)
{
static const WCHAR newlineW[] = {'\n',0};
static const WCHAR emptyW[] = {0};
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];
MultiByteToWideChar(CP_ACP, 0, info->HostName, -1, hostnameW, sizeof(hostnameW)/sizeof(hostnameW[0]));
print_field(STRING_HOSTNAME, hostnameW);
/* FIXME: Output primary DNS suffix. */
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(newlineW);
}
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(newlineW);
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->Flags & IP_ADAPTER_DHCP_ENABLED));
/* FIXME: Output autoconfiguration status. */
for (addr = p->FirstUnicastAddress; addr; addr = addr->Next)
{
if (socket_address_to_string(addr_buf, sizeof(addr_buf)/sizeof(WCHAR), &addr->Address))
print_field(STRING_IP_ADDRESS, addr_buf);
/* FIXME: Output corresponding subnet mask. */
}
if (p->FirstGatewayAddress)
{
if (socket_address_to_string(addr_buf, sizeof(addr_buf)/sizeof(WCHAR), &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, sizeof(addr_buf)/sizeof(WCHAR), &gateway->Address))
print_value(addr_buf);
}
}
else
print_field(STRING_DEFAULT_GATEWAY, emptyW);
ipconfig_printfW(newlineW);
}
}
HeapFree(GetProcessHeap(), 0, adapters);
}
}
int wmain(int argc, WCHAR *argv[])
{
static const WCHAR slashHelp[] = {'/','?',0};
static const WCHAR slashAll[] = {'/','a','l','l',0};
WSADATA data;
if (WSAStartup(MAKEWORD(2, 2), &data))
return 1;
if (argc > 1)
{
if (!strcmpW(slashHelp, argv[1]))
{
ipconfig_message(STRING_USAGE);
WSACleanup();
return 1;
}
else if (!strcmpiW(slashAll, 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;
}