65.9K
CodeProject is changing. Read more.
Home

Mobile development: Netstat, know your device’s open ports

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0 vote)

Sep 24, 2013

CPOL
viewsIcon

10280

Know your device’s open ports.

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

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]; // 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()
    {
        // Start with 20.000 bytes left for information about tcp table
        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;     // 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 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).