Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

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

0.00/5 (No votes)
24 Sep 2013CPOL 10.3K  
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:

C#
...
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).

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)