如何确定 IPv6 地址是否为专用地址

本文关键字:地址 专用 是否 IPv6 何确定 | 更新日期: 2023-09-27 18:34:34

我试图确定给定的IPv6地址在C#中是否是私有的,我很想简单地在IPAddress类上使用"IsIPv6SiteLocal"属性。但是,如本注释中所述,此属性中实现的逻辑已弃用。我运行了以下单元测试:

[TestMethod]
public void IsPrivate_ipv6_True()
{
    // This sample private IPv6 address was generated using: http://unique-local-ipv6.com/
    var ip = IPAddress.Parse("fd44:fda4:e1ba::1");
    Assert.IsTrue(ip.IsIPv6SiteLocal);
}

单元测试中的断言失败,这确认 IsIPv6SiteLocal 未正确确定地址是否为本地地址。所以我需要一个替代方案。

写了以下扩展方法,我想知道是否有人能想到一种无法正确确定地址是私有/公共的场景。

public static bool IsPrivateIPv6(this IPAddress address)
{
    var addressAsString = address.ToString();
    var firstWord = addressAsString.Split(new[] { ':' }, StringSplitOptions.RemoveEmptyEntries)[0];
    // Make sure we are dealing with an IPv6 address
    if (address.AddressFamily != AddressFamily.InterNetworkV6) return false;
    // The original IPv6 Site Local addresses (fec0::/10) are deprecated. Unfortunately IsIPv6SiteLocal only checks for the original deprecated version:
    else if (address.IsIPv6SiteLocal) return true;
    // These days Unique Local Addresses (ULA) are used in place of Site Local. 
    // ULA has two variants: 
    //      fc00::/8 is not defined yet, but might be used in the future for internal-use addresses that are registered in a central place (ULA Central). 
    //      fd00::/8 is in use and does not have to registered anywhere.
    else if (firstWord.Substring(0, 2) == "fc" && firstWord.Length >= 4) return true;
    else if (firstWord.Substring(0, 2) == "fd" && firstWord.Length >= 4) return true;
    // Link local addresses (prefixed with fe80) are not routable
    else if (firstWord == "fe80") return true;
    // Discard Prefix
    else if (firstWord == "100") return true;
    // Any other IP address is not Unique Local Address (ULA)
    else return false;
}

已编辑 2/13/2016

  • 确保第一个单词的长度至少为 4 个字符
  • ,如 @RonMaupin
  • 改进了@RonMaupin建议的"否则返回错误"上方的评论
  • 按照@KevinBurdett的建议检查"fe80"前缀
  • 按照@KevinBurdett的建议检查"丢弃"前缀

如何确定 IPv6 地址是否为专用地址

