Introduction
On desktop PCs you have a nice tool netstat to see which ports are open on the PC. A customer wanted to know why his devices do not release their internet connection. The only tool I know that will show open network connections is called netstat. Unfortunately I did not find such
a tool for Windows Mobile and so I wrote one myself.
netstat for Windows Mobile:
NetstatCF2 is written in C# using the Compact Framework. After you start the tool it immediately collects the open ports data. It will also log this data periodically (every 3 seconds) to a log file called “\netstat.log”.
The code makes massive calls to the ipHlp API functions. Here are some sample snippets:
...
public class IPHlpAPI32Wrapper
{
public const byte NO_ERROR = 0;
public const int FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100;
public const int FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200;
public const int FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000;
public int dwFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS;
[DllImport("iphlpapi.dll", SetLastError = true)]
public extern static int GetUdpStatistics(ref MIB_UDPSTATS pStats);
[DllImport("iphlpapi.dll", SetLastError = true)]
public static extern int GetUdpTable(byte[] UcpTable, out int pdwSize, bool bOrder);
[DllImport("iphlpapi.dll", SetLastError = true)]
public extern static int GetTcpStatistics(ref MIB_TCPSTATS pStats);
[DllImport("iphlpapi.dll", SetLastError = true)]
public static extern int GetTcpTable(byte[] pTcpTable, out int pdwSize, bool bOrder);
[DllImport("iphlpapi.dll", SetLastError = true)]
public static extern int GetIpForwardTable(IntPtr pIpForwardTable, ref int pdwSize, bool bOrder);
[DllImport("iphlpapi.dll", SetLastError = true)]
public static extern int GetIpForwardTable(byte[] pIpForwardTable, ref int pdwSize, bool bOrder);
...
public void GetTcpConnexions()
{
byte[] buffer = new byte[20000];
int pdwSize = 20000;
int res = IPHlpAPI32Wrapper.GetTcpTable(buffer, out pdwSize, true);
if (res != NO_ERROR)
{
buffer = new byte[pdwSize];
res = IPHlpAPI32Wrapper.GetTcpTable(buffer, out pdwSize, true);
if (res != 0)
return;
}
TcpConnexion = new IpHlpApidotnet.MIB_TCPTABLE();
int nOffset = 0;
TcpConnexion.dwNumEntries = Convert.ToInt32(buffer[nOffset]);
nOffset += 4;
TcpConnexion.table = new MIB_TCPROW[TcpConnexion.dwNumEntries];
for (int i = 0; i < TcpConnexion.dwNumEntries; i++)
{
int st = Convert.ToInt32(buffer[nOffset]);
(TcpConnexion.table[i]).StrgState = convert_state(st);
(TcpConnexion.table[i]).iState = st;
nOffset += 4;
string LocalAdrr = buffer[nOffset].ToString() + "." + buffer[nOffset + 1].ToString() +
"." + buffer[nOffset + 2].ToString() + "." + buffer[nOffset + 3].ToString();
nOffset += 4;
int LocalPort = (((int)buffer[nOffset]) << 8) + (((int)buffer[nOffset + 1])) +
(((int)buffer[nOffset + 2]) << 24) + (((int)buffer[nOffset + 3]) << 16);
nOffset += 4;
(TcpConnexion.table[i]).Local = new IPEndPoint(IPAddress.Parse(LocalAdrr), LocalPort);
string RemoteAdrr = buffer[nOffset].ToString() + "." + buffer[nOffset + 1].ToString() +
"." + buffer[nOffset + 2].ToString() + "." + buffer[nOffset + 3].ToString();
nOffset += 4;
int RemotePort;
if (RemoteAdrr == "0.0.0.0")
{
RemotePort = 0;
}
else
{
RemotePort = (((int)buffer[nOffset]) << 8) + (((int)buffer[nOffset + 1])) +
(((int)buffer[nOffset + 2]) << 24) + (((int)buffer[nOffset + 3]) << 16);
}
nOffset += 4;
(TcpConnexion.table[i]).Remote =
new IPEndPoint(IPAddress.Parse(RemoteAdrr), RemotePort);
}
}
...
public void GetUdpConnexions()
{
byte[] buffer = new byte[20000];
int pdwSize = 20000;
int res = IPHlpAPI32Wrapper.GetUdpTable(buffer, out pdwSize, true);
if (res != NO_ERROR)
{
buffer = new byte[pdwSize];
res = IPHlpAPI32Wrapper.GetUdpTable(buffer, out pdwSize, true);
if (res != 0)
return;
}
UdpConnexion = new IpHlpApidotnet.MIB_UDPTABLE();
int nOffset = 0;
UdpConnexion.dwNumEntries = Convert.ToInt32(buffer[nOffset]);
nOffset += 4;
UdpConnexion.table = new MIB_UDPROW[UdpConnexion.dwNumEntries];
for (int i = 0; i < UdpConnexion.dwNumEntries; i++)
{
string LocalAdrr = buffer[nOffset].ToString() + "." +
buffer[nOffset + 1].ToString() + "." +
buffer[nOffset + 2].ToString() + "." + buffer[nOffset + 3].ToString();
nOffset += 4;
int LocalPort = (((int)buffer[nOffset]) << 8) + (((int)buffer[nOffset + 1])) +
(((int)buffer[nOffset + 2]) << 24) + (((int)buffer[nOffset + 3]) << 16);
nOffset += 4;
(UdpConnexion.table[i]).Local = new IPEndPoint(IPAddress.Parse(LocalAdrr), LocalPort);
}
}
...
public class IPHelper
{
private const int NO_ERROR = 0;
private const int MIB_TCP_STATE_CLOSED = 1;
private const int MIB_TCP_STATE_LISTEN = 2;
private const int MIB_TCP_STATE_SYN_SENT = 3;
private const int MIB_TCP_STATE_SYN_RCVD = 4;
private const int MIB_TCP_STATE_ESTAB = 5;
private const int MIB_TCP_STATE_FIN_WAIT1 = 6;
private const int MIB_TCP_STATE_FIN_WAIT2 = 7;
private const int MIB_TCP_STATE_CLOSE_WAIT = 8;
private const int MIB_TCP_STATE_CLOSING = 9;
private const int MIB_TCP_STATE_LAST_ACK = 10;
private const int MIB_TCP_STATE_TIME_WAIT = 11;
private const int MIB_TCP_STATE_DELETE_TCB = 12;
private const int ERROR_INSUFFICIENT_BUFFER = 122;
...
But there is nothing special except how to use C/C++ structures in C#.
Here is a sample of the logged data:
xxxxxxxxxxx AM #################
======= TCP table ========
local remote
0.0.0.0: 21 0.0.0.0: 0 LISTEN
0.0.0.0: 1004 0.0.0.0: 0 LISTEN
0.0.0.0: 2188 0.0.0.0: 0 LISTEN
0.0.0.0: 2189 0.0.0.0: 0 LISTEN
0.0.0.0: 5655 0.0.0.0: 0 LISTEN
0.0.0.0: 52241 0.0.0.0: 0 LISTEN
127.0.0.1: 1032 127.0.0.1: 52241 ESTAB
127.0.0.1: 1034 127.0.0.1: 52241 ESTAB
127.0.0.1: 1035 127.0.0.1: 52241 ESTAB
127.0.0.1: 1036 127.0.0.1: 52241 ESTAB
127.0.0.1: 52241 127.0.0.1: 1032 ESTAB
127.0.0.1: 52241 127.0.0.1: 1034 ESTAB
127.0.0.1: 52241 127.0.0.1: 1035 ESTAB
127.0.0.1: 52241 127.0.0.1: 1036 ESTAB
192.168.55.101: 1082 192.168.55.100: 7438 ESTAB
192.168.55.101: 1083 192.168.55.100: 990 ESTAB
192.168.55.101: 1086 192.168.55.100: 990 ESTAB
192.168.55.101: 1087 192.168.55.100: 990 ESTAB
192.168.55.101: 1092 192.168.55.100: 990 ESTAB
192.168.55.101: 1102 192.168.55.100: 1004 ESTAB
192.168.55.101: 1103 192.168.55.100: 990 ESTAB
192.168.128.104: 1033 192.168.128.5: 62241 ESTAB
192.168.128.104: 5655 192.168.128.2: 59534 ESTAB
192.168.128.104: 5655 192.168.128.2: 59535 ESTAB
192.168.128.104: 6510 192.168.128.2: 59536 ESTAB
192.168.128.104: 6510 192.168.128.2: 59537 ESTAB
======= UDP table ========
0.0.0.0: 53
0.0.0.0: 137
0.0.0.0: 138
0.0.0.0: 1088
0.0.0.0: 9204
0.0.0.0: 49111
192.168.128.104: 68
======= TCP statistics ========
Retransmission timeout (min/max): Van Jacobson's Algorithm: 300/120000
max connnections: -1
active open: 69
passive open: 196
failed attempts: 0
established resets: 243
current established: 20
segments in: 134380
segments out: 130900
retransmitted segments: 175
in errors: 0
out resets: 861
num connections: 26
======= UDP statistics ========
in datagrams: 13771
in errors: 0
num ports: 3353
num addresses: 7
out datagrams: 887
======= Adapter infos ==========
131074: BCMCF1, 192.168.128.104
262147: USB Cable:, 192.168.55.101
======= Route entries ==========
Network Destination Netmask Gateway Interface Metric
0.0.0.0 0.0.0.0 192.168.55.101 003 0
225.20.0.0 0.0.0.0 255.255.255.255 255 0
0.0.0.0 0.0.0.0 192.168.128.1 002 0
225.20.0.0 0.0.0.0 255.255.255.255 255 0
127.0.0.0 255.0.0.0 127.0.0.1 001 0
104.148.1.0 0.0.0.0 255.255.255.255 255 0
192.168.55.101 255.255.255.255 127.0.0.1 001 0
225.20.0.0 0.0.0.0 255.255.255.255 255 0
192.168.55.255 255.255.255.255 192.168.55.101 003 0
225.20.0.0 0.0.0.0 255.255.255.255 255 0
192.168.128.0 255.255.255.0 192.168.128.104 002 0
67.148.1.0 0.0.0.0 255.255.255.255 255 0
Hopefully you will use this small tool at a special time. Code and sample bin
are available at code.google.com (VS2008, CF2, WM5SDK).