【问题标题】:Determine which network adapter has the highest priority in C#?确定哪个网络适配器在 C# 中具有最高优先级?
【发布时间】:2016-06-29 18:08:50
【问题描述】:

如果我们在给定机器上有多个具有相同 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 时才会填充它;我不知道是否对应于优先级或度量,以及它们是否保证是不同的。

【问题讨论】:

  • 对于IP,优先级由掩码大小决定。掩码越小优先级越高。流量将始终以较小的掩码流出路线。当主路由关闭时,数据会从次路由流出。
  • 我知道 - 我两次连接到我的公司网络。我有 2 个 IP 地址,每个 IP 地址都具有相同的网络掩码,并且每个 IP 地址都可以访问相同的路由。我清楚地看到 VPN 适配器受到青睐 - 我如何在代码中以编程方式获取 VPN 适配器 IP 地址?
  • 换面具!!!没有其他办法。 WINDOWS操作系统只用面具!!!
  • @jdweng "流量总是会从掩码较小的路线流出。" 这完全是倒退。较大的掩码更具体,因此使用具有较大掩码的路由。例如,默认掩码(0.0.0.0 = 0 位)是最小的掩码,默认路由是最不优选的,而最大的掩码(255.255.255.255 = 32 位)是最具体的具有此掩码的路由是最喜欢的。

标签: c# networking


【解决方案1】:

几周前我在这里遇到了同样的问题。我发现 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;}
  }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-02-11
    • 2011-12-08
    • 1970-01-01
    • 1970-01-01
    • 2014-03-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多