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?
-
\$\begingroup\$ Single responsibility... your function is doing more than it says it does. \$\endgroup\$404– 4042017年02月19日 00:16:54 +00:00Commented Feb 19, 2017 at 0:16
1 Answer 1
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.
-
\$\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\$Owen– Owen2017年02月21日 16:53:11 +00:00Commented Feb 21, 2017 at 16:53
-
\$\begingroup\$ @Owen I'm glad that I brought some good ideas forward. \$\endgroup\$Svek– Svek2017年02月21日 17:16:39 +00:00Commented 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\$Svek– Svek2017年02月21日 17:26:13 +00:00Commented 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\$Owen– Owen2017年02月21日 21:44:34 +00:00Commented Feb 21, 2017 at 21:44