我试图确定给定的 IPv6 地址在 C# 中是否是私有的,并且我很想简单地使用 IPAddress 类上的“IsIPv6SiteLocal”属性。然而,正如本节中所解释的comment https://stackoverflow.com/questions/6459928/explain-the-instance-properties-of-system-net-ipaddress/6461537#6461537,此属性中实现的逻辑已被弃用。我运行了以下单元测试:
[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;
}
2016 年 2 月 13 日编辑:
- 确保第一个单词的长度至少为 4 个字符(按照@RonMaupin 的建议)
- 按照 @RonMaupin 的建议改进了“else return false”上面的评论
- 检查 @KevinBurdett 建议的“fe80”前缀
- 按照 @KevinBurdett 的建议检查“丢弃”前缀
通过添加特殊情况改进了 @desautelsj 的答案::1
并避免他的解决方案中出现 ArgumentException (这会发生在Substring()
call):
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
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)