Skip to content

Instantly share code, notes, and snippets.

@bpmooch
Created December 1, 2018 05:13
Show Gist options
  • Select an option

  • Save bpmooch/e8316532fbb66f9bb58c0da3cb2ac833 to your computer and use it in GitHub Desktop.

Select an option

Save bpmooch/e8316532fbb66f9bb58c0da3cb2ac833 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Runtime.InteropServices;
namespace yeeticus
{
internal static class NetworkInterfaceEx
{
/// <summary>
/// Gets a list of network adapter interfaces that are of type ethernet or wireless, and are operational.
/// </summary>
/// <returns>IEnumerable of network interfaces.</returns>
public static IEnumerable<NetworkInterface> GetActiveNICs()
=> NetworkInterface.GetAllNetworkInterfaces()
.Where(x => x.OperationalStatus == OperationalStatus.Up)
.Where(x => x.NetworkInterfaceType == NetworkInterfaceType.Ethernet || x.NetworkInterfaceType == NetworkInterfaceType.Wireless80211);
/// <summary>
/// Retrieves all Gateway Addresses for all Network Interfaces
/// </summary>
/// <returns>IEnumerable containing IPv4 addresses as strings</returns>
public static IEnumerable<string> GetIPv4GatewayAddresses()
=> NetworkInterface.GetAllNetworkInterfaces()
.SelectMany(x => x.GetIPProperties().GatewayAddresses)
.Where(x => x.Address.AddressFamily == AddressFamily.InterNetwork)
.Select(x => x.Address.ToString());
/// <summary>
/// Gets the name of the network adapter.
/// </summary>
/// <param name="ip">IP address of the local network interface to query.</param>
/// <returns>The name of the network interface if found, otherwise "Unknown NIC" is returned.</returns>
public static string GetNICName(string ip)
=> GetActiveNICs().SingleOrDefault(x => x.GetIPProperties()
.UnicastAddresses
.Select(y => y.Address.ToString())
.Contains(ip))?
.Name ?? "Unknown NIC";
/// <summary>
/// Determines if an IP/NIC address pair are reachable
/// </summary>
/// <param name="ip">IP to check</param>
/// <param name="nic">NIC to send data through</param>
/// <returns>True if destination is reachable, false otherwise</returns>
public static bool IsReachable(string ip, string nic)
{
var success = IPAddress.TryParse(ip, out IPAddress addr);
if (!success) return false;
if (!CanArpSuccessfully(nic)) return false;
if (!IsMulticastIP(ip) && !CanArpSuccessfully(ip, nic)) return false;
return true;
}
/// <summary>
/// Sends ARP request
/// </summary>
/// <param name="DestIP">[In] Destination IP</param>
/// <param name="SrcIP">[In] Optional parameter for source IP. 0 for INADDR_ANY</param>
/// <param name="pMacAddr">[Out] Mac Address of Destination IP</param>
/// <param name="PhyAddrLen">[In, Out] Buffer max size. On return, set to amount of buffer used</param>
/// <returns>Returns 0 if successful, error code otherwise</returns>
[DllImport("iphlpapi.dll", ExactSpelling = true)]
public static extern int SendARP(int DestIP,
int SrcIP,
byte[] pMacAddr,
ref uint PhyAddrLen);
/// <summary>
/// Determines if an IP is the loopback address
/// </summary>
/// <param name="ip">IP to check</param>
/// <returns>True if IP Address is loopback</returns>
public static bool IsLoopback(IPAddress ip) => ip == IPAddress.Loopback;
/// <summary>
/// Sends ARP to determine if IP is reachable
/// </summary>
/// <param name="ip">IP to check</param>
/// <returns>Returns true if ARP request was successful, false otherwise</returns>
public static bool CanArpSuccessfully(string ip)
{
if (IPAddress.TryParse(ip, out IPAddress addr))
{
return CanArpSuccessfully(addr);
}
else return false;
}
/// <summary>
/// Sends ARP to determine if IP is reachable
/// </summary>
/// <param name="ip">IP to check</param>
/// <returns>True if ARP was successful, false otherwise</returns>
/// <remarks>
/// Replaces IsHostOnLocalNetwork and IsComputerAlive
/// </remarks>
public static bool CanArpSuccessfully(IPAddress ip)
{
if (IsLoopback(ip)) return true;
var addr = BitConverter.ToUInt32(ip.GetAddressBytes(), 0);
uint macLen = 6;
return SendARP((int)addr, 0, new byte[macLen], ref macLen) == 0;
}
/// <summary>
/// Sends ARP to determine if IP is reachable
/// </summary>
/// <param name="ip">IP to check</param>
/// <param name="nic">NIC to send ARP through</param>
/// <returns>Returns true if ARP request was successful, false otherwise</returns>
public static bool CanArpSuccessfully(string ip, string nic)
{
var success = IPAddress.TryParse(ip, out IPAddress addr);
if (!success) return false;
success = IPAddress.TryParse(nic, out IPAddress nicAddr);
if (!success) return false;
return CanArpSuccessfully(addr, nicAddr);
}
/// <summary>
/// Sends ARP to determine if IP is reachable
/// </summary>
/// <param name="ip">IP to check</param>
/// <param name="nic">NIC to send ARP through</param>
/// <returns>True if ARP was successful, false otherwise</returns>
/// <remarks>
/// Replaces IsHostOnLocalNetwork and IsComputerAlive
/// </remarks>
public static bool CanArpSuccessfully(IPAddress ip, IPAddress nic)
{
if (IsLoopback(ip)) return true;
var addr = BitConverter.ToUInt32(ip.GetAddressBytes(), 0);
var nicAddr = BitConverter.ToUInt32(nic.GetAddressBytes(), 0);
uint macLen = 6;
return SendARP((int)addr, (int)nicAddr, new byte[macLen], ref macLen) == 0;
}
/// <summary>
/// Determines if an IP address is a Multicast address
/// </summary>
/// <param name="ip">string containing IP Address</param>
/// <returns>True if ip is multicast, false otherwise</returns>
public static bool IsMulticastIP(string ip)
{
try
{
var octets = ip.Split('.').Select(x => Convert.ToInt32(x));
if (octets.Count() != 4) return false;
return octets.All(x => Enumerable.Range(0, 256).Contains(x)) &&
Enumerable.Range(224, 239).Contains(octets.First());
}
catch { return false; }
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment