确定哪个网络适配器在C#中具有最高优先级?

时间:2016-06-29 18:08:51

标签: c# networking

如果我们在给定的计算机上有多个具有相同DNS后缀的网络接口,我如何以编程方式确定将路由哪些网络接口流量?

例如,我通过办公室中的以太网连接到我的公司网络,并通过VPN从办公室内部连接到公司网络。这听起来很愚蠢,但是我们的网络连接方式,如果我们的数据中心的内部链接出现故障 - 我从办公室内部进行VPN连接以继续开发。

我们的软件具有确定我们的“本地IP地址”的逻辑,并将其用于其他地方的身份验证逻辑。我从实践中知道,我的所有流量都是在连接时通过VPN路由的 - 但我正在努力解决代码中正确实现的问题,以便可靠地选择具有最高优先级的适配器的IP地址。

我现在拥有的是:

var unicastIpAddressInformation = NetworkInterface.GetAllNetworkInterfaces()
                .Where(nic => nic.OperationalStatus == OperationalStatus.Up
                                && nic.NetworkInterfaceType != NetworkInterfaceType.Loopback // ...ignore the loopback NIC as we don't want 127.0.0.1 (1 of 2)
                                && nic.Name.IndexOf("loopback", StringComparison.OrdinalIgnoreCase) == -1 // ...ignore the loopback NIC as we don't want 127.0.0.1 (2 of 2)
                                && nic.Name.IndexOf("virtual", StringComparison.OrdinalIgnoreCase) == -1 // ... ignore virtual NICs so that VMs don't conflict with IP resolution
                )
                .Select(n => n.GetIPProperties())
                // All developer network connections should have the my-company-internal.com suffix
                .Where(ipp => ipp.DnsSuffix.ToLowerInvariant().IndexOf("my-company-internal.com", StringComparison.OrdinalIgnoreCase) >= 0)
                .Where(ipp => ipp.UnicastAddresses.Any(u => u.Address.AddressFamily == AddressFamily.InterNetwork))
                // Is this order by correct?
                .OrderByDescending(ipp => ipp.GetIPv4Properties().Index)
                .SelectMany(ipp => ipp.UnicastAddresses.Where(ip => ip.Address.AddressFamily == AddressFamily.InterNetwork))
                .FirstOrDefault();

我知道IPV4Properties.Index - 它只在启用IPv4时填充;我不知道是否符合优先级或指标,以及它们是否保证是不同的。

1 个答案:

答案 0 :(得分:0)

几周前我在这里遇到了同样的问题。我发现NIC优先级保留在Windows注册表中,并且有一些PowerShell脚本可以给您NIC顺序,但不能给您IP地址。因此,我编写了下面的代码,它对我有用。您可以使用它来查看其他信息,例如dns后缀,网关地址和加号。

您只需要调用RMSNetUtils.GetTopIpv4Ip(string.Empty)

  public class RMSNetUtils
  {
    private static string _linkagePath = @"SYSTEM\CurrentControlSet\Services\Tcpip\Linkage";

    private static string _interfacesPath = @"SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\";

    private static List<string> GetBindingsPriority()
    {
      using (var bindMasterKey = Registry.LocalMachine.OpenSubKey(_linkagePath))
      {
        var bind = (string[]) bindMasterKey.GetValue("Bind");
        var deviceList = bind.Select(x => $@"{_interfacesPath}{x.Replace("\\Device\\", string.Empty)}")
          .ToList();

        var result = new List<string>();

        foreach (var device in deviceList)
        {
          using (var bindKey = Registry.LocalMachine.OpenSubKey(device))
          {
            var fixIP = (string[])bindKey.GetValue("IPAddress");
            if (fixIP != null)
            {
              result.Add( fixIP.FirstOrDefault());
              continue;
            }

            var dhcpIp = bindKey.GetValue("DhcpIPAddress");
            if (dhcpIp != null)
            {
              result.Add((string) dhcpIp);
            }
          }
        }
        return result;
      }
    }

    private static List<NICInformation> GetFilteredBindings()
    {
      var bindings = GetBindingsPriority();
      var nicsInfo = GetIpList(GetInterNetworkAdapters());
      var result = new List<NICInformation>();
      foreach (var bind in bindings)
      {
        var nicInfo = nicsInfo.FirstOrDefault(y => string.Compare(y.IPv4, bind) == 0);
        if(nicInfo!= null)
          result.Add(nicInfo);
      }

      return result;
    }

    private static IEnumerable<IPAddress> GetInterNetworkAdapters()
    {
      IPHostEntry local = Dns.GetHostEntry(string.Empty);
      return (from ipa in local.AddressList
        where ipa.AddressFamily == AddressFamily.InterNetwork
        select ipa);
    }

    public static string GetFirstIpv4Ip()
    {
      return GetFirstIpv4Ip(String.Empty);
    }

    private static List<NICInformation> GetIpList(IEnumerable<IPAddress> ips)
    {
      var ipAddresses = ips.Select(x => x.ToString()).ToList();
      var result = new List<NICInformation>();

      foreach (NetworkInterface ni in NetworkInterface.GetAllNetworkInterfaces())
      {
        if (ni.NetworkInterfaceType == NetworkInterfaceType.Wireless80211 ||
            ni.NetworkInterfaceType == NetworkInterfaceType.Ethernet)
        {
          foreach (UnicastIPAddressInformation ip in ni.GetIPProperties().UnicastAddresses)
          {
            if (ip.Address.AddressFamily == AddressFamily.InterNetwork)
            {
              var ipStr = ip.Address.ToString();
              if (ipAddresses.Contains(ipStr))
              {
                var nic = new NICInformation();
                nic.IPv4 = ip.Address.ToString();
                nic.Mask = ip.IPv4Mask.ToString();
                nic.DnsSuffix = ni.GetIPProperties().DnsSuffix;
                var gateway = ni.GetIPProperties().GatewayAddresses.FirstOrDefault();
                if(gateway!=null)
                  nic.Gateway = gateway.Address.ToString();
                result.Add(nic);
              }
            }
          }
        }
      }

      return result;
    }

    public static string GetTopIpv4Ip(string hostName)
    {
      if (!string.IsNullOrEmpty(hostName))
        return GetFirstIpv4Ip(hostName);
      var item = GetFilteredBindings().FirstOrDefault();

      return item == null ? hostName : item.IPv4;
    }

    public static string GetFirstIpv4Ip(string hostName)
    {
      var ip = string.Empty;
      try
      {
        IPHostEntry local = Dns.GetHostEntry(hostName);
        var result = GetInterNetworkAdapters().FirstOrDefault();

        return result != null ? result.ToString() : hostName;
      }
      catch (SocketException ex)
      {
        ip = hostName;
      }

      return ip;
    }
  }

  public class NICInformation
  {
    public string DnsSuffix {get;set;}
    public string IPv4 {get;set; }

    public string Gateway {get;set;}

    public string Mask {get;set;}
  }