【问题标题】:How to determine whether an IP address is private?如何判断一个IP地址是否是私有的?
【发布时间】:2011-11-13 18:04:53
【问题描述】:

到目前为止,我有这个代码:

NetworkInterface[] adapters = NetworkInterface.GetAllNetworkInterfaces();

foreach (NetworkInterface adapter in adapters)
{
  IPInterfaceProperties properties = adapter.GetIPProperties();

  foreach (IPAddressInformation uniCast in properties.UnicastAddresses)
  {

    // Ignore loop-back addresses & IPv6
    if (!IPAddress.IsLoopback(uniCast.Address) && 
      uniCast.Address.AddressFamily!= AddressFamily.InterNetworkV6)
        Addresses.Add(uniCast.Address);
  }
}

如何过滤私有 IP 地址?以同样的方式过滤环回 IP 地址。

【问题讨论】:

    标签: c# asp.net network-programming


    【解决方案1】:

    更详细的回复在这里:

    private bool _IsPrivate(string ipAddress)
    {
        int[] ipParts = ipAddress.Split(new String[] { "." }, StringSplitOptions.RemoveEmptyEntries)
                                 .Select(s => int.Parse(s)).ToArray();
        // in private ip range
        if (ipParts[0] == 10 ||
            (ipParts[0] == 192 && ipParts[1] == 168) ||
            (ipParts[0] == 172 && (ipParts[1] >= 16 && ipParts[1] <= 31))) {
            return true;
        }
    
        // IP Address is probably public.
        // This doesn't catch some VPN ranges like OpenVPN and Hamachi.
        return false;
    }
    

    【讨论】:

    【解决方案2】:

    做到这一点的最佳方法是 IP 地址类的扩展方法

        /// <summary>
        /// An extension method to determine if an IP address is internal, as specified in RFC1918
        /// </summary>
        /// <param name="toTest">The IP address that will be tested</param>
        /// <returns>Returns true if the IP is internal, false if it is external</returns>
        public static bool IsInternal(this IPAddress toTest)
        {
            if (IPAddress.IsLoopback(toTest)) return true;
            else if (toTest.ToString() == "::1") return false;
    
            byte[] bytes = toTest.GetAddressBytes();
            switch( bytes[ 0 ] )
            {
                case 10:
                    return true;
                case 172:
                    return bytes[ 1 ] < 32 && bytes[ 1 ] >= 16;
                case 192:
                    return bytes[ 1 ] == 168;
                default:
                    return false;
            }
        }
    

    然后,可以在 IP 地址类的实例上调用该方法

        bool isIpInternal = ipAddressInformation.Address.IsInternal();
    

    【讨论】:

    • 在开始时插入这个以获取 IP v6 环回案例: if (IPAddress.IsLoopback(toTest)) return true;
    • 如果是 IPV6 而不是 IPV6 环回,也可以返回 false
    【解决方案3】:

    添加了 IPv6 和 localhost 案例。

        /* An IP should be considered as internal when:
    
           ::1          -   IPv6  loopback
           10.0.0.0     -   10.255.255.255  (10/8 prefix)
           127.0.0.0    -   127.255.255.255  (127/8 prefix)
           172.16.0.0   -   172.31.255.255  (172.16/12 prefix)
           192.168.0.0  -   192.168.255.255 (192.168/16 prefix)
         */
        public bool IsInternal(string testIp)
        {
            if(testIp == "::1") return true;
    
            byte[] ip = IPAddress.Parse(testIp).GetAddressBytes();
            switch (ip[0])
            {
                case 10:
                case 127:
                    return true;
                case 172:
                    return ip[1] >= 16 && ip[1] < 32;
                case 192:
                    return ip[1] == 168;
                default:
                    return false;
            }
        }
    

    【讨论】:

    【解决方案4】:

    私有地址范围在RFC1918 中定义。它们是:

    • 10.0.0.0 - 10.255.255.255(10/8 前缀)
    • 172.16.0.0 - 172.31.255.255(172.16/12 前缀)
    • 192.168.0.0 - 192.168.255.255(192.168/16前缀)

    您可能还想过滤掉RFC3927 中定义的链接本地地址 (169.254/16)。

    【讨论】:

      【解决方案5】:
      10.0.0.0        -   10.255.255.255  (10/8 prefix)
      172.16.0.0      -   172.31.255.255  (172.16/12 prefix)
      192.168.0.0     -   192.168.255.255 (192.168/16 prefix)
      

      使用 RFC 中定义的范围(如 Anders 建议的那样);而不是使用正则表达式从列表中检测/删除私有 IP 地址。

      这是一个用于检测私有 IP 地址的示例 RegEx。 (未经我测试)

      (^127\.0\.0\.1)|
      (^10\.)|
      (^172\.1[6-9]\.)|(^172\.2[0-9]\.)|(^172\.3[0-1]\.)|
      (^192\.168\.)
      

      【讨论】:

      • 可能更容易转换为 uint32,然后使用按位运算:((address &amp; 0xFF000000U) == 0x0A000000U) || ...。如果有很多地址要检查它也应该更快。
      • 我怀疑这会起作用,但正则表达式在概念上是用于测试小整数是否在正确范围内的错误工具。比较数字将比匹配字符串更有效。
      • 将当前 IP 转换为数字表示,然后查看它是否适合任何类别(仅使用数字比较)。它对我来说非常有效。
      • 请注意,127.0.0.0/8 保留用于回送(不仅是 127.0.0.1,还有 127.*.*.*),请参阅en.wikipedia.org/wiki/Loopback
      猜你喜欢
      • 2013-11-07
      • 2010-11-19
      • 2013-07-30
      • 1970-01-01
      • 2014-03-27
      • 2012-11-28
      • 2010-10-16
      • 1970-01-01
      • 2011-03-26
      相关资源
      最近更新 更多