通过为::1添加一个特殊情况并避免从他的解决方案中出现 ArgumentException(这将发生在Substring()调用中(来改进@desautelsj的答案:

public static bool IsPrivateIPv6(IPAddress address)
{
    // Make sure we are dealing with an IPv6 address
    if (address.AddressFamily != AddressFamily.InterNetworkV6)
        throw new ArgumentException("IP address is not V6", "address");
    var addressAsString = address.ToString();
    var firstWord = addressAsString.Split(new[] { ':' }, StringSplitOptions.RemoveEmptyEntries)[0];
    // equivalent of 127.0.0.1 in IPv6
    if (addressAsString == "::1")
        return true;
    // The original IPv6 Site Local addresses (fec0::/10) are deprecated. Unfortunately IsIPv6SiteLocal only checks for the original deprecated version:
    else if (address.IsIPv6SiteLocal)
        return true;
    // These days Unique Local Addresses (ULA) are used in place of Site Local. 
    // ULA has two variants: 
    //      fc00::/8 is not defined yet, but might be used in the future for internal-use addresses that are registered in a central place (ULA Central). 
    //      fd00::/8 is in use and does not have to registered anywhere.
    else if (firstWord.Length >= 4 && firstWord.Substring(0, 2) == "fc")
        return true;
    else if (firstWord.Length >= 4 && firstWord.Substring(0, 2) == "fd")
        return true;
    // Link local addresses (prefixed with fe80) are not routable
    else if (firstWord == "fe80")
        return true;
    // Discard Prefix
    else if (firstWord == "100")
        return true;
    // Any other IP address is not Unique Local Address (ULA)
    return false;
}

在 F# 中:

let private IsIpv6AddressPrivate (address: IPAddress) =
    if address.AddressFamily = AddressFamily.InterNetwork then
        invalidArg "address" "address must be IPv6"
    // The original IPv6 Site Local addresses (fec0::/10) are deprecated. Unfortunately IsIPv6SiteLocal only checks for the original deprecated version:
    elif address.IsIPv6SiteLocal then
        true
    else
        let addressAsString = address.ToString()
        // equivalent of 127.0.0.1 in IPv6
        if addressAsString = "::1" then
            true
        else
            let firstWord = addressAsString.Split([|':'|], StringSplitOptions.RemoveEmptyEntries).[0]
            // These days Unique Local Addresses (ULA) are used in place of Site Local. 
            // ULA has two variants: 
            //      fc00::/8 is not defined yet, but might be used in the future for internal-use addresses that are registered in a central place (ULA Central). 
            //      fd00::/8 is in use and does not have to registered anywhere.
            if (firstWord.Length >= 4 && firstWord.Substring(0, 2) = "fc") ||
               (firstWord.Length >= 4 && firstWord.Substring(0, 2) = "fd") ||
               // Link local addresses (prefixed with fe80) are not routable
               (firstWord = "fe80") ||
               // Discard Prefix
               (firstWord = "100") then
                true
            else
                false

虽然不是特别优雅...我真的想不出更好的:)

但是,我也会检查以 fe80: 为前缀的链接本地地址。它们不可路由,但如果直接从接口拉取 IP,则当不存在其他 IPv6 地址时,它仍可能报告本地链路。

维基百科关于IPv6(https://en.wikipedia.org/wiki/Reserved_IP_addresses#IPv6(的文章也将100:显示为丢弃前缀。根据您要完成的任务,您可能还需要检查这些内容。

这是我使用的最终代码,到目前为止,它似乎按预期工作:

public static bool IsPrivateIPv6(this IPAddress address)
{
    var addressAsString = address.ToString();
    var firstWord = addressAsString.Split(new[] { ':' }, StringSplitOptions.RemoveEmptyEntries)[0];
    // Make sure we are dealing with an IPv6 address
    if (address.AddressFamily != AddressFamily.InterNetworkV6) return false;
    // The original IPv6 Site Local addresses (fec0::/10) are deprecated. Unfortunately IsIPv6SiteLocal only checks for the original deprecated version:
    else if (address.IsIPv6SiteLocal) return true;
    // These days Unique Local Addresses (ULA) are used in place of Site Local. 
    // ULA has two variants: 
    //      fc00::/8 is not defined yet, but might be used in the future for internal-use addresses that are registered in a central place (ULA Central). 
    //      fd00::/8 is in use and does not have to registered anywhere.
    else if (firstWord.Substring(0, 2) == "fc" && firstWord.Length >= 4) return true;
    else if (firstWord.Substring(0, 2) == "fd" && firstWord.Length >= 4) return true;
    // Link local addresses (prefixed with fe80) are not routable
    else if (firstWord == "fe80") return true;
    // Discard Prefix
    else if (firstWord == "100") return true;
    // Any other IP address is not Unique Local Address (ULA)
    else return false;
}

这里提供的一些答案包括检查"::1",这是本地主机的IPv6地址。

从技术上讲,本地主机不是私有 IP 地址,应单独检查。


要检查包括 IPv4 和 IPv6 地址以及可选的本地主机,您可以移植此 javascript 函数。



这应该是一个评论,但我的声誉还不够高。