1

[After Googling and searching for hours/days, I can't believe such basic task has not an out-of-the-box "hello world".]

On a Windows 7, how to log network statistics? If possible, for a specific IP address. The goal here is to log UDP/TCP bandwidth and errors over several hours.

Already tried a lot of software, but none was working. For example, NetMon has not succedeed to launch a capture, even by launching it as Administrator.

Programming solutions are welcome, especially using C/C++/C#.

yO_
  • 1,135
  • 2
  • 12
  • 18
  • 1
    Use `GetIpStatistics()`or **WMI**. See https://stackoverflow.com/questions/221181/how-can-i-access-netstat-like-ethernet-statistics-from-a-windows-program – Frankie_C Feb 19 '19 at 13:05
  • stackoverflow.com is NOT a free code design service. Please post what you have tried and how it fails to perform the desired task. – user3629249 Feb 19 '19 at 19:56
  • @user3629249 Problem is precisely because hours and hours of Google gave no results. Everyone can try this and find out the lack of documentation on this subject. The question was essentially about getting some directly useful pointers. – yO_ Feb 20 '19 at 08:29
  • @user3629249 But if you really insist, I could try to recall some of the unsuccessful attempts (at the measure one recalls unfructful Googling...): I tried at least one hour around NetMon; tried "PerfMon /res" but did not found how to log; tried Nagios to find they were not offering a native Windows download; parsed some documentation about WMI but it was difficult to dive in all that in a few hours; ... – yO_ Feb 20 '19 at 08:30
  • 1
    Use the sample code from https://learn.microsoft.com/en-us/windows/desktop/api/iphlpapi/nf-iphlpapi-getipstatistics. Just copy-paste-compile and run! – Frankie_C Feb 20 '19 at 10:23
  • 1
    I see, I have understood that you were interested in C code. Anyway in C you can also use `GetUdpStatistics()` to retrieve statistics specific for **UDP** https://learn.microsoft.com/en-us/windows/desktop/api/iphlpapi/nf-iphlpapi-getudpstatistics), or `GetTcpStatistics()` for **TCP** (https://learn.microsoft.com/en-us/windows/desktop/api/iphlpapi/nf-iphlpapi-gettcpstatistics). Just replace them in the sample code from `GetIpStatistics()`. There many other functions that give interesting info's. **May I suggest you to have a deeper look to the pages I signaled to you?**. – Frankie_C Feb 22 '19 at 09:09

2 Answers2

1

MS make available a set of IP helper functions (https://learn.microsoft.com/en-us/windows/desktop/api/_iphlp/), that allows management and monitoring of the whole IP stack (native IP protocol and derived).

You can use monitoring functions specialized for IP, TCP or UDP:

  • GetIpStatistics()
  • GetUdpStatistics()
  • GetTcpStatistics()

MS supply a functional sample in https://learn.microsoft.com/en-us/windows/desktop/api/iphlpapi/nf-iphlpapi-getipstatistics, that I report:

#ifndef UNICODE
#define UNICODE
#endif

#include <winsock2.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#include <stdio.h>

#pragma comment(lib, "iphlpapi.lib")

#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))

/* Note: could also use malloc() and free() */

int main()
{

    DWORD dwRetval;
    MIB_IPSTATS *pStats;

    pStats = (MIB_IPSTATS *) MALLOC(sizeof (MIB_IPSTATS));

    if (pStats == NULL) {
        wprintf(L"Unable to allocate memory for MIB_IPSTATS\n");
        exit(1);
    }
    dwRetval = GetIpStatistics(pStats);
    if (dwRetval != NO_ERROR) {
        wprintf(L"GetIpStatistics call failed with %d\n", dwRetval);
        exit(1);
    } else {

        wprintf(L"IP forwarding: \t\t" );
        switch (pStats->dwForwarding) {
        case MIB_IP_FORWARDING: 
            wprintf(L"Enabled\n");
            break;
        case MIB_IP_NOT_FORWARDING: 
            wprintf(L"Disabled\n");
            break;
        default: 
            wprintf(L"unknown value = %d\n", pStats->dwForwarding);
            break;
        }

        wprintf(L"Default initial TTL: \t\t\t\t\t%u\n", pStats->dwDefaultTTL);

        wprintf(L"Number of received datagrams: \t\t\t\t%u\n", pStats->dwInReceives);
        wprintf(L"Number of received datagrams with header errors: \t%u\n", pStats->dwInHdrErrors);
        wprintf(L"Number of received datagrams with address errors: \t%u\n", pStats->dwInAddrErrors);

        wprintf(L"Number of datagrams forwarded: \t\t\t\t%ld\n", pStats->dwForwDatagrams);

        wprintf(L"Number of received datagrams with an unknown protocol: \t%u\n", pStats->dwInUnknownProtos);
        wprintf(L"Number of received datagrams discarded: \t\t%u\n", pStats->dwInDiscards);
        wprintf(L"Number of received datagrams delivered: \t\t%u\n", pStats->dwInDelivers);

        wprintf(L"Number of outgoing datagrams requested to transmit: \t%u\n", pStats->dwOutRequests);
        wprintf(L"Number of outgoing datagrams discarded for routing: \t%u\n", pStats->dwRoutingDiscards);
        wprintf(L"Number of outgoing datagrams discarded: \t\t%u\n", pStats->dwOutDiscards);
        wprintf(L"Number of outgoing datagrams with no route to destination discarded: %u\n", pStats->dwOutNoRoutes);

        wprintf(L"Fragment reassembly timeout: \t\t\t\t%u\n", pStats->dwReasmTimeout);
        wprintf(L"Number of datagrams that required reassembly: \t\t%u\n", pStats->dwReasmReqds);
        wprintf(L"Number of datagrams successfully reassembled: \t\t%u\n", pStats->dwReasmOks);
        wprintf(L"Number of datagrams that could not be reassembled: \t%u\n", pStats->dwReasmFails);

        wprintf(L"Number of datagrams fragmented successfully: \t\t%u\n", pStats->dwFragOks);
        wprintf(L"Number of datagrams not fragmented and discarded: \t%u\n", pStats->dwFragFails);
        wprintf(L"Number of fragments created: \t\t\t\t%u\n", pStats->dwFragCreates);

        wprintf(L"Number of interfaces: \t\t\t\t\t%u\n", pStats->dwNumIf);
        wprintf(L"Number of IP addresses: \t\t\t\t%u\n", pStats->dwNumAddr);
        wprintf(L"Number of routes: \t\t\t\t\t%u\n", pStats->dwNumRoutes);
    }

// Free memory allocated for the MIB_IPSTATS structure
    if (pStats)
        FREE(pStats);

    return 0;
}

This code can be reused for each of the functions relative to IP, TCP and UDP by replacing the helper function with the appropriate one.

Exists also extended version for those functions that allow to restrict monitoring to IPV4 or IPV6.

Detailed information are available on the MS page of IP helper.

Frankie_C
  • 4,764
  • 1
  • 13
  • 30
0

Here is a working code in C#:

using System;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text;

namespace App1
{
class Wrap
{
    public static void ShowUdpStatistics(NetworkInterfaceComponent version)
    {
        IPGlobalProperties properties = IPGlobalProperties.GetIPGlobalProperties();
        UdpStatistics udpStat = null;

        switch (version)
        {
            case NetworkInterfaceComponent.IPv4:
                udpStat = properties.GetUdpIPv4Statistics();
                Console.WriteLine("UDP IPv4 Statistics");
                break;
            case NetworkInterfaceComponent.IPv6:
                udpStat = properties.GetUdpIPv6Statistics();
                Console.WriteLine("UDP IPv6 Statistics");
                break;
            default:
                throw new ArgumentException("version");
                //    break;
        }
        Console.WriteLine("  Datagrams Received ...................... : {0}",
            udpStat.DatagramsReceived);
        Console.WriteLine("  Datagrams Sent .......................... : {0}",
            udpStat.DatagramsSent);
        Console.WriteLine("  Incoming Datagrams Discarded ............ : {0}",
            udpStat.IncomingDatagramsDiscarded);
        Console.WriteLine("  Incoming Datagrams With Errors .......... : {0}",
            udpStat.IncomingDatagramsWithErrors);
        Console.WriteLine("  UDP Listeners ........................... : {0}",
            udpStat.UdpListeners);
        Console.WriteLine("");
    }

    /*public static void SendUdp()
    {
        Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram,
ProtocolType.Udp);

        IPAddress serverAddr = IPAddress.Parse("192.168.2.255");

        IPEndPoint endPoint = new IPEndPoint(serverAddr, 11050);

        string text = "Hello";
        byte[] send_buffer = Encoding.ASCII.GetBytes(text);

        sock.SendTo(send_buffer, endPoint);
    }*/

}

class Program
{
    static void Main(string[] args)
    {
        for (int i=0; i < 10; i++)
        {
            Wrap.ShowUdpStatistics(NetworkInterfaceComponent.IPv4);
            /*Wrap.SendUdp();*/
        }
    }
}
}

This is an enhanced (and working out-of-the-box!) version of the example in MSDN documentation.

Commented code is added here to verify that counters grow up while sending UDP packets. Thanks to the first answer of this SO question.

yO_
  • 1,135
  • 2
  • 12
  • 18