Search
Close this search box.

C# code to maintain VPN connection programatically

Windows has pretty good VPN management.  It’s pretty good at redialing the connection when the connection is dropped, and for the most part it works.

However, sometimes it thinks it connected to the VPN when it’s really not, and it doesn’t validate the connection to a specific internal IP.  I needed something that was a bit more robust and could disconnect and reconnect if it couldn’t see a specific IP.

This class takes a VPN connection name and an IP to ping and will use rasphone.exe to connect and NetworkInformation.Ping to verify connectivity.  Every 15 seconds, it checks connectivity and redials as needed.

Obviously, the VPN has to have the authentication saved, and redial attempts set to zero.

using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;

namespace VPNManager {
  /// <summary>
  /// Class to maintain connectivity to a specific VPN connection
  /// </summary>
  /// <history>
  ///     [Tim Hibbard]   01/24/2007  Created
  /// </history>
  public class VPN {
#region-- Const--
    /// <summary>
    /// Where the rasphone.exe lives
    /// </summary>
    private const string VPNPROCESS = "C:\\WINDOWS\\system32\\rasphone.exe";
#endregion

#region-- Fields--
    /// <summary>
    /// Internal variable for VPNConnectionName
    /// </summary>
    private string _VPNConnectionName = "";
    /// <summary>
    /// Internal variable for IPToPing
    /// </summary>
    private string _IPToPing = "";
    /// <summary>
    /// Internal variable for IsConnected
    /// </summary>
    private bool _isConnected = false;
    /// <summary>
    /// Timer that manages the Manage function
    /// </summary>
    private System.Timers.Timer MonitorTimer;
    /// <summary>
    /// Bool to flag if the system is currently checking for network validity
    /// </summary>
    private bool _isChecking = false;
    /// <summary>
    /// Bool to flag if the system is currently in a Manage loop
    /// </summary>
    private bool _isManaging = false;
#endregion

#region-- Events--
    public delegate void PingingHandler();
    public delegate void ConnectingHandler();
    public delegate void DisconnectingHandler();
    public delegate void IdleHandler();
    public delegate void ConnectionStatusChangedHandler(bool Connected);

    /// <summary>
    /// Fires when validating connectivity
    /// </summary>
    /// <history>
    ///     [Tim Hibbard]   01/24/2007  Created
    /// </history>
    public event PingingHandler Pinging;

    /// <summary>
    /// Fired when it is trying to connect to the VPN
    /// </summary>
    /// <history>
    ///     [Tim Hibbard]   01/24/2007  Created
    /// </history>
    public event ConnectingHandler Connecting;

    /// <summary>
    /// Fired when it is trying to disconnect from the VPN
    /// </summary>
    public event DisconnectingHandler Disconnecting;

    /// <summary>
    /// Fired when it is done working for the moment
    /// </summary>
    /// <history>
    ///     [Tim Hibbard]   01/24/2007  Created
    /// </history>
    public event IdleHandler Idle;

    /// <summary>
    /// Fired when the IsConnected Property changes
    /// </summary>
    /// <history>
    ///     [Tim Hibbard]   01/24/2007  Created
    /// </history>
    public event ConnectionStatusChangedHandler ConnectionStatusChanged;

    /// <summary>
    /// Call to raise Pinging event
    /// </summary>
    /// <history>
    ///     [Tim Hibbard]   01/24/2007  Created
    /// </history>
    protected void OnPinging() {
      if (Pinging != null) {
        Pinging();
      }
    }

    /// <summary>
    /// Call to raise Connecting event
    /// </summary>
    /// <history>
    ///     [Tim Hibbard]   01/24/2007  Created
    /// </history>
    protected void OnConnecting() {
      if (Connecting != null) {
        Connecting();
      }
    }

    /// <summary>
    /// Call to raise Disconnecting event
    /// </summary>
    /// <history>
    ///     [Tim Hibbard]   01/24/2007  Created
    /// </history>
    protected void OnDisconnecting() {
      if (Disconnecting != null) {
        Disconnecting();
      }
    }

    /// <summary>
    /// Call to raise Idle event
    /// </summary>
    /// <history>
    ///     [Tim Hibbard]   01/24/2007  Created
    /// </history>
    protected void OnIdle() {
      if (Idle != null) {
        Idle();
      }
    }

