239 lines
9.9 KiB
C#
239 lines
9.9 KiB
C#
using DTS.Common.Utilities.Logging;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Net;
|
|
using System.Net.NetworkInformation;
|
|
using System.Net.Sockets;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace DTS.Common.Utils
|
|
{
|
|
//FB 18512 This calss contains utility methods, they are moved from Netwroking module
|
|
public static class NetworkUtils
|
|
{
|
|
/// <summary>
|
|
/// returns true if the network interface is up, false otherwise
|
|
/// stolen from FWTU
|
|
/// </summary>
|
|
/// <param name="ip"></param>
|
|
/// <returns></returns>
|
|
public static bool IsNetworkInterfaceUp(IPAddress ip)
|
|
{
|
|
foreach (var a in NetworkInterface.GetAllNetworkInterfaces())
|
|
{
|
|
try
|
|
{
|
|
var ipp = a.GetIPProperties();
|
|
|
|
if (ipp.MulticastAddresses.Count == 0)
|
|
continue; // most of VPN adapters will be skipped
|
|
if (!a.SupportsMulticast)
|
|
continue; // multicast is meaningless for this type of connection
|
|
if (OperationalStatus.Up != a.OperationalStatus)
|
|
continue; // this adapter is off or not connected
|
|
if (null == ipp.GetIPv4Properties())
|
|
continue; // IPv4 is not configured on this adapter
|
|
if (a.NetworkInterfaceType == NetworkInterfaceType.Loopback)
|
|
continue;
|
|
var addressBytes = ip.GetAddressBytes();
|
|
if (!AllowInternalNICIPs && 4 == addressBytes.Length && addressBytes[0] == 169 && addressBytes[1] == 254) { continue; }
|
|
if (a.GetIPProperties().UnicastAddresses.Any(i => i.Address.AddressFamily == AddressFamily.InterNetwork && IPAddress.Equals(i.Address, ip)))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
/// <summary>
|
|
/// Indicates whether any network connection is available.
|
|
/// Filter connections below a specified speed, as well as virtual network cards.
|
|
/// </summary>
|
|
/// <param name="minimumSpeed">The minimum speed required. Passing 0 will not filter connection using speed.</param>
|
|
/// <returns>
|
|
/// <c>true</c> if a network connection is available; otherwise, <c>false</c>.
|
|
/// </returns>
|
|
private static List<NetworkInterface> GetAvailableNetworkInterfaces(long minimumSpeed = 115200)
|
|
{
|
|
if (!NetworkInterface.GetIsNetworkAvailable())
|
|
return null;
|
|
|
|
var niList = new List<NetworkInterface>();
|
|
foreach (var ni in NetworkInterface.GetAllNetworkInterfaces())
|
|
{
|
|
// discard because of standard reasons
|
|
if ((ni.NetworkInterfaceType == NetworkInterfaceType.Loopback)
|
|
|| (ni.NetworkInterfaceType == NetworkInterfaceType.Tunnel))
|
|
continue;
|
|
|
|
// this allow to filter modems, serial, etc.
|
|
// use 10000000 as a minimum speed for most cases
|
|
if (ni.Speed < minimumSpeed)
|
|
continue;
|
|
|
|
// discard virtual cards (virtual box, virtual pc, etc.)
|
|
if (ni.Description.ToLower().Contains("virtual")
|
|
|| ni.Name.ToLower().Contains("virtual")
|
|
|| ni.Description.ToLower().Contains("bluethooth")
|
|
|| ni.Name.ToLower().Contains("bluethooth"))
|
|
continue;
|
|
|
|
// discard "Microsoft Loopback Adapter", it will not show as NetworkInterfaceType.Loopback but as Ethernet Card.
|
|
if (ni.Description.Equals("Microsoft Loopback Adapter", StringComparison.OrdinalIgnoreCase))
|
|
continue;
|
|
|
|
niList.Add(ni);
|
|
}
|
|
|
|
return niList;
|
|
}
|
|
|
|
private static string GetMACAddress(string id)
|
|
{
|
|
var macAddress = string.Empty;
|
|
|
|
var nics = GetAvailableNetworkInterfaces();
|
|
|
|
if (nics == null)
|
|
return macAddress;
|
|
|
|
foreach (var nic in nics)
|
|
{
|
|
if (nic.Id != id) continue;
|
|
var pa = BitConverter.ToString(nic.GetPhysicalAddress().GetAddressBytes());
|
|
pa = pa.Replace("-", ":");
|
|
if (string.IsNullOrEmpty(pa)) continue;
|
|
macAddress = pa;
|
|
break;
|
|
}
|
|
return macAddress;
|
|
}
|
|
|
|
private static bool InvalidNIC(NetworkInterface ni)
|
|
{
|
|
return OperationalStatus.Up != ni.OperationalStatus || !ni.SupportsMulticast;
|
|
}
|
|
public static bool AllowInternalNICIPs { get; set; } = false;
|
|
public static List<HostInfo> GetAvailableHosts(bool supportMulticastOnly = false)
|
|
{
|
|
var nics = GetAvailableNetworkInterfaces();
|
|
if (nics == null) { return new List<HostInfo>(); }
|
|
var hosts = new List<HostInfo>();
|
|
|
|
foreach (NetworkInterface ni in nics)
|
|
{
|
|
if (supportMulticastOnly && InvalidNIC(ni))
|
|
{
|
|
continue;
|
|
}
|
|
//exclude wireshark network interface, it claims it can ping ips lyingly
|
|
if (ni.Description.Contains("Npcap")) { continue; }
|
|
foreach (UnicastIPAddressInformation ip in ni.GetIPProperties().UnicastAddresses)
|
|
{
|
|
var addressBytes = ip.Address.GetAddressBytes();
|
|
if ( !AllowInternalNICIPs && 4 == addressBytes.Length && addressBytes[0] == 169 && addressBytes[1] == 254)
|
|
{
|
|
APILogger.Log($"skipping {ni.Name}\\{ni.Description} as it has a 169.254 address");
|
|
continue;//internal only
|
|
}
|
|
if (ip.Address.AddressFamily == AddressFamily.InterNetwork)
|
|
{
|
|
GetStartAndEndAddress(ip.Address, ip.IPv4Mask, out var startAddress, out var endAddress);
|
|
hosts.Add(new HostInfo
|
|
{
|
|
HostIpAddress = ip.Address.ToString(),
|
|
HostNetworkId = ni.Id,
|
|
HostMacAddress = GetMACAddress(ni.Id),
|
|
StartAddress = startAddress,
|
|
EndAddress = endAddress
|
|
});
|
|
}
|
|
}
|
|
}
|
|
return hosts;
|
|
}
|
|
/// <summary>
|
|
/// given an IP address and a mask returns a ip address as a string for the first address that is accessible and a string for the last address that is accessible
|
|
/// anything between the start address and end address after doing a byte-by-byte comparison should be addressable
|
|
/// will return empty strings if something bad happens. Is designed for 4 byte addresses but isn't necessarily limited.
|
|
/// </summary>
|
|
/// <param name="ip"></param>
|
|
/// <param name="mask"></param>
|
|
/// <param name="startAddress"></param>
|
|
/// <param name="endAddress"></param>
|
|
private static void GetStartAndEndAddress(IPAddress ip, IPAddress mask, out string startAddress, out string endAddress)
|
|
{
|
|
try
|
|
{
|
|
var ipByte = ip.GetAddressBytes();
|
|
var maskBytes = mask.GetAddressBytes();
|
|
|
|
var startBytes = new byte[ipByte.Length];
|
|
var endBytes = new byte[ipByte.Length];
|
|
|
|
for (var i = 0; i < ipByte.Length; i++)
|
|
{
|
|
startBytes[i] = (byte)(ipByte[i] & maskBytes[i]);
|
|
endBytes[i] = (byte)(ipByte[i] | ~maskBytes[i]);
|
|
}
|
|
var startIP = new IPAddress(startBytes);
|
|
var endIP = new IPAddress(endBytes);
|
|
startAddress = startIP.ToString();
|
|
endAddress = endIP.ToString();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
startAddress = string.Empty;
|
|
endAddress = string.Empty;
|
|
APILogger.Log(ex);
|
|
}
|
|
}
|
|
//FB 25658 Changed the method signature to return bool to determine the connection string has IP in it and it's not USB
|
|
/// <summary>
|
|
/// Try to parse connectionString and retrieve the IP address.
|
|
/// </summary>
|
|
/// <param name="connectionString"> DAS connectionString which might include the IP address or might be a USB connection string</param>
|
|
/// <param name="ipAddress">Return the parsed IP address from connectionString</param>
|
|
/// <returns>Returns true if was able to parse and get the IP otherwise false including the valid USB connection string </returns>
|
|
public static bool TryParseConnectionString(string connectionString, out string ipAddress)
|
|
{
|
|
ipAddress = null;
|
|
|
|
if (string.IsNullOrEmpty(connectionString))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
try
|
|
{
|
|
var uri = new Uri(connectionString);
|
|
|
|
if (IPAddress.TryParse(uri.Host, out _))
|
|
{
|
|
ipAddress = uri.Host;
|
|
return true;
|
|
}
|
|
|
|
}
|
|
catch
|
|
{
|
|
var ip = connectionString.Split(':')[0];
|
|
|
|
if (IPAddress.TryParse(ip, out _))
|
|
{
|
|
ipAddress = ip;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
}
|