Mobile development: Netstat, know your device’s open ports
On desktop PCs you have the nice tool netstat to see which ports are open on the PC. A customer wanted to know, why his devices do not release there internet connection. The only tool I know, that will show open network connections, is called netstat. Unfortunately I did not find such tool for Windows Mobile and so I wrote one myself:
netstat for windows mobile
NetstatCF2 is written in C#, Compact Framework. After you started 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]; // Start with 20.000 bytes left for information about tcp table 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; // Error. You should handle it } TcpConnexion = new IpHlpApidotnet.MIB_TCPTABLE(); int nOffset = 0; // number of entry in the TcpConnexion.dwNumEntries = Convert.ToInt32(buffer[nOffset]); nOffset += 4; TcpConnexion.table = new MIB_TCPROW[TcpConnexion.dwNumEntries]; for (int i = 0; i < TcpConnexion.dwNumEntries; i++) { // state int st = Convert.ToInt32(buffer[nOffset]); // state in string //((MIB_TCPROW) (TcpConnexion.table[i]).StrgState = convert_state(st); // state by ID //((MIB_TCPROW) (TcpConnexion.table[i]).iState = st; nOffset += 4; // local address string LocalAdrr = buffer[nOffset].ToString() + "." + buffer[nOffset + 1].ToString() + "." + buffer[nOffset + 2].ToString() + "." + buffer[nOffset + 3].ToString(); nOffset += 4; //local port in decimal int LocalPort = (((int)buffer[nOffset]) << 8) + (((int)buffer[nOffset + 1])) + (((int)buffer[nOffset + 2]) << 24) + (((int)buffer[nOffset + 3]) << 16); nOffset += 4; // store the remote endpoint //((MIB_TCPROW)( (TcpConnexion.table[i]).Local = new IPEndPoint(IPAddress.Parse(LocalAdrr), LocalPort); // remote address string RemoteAdrr = buffer[nOffset].ToString() + "." + buffer[nOffset + 1].ToString() + "." + buffer[nOffset + 2].ToString() + "." + buffer[nOffset + 3].ToString(); nOffset += 4; // if the remote address = 0 (0.0.0.0) the remote port is always 0 // else get the remote port in decimal 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; //((MIB_TCPROW) (TcpConnexion.table[i]).Remote = new IPEndPoint(IPAddress.Parse(RemoteAdrr), RemotePort); } } ... public void GetUdpConnexions() { byte[] buffer = new byte[20000]; // Start with 20.000 bytes left for information about tcp table 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; // Error. You should handle it } UdpConnexion = new IpHlpApidotnet.MIB_UDPTABLE(); int nOffset = 0; // number of entry in the 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; //((MIB_UDPROW) (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 on 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 use this small tool at a special time.
Code and sample bin at code.google.com (VS2008, CF2, WM5SDK)
Possibly outdated bin: [Download not found]