3

We're monitoring usage statistics of a network interface using NetworkInterface.GetIPv4Statistics() in .NET 2.0. This isn't reporting correct statistics for connections over which VPN traffic is being tunneled. Instead - in the case of the Cisco VPN client - the usage is just attributed to a new network interface that just looks like an Ethernet connection.

Windows itself (Vista, at least) adds the VPN statistics to the actual physical interface correctly, so viewing the 'Status' dialog for the original connection shows the correct byte counts. However, the results of the call in .NET do not merge the traffic together.

Is there a way to associate the VPN connection back to the network connection over which it's being tunneled? Failing that, does anyone know which API is being used by the status dialog to retrieve correct statistics?

At the moment we're having to manually detect connections that look like they're VPNs and add their usage to whatever other connection is active, and this doesn't seem like a robust solution.

Thom
  • 2,643
  • 2
  • 30
  • 33
  • Your approach seems correct. I am using Vista with 2 Windows VPN connections running over my Ethernet. I iterate over NetworkInterface.GetAllNetworkInterfaces to GetIPv4Statistics for each. The Ethernet total includes the usage for each VPN connection. Please post details of ipcongif /all ? – Michael Logothetis Mar 02 '09 at 23:38
  • The only difference in the setup we're testing appears to be that the VPN is built over a PPP connection, not Ethernet. Perhaps also relevant is that HTTP traffic (which is all we're really testing) is going through a proxy behind the VPN. I'll see if I can gather some more detailed info soon. – Thom Mar 05 '09 at 11:11

3 Answers3

2

Here's a program written in Delphi (with full source and explanation) that will help you to collect network information, including VPN data. This is using the open-source Indy components, which is also available for use with C#.

I'd suggest browsing through the source, and you'll find the exact Windows API calls it makes. It relies HEAVILY on the IP Helper API (IPHlpApi).

If you are looking for C# only examples, I'd suggest doing some google-ing for "C# and IpHlpApi".

Regards

alt text http://z.about.com/d/delphi/1/0/k/2/112903_2.gif

Mick
  • 13,248
  • 9
  • 69
  • 119
  • Most of the stuff in System.Net.NetworkInformation wraps iphlpapi.dll anyway, so I'm not sure this will help. I'll have a look through the MSDN docs you linked to anyway, and see if there are any other avenues of attack. – Thom Mar 05 '09 at 11:14
  • Fair enough. In my opinion, I think you will need quite a bit of P/Invoke for this solution, and you may be better off with a native language like C++/Delphi for this. However, I'll leave that to you. Regards. – Mick Mar 05 '09 at 15:32
1

I'll have to check when I get to work to see what my config looks like.

One thing that Cisco VPN does is, if configured, disabling split tunneling. What that means is that you are prevented from accessing your local subnet on the connection that is connected to VPN.

The way I can see this, is when my ethernet connection is configured with an IP Address, but doesn't have a Default Gateway.

Supposing that you identify the VPN connection, that gateway-less connection would be your other connection.

Also, have you looked into any WMI classes. Cisco VPN may interact with a WMI class perhaps.

Rob Haupt
  • 2,104
  • 1
  • 15
  • 24
  • I can still see the gateway address for the original (PPP) connection, unfortunately. I'll have a trawl through WMI and see if there's any more information in there. Win32_NetworkAdapter and Win32_NetworkAdapterConfiguration don't add anything useful, though. – Thom Feb 24 '09 at 09:23
0

As Rob suggests, the answer lies within WMI. Win32_PerfFormattedData_RemoteAccess_RasPort seems to be exactly what Windows uses itself - the numbers are the same, byte for byte, whether the VPN is up or not.

I tested with:

static class Program
{
    static void Main()
    {
        var query = new WqlEventQuery("__InstanceModificationEvent", TimeSpan.FromSeconds(1),
                                      "TargetInstance ISA 'Win32_PerfFormattedData_RemoteAccess_RasPort' AND TargetInstance.BytesReceived > 0");

        var watcher = new ManagementEventWatcher(query);
        watcher.EventArrived += EventArrived;
        watcher.Start();

        Console.ReadLine();
    }

    static void EventArrived(object sender, EventArrivedEventArgs e)
    {
        var mo = e.NewEvent["TargetInstance"] as ManagementBaseObject;
        Console.WriteLine("{0:#,0}: {1:#,0} bytes sent, {2:#,0} bytes received", mo["Name"], mo["BytesTransmitted"], mo["BytesReceived"]);
    }
}
Thom
  • 2,643
  • 2
  • 30
  • 33
  • This turns out not to be widely supported. We ended up using a third-party RAS library. – Thom Nov 23 '09 at 15:01