Friday, 27 October 2017

Open & Close a VPN Connection with C#

I've thrown together this simple class to check if a windows VPN connection is open and with it you can also connect and disconnect. It's not massively robust but does the trick. It's makes use of the rasdial command and is inspired by this post on SO.

Here's how to use it:
//Get a VPN connector ready
VPNConnector vpn = new VPNConnector("VPN_NAME", "USER_NAME", "USER_PASSWORD");

//Connect
Tuple<bool, IList<string>> response = vpn.Connect();

if (response.Item1)
{
    //Successfully connected
    Console.WriteLine("Connected!");
}
else
{
    //Failed to connect
    Console.WriteLine("Failed to connect :(");
    foreach (string s in response.Item2)
    {
        Console.WriteLine(s);
    }
}

//Disconnect
vpn.Disconnect();

You can optionally check if the connection is already open by using vpn.IsOpen.

The code:
/// <summary>
/// Gives access to Windows VPN connections
/// </summary>
public class VPNConnector
{

	#region Properties

	#region VPNName
	/// <summary>
	/// The name of the VPN connection
	/// </summary>
	public string VPNName { get; set; }
	#endregion

	#region Username
	/// <summary>
	/// The username to use for the connection
	/// </summary>
	public string Username { get; set; }
	#endregion

	#region Password
	/// <summary>
	/// The password to use for the connection
	/// </summary>
	public string Password { get; set; }
	#endregion

	#region IsOpen
	/// <summary>
	/// Whether the connection is currently open or not
	/// </summary>
	public bool IsOpen
	{
		get
		{
			if (String.IsNullOrWhiteSpace(this.VPNName))
				throw new ArgumentException("No VPN name (VPNName) has been set");
			
			Process p = this.getNewProcess;
			p.Start();

			bool bOpen = false;
			while (!p.StandardOutput.EndOfStream)
			{
				string sOutput = p.StandardOutput.ReadLine();
				if (sOutput.ToLower() != "no connections")
				{
					if (sOutput == this.VPNName)
					{
						bOpen = true;
						break;
					}
				}
				else
					break;
			}
			p.WaitForExit();

			return bOpen;
		}
	}
	#endregion

	#region parametersAreASet
	/// <summary>
	/// Determines if all the necessary parameters are set to make a VPN connection
	/// </summary>
	private bool parametersAreASet { get { return (!String.IsNullOrWhiteSpace(this.VPNName) && !String.IsNullOrWhiteSpace(this.Username) && !String.IsNullOrWhiteSpace(this.Password)); } }
	#endregion

	#region getNewProcess
	/// <summary>
	/// Get a new process ready to start a rasdial call
	/// </summary>
	private Process getNewProcess
	{
		get
		{
			return new Process
			{
				StartInfo = new ProcessStartInfo
				{
					FileName = "rasdial.exe",
					UseShellExecute = false,
					RedirectStandardOutput = true,
					CreateNoWindow = true
				}
			};
		}
	} 
	#endregion

	#endregion

	#region Cosntructor
	public VPNConnector() { }

	public VPNConnector(string name, string username, string password)
	{
		this.VPNName = name;
		this.Username = username;
		this.Password = password;

		if (!this.parametersAreASet)
			throw new ArgumentException("All arguments must have a value");
	}
	#endregion

	#region Public Methods

	#region Instance

	#region Connect
	/// <summary>
	/// Make a connection to the VPN. Item1 of Tuple indicates success or failure. Item2 of Tuple is the output of the dial call
	/// </summary>
	public Tuple<bool, IList<string>> Connect()
	{
		if (!this.IsOpen)
		{
			if (!this.parametersAreASet)
				throw new ArgumentException("All arguments must have a value");

			Process p = this.getNewProcess;
			p.StartInfo.Arguments = $"\"{this.VPNName}\" \"{this.Username}\" \"{ this.Password}\"";
			p.Start();

			bool bSuccess = false;
			IList<string> outputs = new List<string&gt();
			while (!p.StandardOutput.EndOfStream)
			{
				string sOutput = p.StandardOutput.ReadLine();
				outputs.Add(sOutput);

				if (sOutput.ToLower().StartsWith("success"))
					bSuccess = true;
			}
			p.WaitForExit();

			return new Tuple<bool, IList<string>>(bSuccess, outputs);
		}
		else
			return new Tuple<bool, IList<string>>(false, new List<string>() { "Connection already open" } );
	}
	#endregion

	#region Disconnect
	/// <summary>
	/// Disconnect from the VPN. Item1 of Tuple indicates success or failure. Item2 of Tuple is the output of the dial call
	/// </summary>
	public Tuple<bool, IList<string>> Disconnect()
	{
		if (this.IsOpen)
		{
			Process p = this.getNewProcess;
			p.StartInfo.Arguments = $"\"{this.VPNName}\" /d";
			p.Start();

			bool bSuccess = false;
			IList<string> outputs = new List<string>();
			while (!p.StandardOutput.EndOfStream)
			{
				string sOutput = p.StandardOutput.ReadLine();
				outputs.Add(sOutput);

				if (sOutput.ToLower().Contains("success"))
					bSuccess = true;
			}
			p.WaitForExit();

			return new Tuple<bool, IList<string>>(bSuccess, outputs);
		}
		else
			return new Tuple<bool, IList<string>>(false, new List<string&gt() { "Connection already closed" });
	}
	#endregion

	#endregion

	#endregion

}

No comments:

Post a Comment