    /// <summary>
    /// Call to raise ConnectionStatusChanged event
    /// </summary>
    /// <param name="Connected">If connected to network</param>
    /// <history>
    ///     [Tim Hibbard]   01/24/2007  Created
    /// </history>
    protected void OnConnectionStatusChanged(bool Connected) {
      if (ConnectionStatusChanged != null) {
        ConnectionStatusChanged(Connected);
      }
    }

#endregion

#region-- Properties--
    /// <summary>
    /// Returns if you are connected to the network
    /// </summary>
    /// <history>
    ///     [Tim Hibbard]   01/24/2007  Created
    /// </history>
    public bool IsConnected {
      get { return _isConnected; }
    }

    /// <summary>
    /// IP to ping to validate connectivity
    /// </summary>
    /// <history>
    ///     [Tim Hibbard]   01/24/2007  Created
    /// </history>
    public string IPToPing {
      get { return _IPToPing; }
      set { _IPToPing = value; }
    }

    /// <summary>
    /// Name of VPN connection as seen in network connections (not case
    /// sensitive)
    /// </summary>
    /// <history>
    ///     [Tim Hibbard]   01/24/2007  Created
    /// </history>
    public string VPNConnectionName {
      get { return _VPNConnectionName; }
      set { _VPNConnectionName = value; }
    }
#endregion

#region-- Private Methods--
    /// <summary>
    /// Pings the provided IP to validate connection
    /// </summary>
    /// <returns>True if you are connected</returns>
    /// <history>
    ///     [Tim Hibbard]   01/24/2007  Created
    /// </history>
    public bool TestConnection() {
      bool RV = false;
      _isChecking = true;
      try {
        OnPinging();
        System.Net.NetworkInformation.Ping ping =
            new System.Net.NetworkInformation.Ping();

        if (ping.Send(_IPToPing).Status ==
            System.Net.NetworkInformation.IPStatus.Success) {
          RV = true;
        } else {
          RV = false;
        }
        ping = null;
        if (RV != _isConnected) {
          _isConnected = RV;
          OnConnectionStatusChanged(_isConnected);
        }
        OnIdle();
      } catch (Exception Ex) {
        Debug.Assert(false, Ex.ToString());
        RV = false;
        OnIdle();
      }
      _isChecking = false;
      return RV;
    }

    /// <summary>
    /// Shells the command to connect to the VPN
    /// </summary>
    /// <returns>True if connected</returns>
    /// <history>
    ///     [Tim Hibbard]   01/24/2007  Created
    /// </history>
    private bool ConnectToVPN() {
      bool RV = false;
      try {
        OnConnecting();
        Process.Start(VPNPROCESS, " -d " + _VPNConnectionName);
        System.Windows.Forms.Application.DoEvents();
        System.Threading.Thread.Sleep(5000);
        System.Windows.Forms.Application.DoEvents();
        RV = true;
        OnIdle();

      } catch (Exception Ex) {
        Debug.Assert(false, Ex.ToString());
        RV = false;
        OnIdle();
      }
      return RV;
    }

    /// <summary>
    /// Shells the command to disconnect from the VPN connection
    /// </summary>
    /// <returns>True if successfully disconnected</returns>
    /// <history>
    ///     [Tim Hibbard]   01/24/2007  Created
    /// </history>
    private bool DisconnectFromVPN() {
      bool RV = false;
      try {
        OnDisconnecting();
        System.Diagnostics.Process.Start(VPNPROCESS,
                                         " -h " + _VPNConnectionName);
        System.Windows.Forms.Application.DoEvents();
        System.Threading.Thread.Sleep(8000);
        System.Windows.Forms.Application.DoEvents();
        RV = true;
        OnIdle();
      } catch (Exception Ex) {
        Debug.Assert(false, Ex.ToString());
        RV = false;
        OnIdle();
      }
      return RV;
    }

