Sweden-Number/programs/netstat/netstat.c

286 lines
9.4 KiB
C
Raw Normal View History

2012-12-27 19:03:38 +01:00
/*
* Copyright 2011-2013 André Hentschel
2012-12-27 19:03:38 +01:00
*
* 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 "netstat.h"
#include <winsock2.h>
#include <iphlpapi.h>
#include "wine/unicode.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(netstat);
2013-01-02 21:37:45 +01:00
static const WCHAR ipW[] = {'I', 'P', 0};
static const WCHAR ipv6W[] = {'I', 'P', 'v', '6', 0};
static const WCHAR icmpW[] = {'I', 'C', 'M', 'P', 0};
static const WCHAR icmpv6W[] = {'I', 'C', 'M', 'P', 'v', '6', 0};
2012-12-27 19:03:38 +01:00
static const WCHAR tcpW[] = {'T', 'C', 'P', 0};
2013-01-02 21:37:45 +01:00
static const WCHAR tcpv6W[] = {'T', 'C', 'P', 'v', '6', 0};
static const WCHAR udpW[] = {'U', 'D', 'P', 0};
static const WCHAR udpv6W[] = {'U', 'D', 'P', 'v', '6', 0};
2012-12-27 19:03:38 +01:00
static const WCHAR fmtport[] = {'%', 'd', 0};
static const WCHAR fmtip[] = {'%', 'd', '.', '%', 'd', '.', '%', 'd', '.', '%', 'd', 0};
static const WCHAR fmtn[] = {'\n', 0};
static const WCHAR fmtnn[] = {'\n', '%', 's', '\n', 0};
static const WCHAR fmtcolon[] = {'%', 's', ':', '%', 's', 0};
static const WCHAR fmttcpout[] = {' ', ' ', '%', '-', '6', 's', ' ', '%', '-', '2', '2', 's', ' ', '%', '-', '2', '2', 's', ' ', '%', 's', '\n', 0};
static const WCHAR fmtudpout[] = {' ', ' ', '%', '-', '6', 's', ' ', '%', '-', '2', '2', 's', ' ', '*', ':', '*', '\n', 0};
2012-12-27 19:03:38 +01:00
/* =========================================================================
* Output a unicode string. Ideally this will go to the console
* and hence required WriteConsoleW to output it, however if file i/o is
* redirected, it needs to be WriteFile'd using OEM (not ANSI) format
* ========================================================================= */
static int __cdecl NETSTAT_wprintf(const WCHAR *format, ...)
{
static WCHAR *output_bufW = NULL;
static char *output_bufA = NULL;
static BOOL toConsole = TRUE;
static BOOL traceOutput = FALSE;
#define MAX_WRITECONSOLE_SIZE 65535
__ms_va_list parms;
DWORD nOut;
int len;
DWORD res = 0;
/*
* Allocate buffer to use when writing to console
* Note: Not freed - memory will be allocated once and released when
* xcopy ends
*/
if (!output_bufW) output_bufW = HeapAlloc(GetProcessHeap(), 0,
MAX_WRITECONSOLE_SIZE);
if (!output_bufW) {
WINE_FIXME("Out of memory - could not allocate 2 x 64K buffers\n");
return 0;
}
__ms_va_start(parms, format);
len = wvsprintfW(output_bufW, format, parms);
__ms_va_end(parms);
/* Try to write as unicode all the time we think its a console */
if (toConsole) {
res = WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE),
output_bufW, len, &nOut, NULL);
}
/* If writing to console has failed (ever) we assume its file
i/o so convert to OEM codepage and output */
if (!res) {
BOOL usedDefaultChar = FALSE;
DWORD convertedChars;
toConsole = FALSE;
/*
* Allocate buffer to use when writing to file. Not freed, as above
*/
if (!output_bufA) output_bufA = HeapAlloc(GetProcessHeap(), 0,
MAX_WRITECONSOLE_SIZE);
if (!output_bufA) {
WINE_FIXME("Out of memory - could not allocate 2 x 64K buffers\n");
return 0;
}
/* Convert to OEM, then output */
convertedChars = WideCharToMultiByte(GetConsoleOutputCP(), 0, output_bufW,
len, output_bufA, MAX_WRITECONSOLE_SIZE,
"?", &usedDefaultChar);
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), output_bufA, convertedChars,
&nOut, FALSE);
}
/* Trace whether screen or console */
if (!traceOutput) {
WINE_TRACE("Writing to console? (%d)\n", toConsole);
traceOutput = TRUE;
}
return nOut;
}
2013-01-02 21:37:17 +01:00
static WCHAR *NETSTAT_load_message(UINT id) {
2012-12-27 19:03:38 +01:00
static WCHAR msg[2048];
static const WCHAR failedW[] = {'F','a','i','l','e','d','!','\0'};
if (!LoadStringW(GetModuleHandleW(NULL), id, msg, sizeof(msg)/sizeof(WCHAR))) {
WINE_FIXME("LoadString failed with %d\n", GetLastError());
strcpyW(msg, failedW);
}
return msg;
}
2013-01-02 21:37:17 +01:00
static WCHAR *NETSTAT_port_name(UINT port, WCHAR name[])
2012-12-27 19:03:38 +01:00
{
/* FIXME: can we get the name? */
sprintfW(name, fmtport, htons((WORD)port));
return name;
}
2013-01-02 21:37:17 +01:00
static WCHAR *NETSTAT_host_name(UINT ip, WCHAR name[])
2012-12-27 19:03:38 +01:00
{
UINT nip;
/* FIXME: can we get the name? */
nip = htonl(ip);
sprintfW(name, fmtip, (nip >> 24) & 0xFF, (nip >> 16) & 0xFF, (nip >> 8) & 0xFF, (nip) & 0xFF);
return name;
}
static void NETSTAT_tcp_header(void)
{
WCHAR local[22], remote[22], state[22];
NETSTAT_wprintf(fmtnn, NETSTAT_load_message(IDS_TCP_ACTIVE_CONN));
NETSTAT_wprintf(fmtn);
strcpyW(local, NETSTAT_load_message(IDS_TCP_LOCAL_ADDR));
strcpyW(remote, NETSTAT_load_message(IDS_TCP_REMOTE_ADDR));
strcpyW(state, NETSTAT_load_message(IDS_TCP_STATE));
NETSTAT_wprintf(fmttcpout, NETSTAT_load_message(IDS_TCP_PROTO), local, remote, state);
}
2013-01-02 21:37:17 +01:00
static void NETSTAT_tcp_table(void)
2012-12-27 19:03:38 +01:00
{
PMIB_TCPTABLE table;
DWORD err, size, i;
WCHAR HostIp[MAX_HOSTNAME_LEN], HostPort[32];
WCHAR RemoteIp[MAX_HOSTNAME_LEN], RemotePort[32];
WCHAR Host[MAX_HOSTNAME_LEN + 32];
WCHAR Remote[MAX_HOSTNAME_LEN + 32];
size = sizeof(MIB_TCPTABLE);
do
{
table = (PMIB_TCPTABLE)HeapAlloc(GetProcessHeap(), 0, size);
err = GetTcpTable(table, &size, TRUE);
if (err != NO_ERROR) HeapFree(GetProcessHeap(), 0, table);
} while (err == ERROR_INSUFFICIENT_BUFFER);
if (err) return;
NETSTAT_tcp_header();
2012-12-27 19:03:38 +01:00
for (i = 0; i < table->dwNumEntries; i++)
{
if ((table->table[i].dwState == MIB_TCP_STATE_CLOSE_WAIT) ||
(table->table[i].dwState == MIB_TCP_STATE_ESTAB) ||
(table->table[i].dwState == MIB_TCP_STATE_TIME_WAIT))
{
NETSTAT_host_name(table->table[i].dwLocalAddr, HostIp);
NETSTAT_port_name(table->table[i].dwLocalPort, HostPort);
NETSTAT_host_name(table->table[i].dwRemoteAddr, RemoteIp);
NETSTAT_port_name(table->table[i].dwRemotePort, RemotePort);
sprintfW(Host, fmtcolon, HostIp, HostPort);
sprintfW(Remote, fmtcolon, RemoteIp, RemotePort);
NETSTAT_wprintf(fmttcpout, tcpW, Host, Remote, NETSTAT_load_message(table->table[i].dwState));
}
}
HeapFree(GetProcessHeap(), 0, table);
}
static void NETSTAT_udp_table(void)
{
PMIB_UDPTABLE table;
DWORD err, size, i;
WCHAR HostIp[MAX_HOSTNAME_LEN], HostPort[32];
WCHAR Host[MAX_HOSTNAME_LEN + 32];
size = sizeof(MIB_UDPTABLE);
do
{
table = (PMIB_UDPTABLE)HeapAlloc(GetProcessHeap(), 0, size);
err = GetUdpTable(table, &size, TRUE);
if (err != NO_ERROR) HeapFree(GetProcessHeap(), 0, table);
} while (err == ERROR_INSUFFICIENT_BUFFER);
if (err) return;
NETSTAT_tcp_header();
for (i = 0; i < table->dwNumEntries; i++)
{
NETSTAT_host_name(table->table[i].dwLocalAddr, HostIp);
NETSTAT_port_name(table->table[i].dwLocalPort, HostPort);
sprintfW(Host, fmtcolon, HostIp, HostPort);
NETSTAT_wprintf(fmtudpout, udpW, Host);
}
HeapFree(GetProcessHeap(), 0, table);
}
2013-01-02 21:37:45 +01:00
static NETSTATPROTOCOLS NETSTAT_get_protocol(WCHAR name[])
{
if (!strcmpiW(name, ipW)) return PROT_IP;
if (!strcmpiW(name, ipv6W)) return PROT_IPV6;
if (!strcmpiW(name, icmpW)) return PROT_ICMP;
if (!strcmpiW(name, icmpv6W)) return PROT_ICMPV6;
if (!strcmpiW(name, tcpW)) return PROT_TCP;
if (!strcmpiW(name, tcpv6W)) return PROT_TCPV6;
if (!strcmpiW(name, udpW)) return PROT_UDP;
if (!strcmpiW(name, udpv6W)) return PROT_UDPV6;
return PROT_UNKNOWN;
}
2012-12-27 19:03:38 +01:00
int wmain(int argc, WCHAR *argv[])
{
WSADATA wsa_data;
if (WSAStartup(MAKEWORD(2, 2), &wsa_data))
{
WINE_ERR("WSAStartup failed: %d\n", WSAGetLastError());
return 1;
}
2013-01-02 21:37:45 +01:00
if (argc == 1)
{
/* No options */
NETSTAT_tcp_table();
return 0;
}
while (argv[1] && argv[1][0] == '-')
{
switch (argv[1][1])
{
case 'p':
argv++; argc--;
if (argc == 1) return 1;
switch (NETSTAT_get_protocol(argv[1]))
{
case PROT_TCP:
NETSTAT_tcp_table();
break;
case PROT_UDP:
NETSTAT_udp_table();
break;
2013-01-02 21:37:45 +01:00
default:
WINE_FIXME("Protocol not yet implemented: %s\n", debugstr_w(argv[1]));
}
break;
default:
WINE_FIXME("Unknown option: %s\n", debugstr_w(argv[1]));
return 1;
}
argv++; argc--;
}
2012-12-27 19:03:38 +01:00
return 0;
}