2
\$\begingroup\$

I wrote a method that will start OpenVPN on a config file, and then wait to be connected.

It relies on OpenVPN using Local Area Connection 2, which hurts code reusability, but I'm not sure how to do it any other way.

private static async void StartOpenVPN(string configFile)
{
 // Start OpenVPN on the config file...
 Process.Start("openvpn-gui", $"--connect {configFile}");
 // OpenVPN uses Local Area Connection 2.
 var adapter =
 NetworkInterface.GetAllNetworkInterfaces()
 .First(networkInterface => networkInterface.Name == "Local Area Connection 2");
 // Wait for Local Area Connection 2 to be operational...
 while (adapter.OperationalStatus != OperationalStatus.Up)
 {
 await Task.Delay(100);
 adapter =
 NetworkInterface.GetAllNetworkInterfaces()
 .First(networkInterface => networkInterface.Name == "Local Area Connection 2");
 }
 Console.WriteLine("Connected!");
}

Is there a more effective/efficient/elegant way to start OpenVPN on a config file, and then wait to be connected?

t3chb0t
44.6k9 gold badges84 silver badges190 bronze badges
asked Feb 18, 2017 at 21:33
\$\endgroup\$
1
  • \$\begingroup\$ Single responsibility... your function is doing more than it says it does. \$\endgroup\$ Commented Feb 19, 2017 at 0:16

1 Answer 1

2
\$\begingroup\$

Use the Gateway or Unicast IP Address

For the case of checking if the VPN Connection is online or not, you could consider a solution that just returns a boolean value.

Secondly, I wouldn't do it by connection name, instead how about using either the gateway IP address or the unicast IP address?

public class OpenVpnConnection
{
 private IPAddress _gatewayIpAddress;
 private IPAddress _unicastIpAddress;
 public OpenVpnConnection()
 {
 _gatewayIpAddress = IPAddress.Parse("10.0.0.1");
 _unicastIpAddress = IPAddress.Parse("10.0.0.101");
 }
 public bool IsNetworkAvailable()
 {
 if (!NetworkInterface.GetIsNetworkAvailable())
 return false;
 foreach (NetworkInterface ni in NetworkInterface.GetAllNetworkInterfaces())
 {
 // discard because of standard reasons
 if (ni.OperationalStatus != OperationalStatus.Up) continue;
 if (ni.NetworkInterfaceType == NetworkInterfaceType.Loopback) continue;
 //if (ni.NetworkInterfaceType == NetworkInterfaceType.Tunnel) continue;
 // discard if the interface is not "virtual"
 //if (ni.Description.IndexOf("virtual", StringComparison.OrdinalIgnoreCase) <= 0) continue;
 //if (ni.Name.IndexOf("virtual", StringComparison.OrdinalIgnoreCase) <= 0) continue;
 if (GetIpFromGatewayAddresses(ni).Contains(_gatewayIpAddress)) return true;
 if (GetIpFromUnicastAddresses(ni).Contains(_unicastIpAddress)) return true;
 }
 return false;
 }
 private static IEnumerable<IPAddress> GetIpFromGatewayAddresses(NetworkInterface nic)
 {
 return nic.GetIPProperties().GatewayAddresses
 .Where(ip => ip.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
 .Select(ip => ip.Address);
 }
 private static IEnumerable<IPAddress> GetIpFromUnicastAddresses(NetworkInterface nic)
 {
 return nic.GetIPProperties().UnicastAddresses
 .Where(ip => ip.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
 .Select(ip => ip.Address);
 }
}

You can take out sections of the code that you don't need, but I included both unicast and gateway options above.

You would then simply check if the connection is online by

var vpn = new OpenVpnConnection();
bool online = vpn.IsNetworkAvailable();

of course, you'll want to pass parameters and what-not, but this is simply to illustrate the idea of moving away from the connection name and using an IP address instead.


Putting it together

A quick and dirty way of piecing it together with you current code would look something like this

private static async void StartOpenVPN(string configFile)
{
 // Start OpenVPN on the config file...
 Process.Start("openvpn-gui", $"--connect {configFile}");
 var vpn = new OpenVpnConnection(); //of course, send parameters in your actual code
 while (!vpn.IsNetworkAvailable)
 {
 await Task.Delay(100);
 }
 Console.WriteLine("Connected!");
}

Rather than using a loop, you could consider using the NetworkChange.NetworkAvailabilityChanged Event instead.

answered Feb 20, 2017 at 6:30
\$\endgroup\$
4
  • \$\begingroup\$ Even though I'm not going to use anything you wrote (thanks though), I'm marking this as the answer because of the unicast address idea, and because you made me realize how clunky my "wait until connected loop" was. \$\endgroup\$ Commented Feb 21, 2017 at 16:53
  • \$\begingroup\$ @Owen I'm glad that I brought some good ideas forward. \$\endgroup\$ Commented Feb 21, 2017 at 17:16
  • \$\begingroup\$ @Owen On further thought, may I recommend to consider thinking about using a gateway address (instead of unicast)? I feel that the gateway address is usually more static/reliable overall versus a client address, as it is more resilient to reconnects, self-assigned addresses, NAT and other routing-related issues. \$\endgroup\$ Commented Feb 21, 2017 at 17:26
  • \$\begingroup\$ I'll look into using the gateway address instead, thanks! I'm not very experienced with anything network related, so I appreciate the advice. :) \$\endgroup\$ Commented Feb 21, 2017 at 21:44

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.