    /// <summary>
    /// Handles the grunt work.
    /// </summary>
    /// <history>
    ///     [Tim Hibbard]   01/24/2007  Created
    /// </history>
    private void Manage() {
      try {
        if (!_isManaging) {
          _isManaging = true;
          if (!_isChecking) {
            if (!TestConnection()) {
              ConnectToVPN();
              if (!TestConnection()) {
                DisconnectFromVPN();
                ConnectToVPN();
                if (!TestConnection()) {
                  DisconnectFromVPN();
                  ConnectToVPN();
                }
              }
            }
          }
          _isManaging = false;
        }
      } catch (Exception) {
        _isManaging = false;
      }
    }
#endregion

#region-- Public Methods--
    /// <summary>
    /// Overloaded end point to begin monitoring VPN status
    /// </summary>
    /// <param name="VPNName">Name of VPN connection as seen in network
    /// connections (not case sensitive)</param> <param name="IPtoPing">IP to
    /// ping to validate connectivity</param> <history>
    ///     [Tim Hibbard]   01/24/2007  Created
    /// </history>
    public void StartManaging(string VPNName, string IPtoPing) {
      _VPNConnectionName = VPNName;
      _IPToPing = IPtoPing;
      StartManaging();
    }

    /// <summary>
    /// End point to begin monitoring VPN status
    /// </summary>
    /// <history>
    ///     [Tim Hibbard]   01/24/2007  Created
    /// </history>
    public void StartManaging() {
      if (!string.IsNullOrEmpty(_VPNConnectionName) &
          !string.IsNullOrEmpty(_IPToPing)) {
        MonitorTimer = new System.Timers.Timer(15000);
        MonitorTimer.Enabled = true;
        MonitorTimer.Elapsed +=
            new System.Timers.ElapsedEventHandler(MonitorTimer_Elapsed);
        System.Net.NetworkInformation.NetworkChange
            .NetworkAvailabilityChanged +=
            new System.Net.NetworkInformation
                .NetworkAvailabilityChangedEventHandler(
                    NetworkChange_NetworkAvailabilityChanged);
        Microsoft.Win32.SystemEvents.PowerModeChanged +=
            new Microsoft.Win32.PowerModeChangedEventHandler(
                SystemEvents_PowerModeChanged);
        Manage();
      }
    }
#endregion

#region-- Constructors--
    /// <summary>
    /// Overloaded constructor
    /// </summary>
    /// <param name="VPNName">Name of VPN connection as seen in network
    /// connections (not case sensitive)</param> <param name="IPtoPing">IP to
    /// ping to validate connectivity</param> <history>
    ///     [Tim Hibbard]   01/24/2007  Created
    /// </history>
    public VPN(string VPNName, string IPtoPing) {
      StartManaging(VPNName, IPtoPing);
    }

    /// <summary>
    /// Default empty constructor
    /// </summary>
    /// <history>
    ///     [Tim Hibbard]   01/24/2007  Created
    /// </history>
    public VPN() {}
#endregion

#region-- Event Handlers--
    /// <summary>
    /// Handles the event that is raised when the computer goes into, or comes
    /// out of, standby.  Very useful for laptops
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    /// <history>
    ///     [Tim Hibbard]   01/24/2007  Created
    /// </history>
    void SystemEvents_PowerModeChanged(
        object sender, Microsoft.Win32.PowerModeChangedEventArgs e) {
      if (e.Mode == Microsoft.Win32.PowerModes.Resume) {
        MonitorTimer.Stop();
        System.Threading.Thread.Sleep(15000);
        MonitorTimer.Start();
      }
      if (e.Mode == Microsoft.Win32.PowerModes.Suspend) {
        MonitorTimer.Stop();
      }
    }

    /// <summary>
    /// Handles the event that is raised when the network status changes
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    /// <history>
    ///     [Tim Hibbard]   01/24/2007  Created
    /// </history>
    void NetworkChange_NetworkAvailabilityChanged(
        object sender,
        System.Net.NetworkInformation.NetworkAvailabilityEventArgs e) {
      if (e.IsAvailable) {
        if (!MonitorTimer.Enabled) {
          MonitorTimer.Start();
        }
      } else {
        MonitorTimer.Stop();
      }
    }

    /// <summary>
    /// Handles the event the timer raises when it elapses
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    /// <history>
    ///     [Tim Hibbard]   01/24/2007  Created
    /// </history>
    void MonitorTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) {
      Manage();
    }
#endregion
  }
}

Print | posted on Monday, January 22, 2007 9:14 AM |

This article is part of the GWB Archives. Original Author: Tim Hibbard

Related Posts