如何判断IPv6地址是否私有?
How to determine if IPv6 address is private?
我试图确定给定的 IPv6 地址在 C# 中是否私有,我很想简单地在 IP 地址 class 上使用 'IsIPv6SiteLocal' 属性。但是,如本 comment 中所述,本 属性 中实现的逻辑已弃用。我运行下面的单元测试:
[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 未正确确定地址是否为本地地址。所以我需要一个替代方案。
我写了下面的扩展方法,我想知道是否有人能想到无法正确确定地址是否为 private/public 的场景。
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 日编辑:
- 确保第一个单词的长度至少为@RonMaupin 所建议的 4 个字符
- 根据@RonMaupin
的建议改进了 'else return false' 以上的评论
- 按照@KevinBurdett
的建议检查 'fe80' 前缀
- 按照@KevinBurdett
的建议检查 'Discard' 前缀
虽然不是特别优雅...我真的想不出更好的了:)
但是,我还会检查 link 个本地地址,前缀为 fe80:
。它们不可路由,但如果您直接从接口提取 IP,当不存在其他 IPv6 地址时,它仍可能报告 link 本地。
关于 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
添加一个特例并避免他的解决方案中的 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
我试图确定给定的 IPv6 地址在 C# 中是否私有,我很想简单地在 IP 地址 class 上使用 'IsIPv6SiteLocal' 属性。但是,如本 comment 中所述,本 属性 中实现的逻辑已弃用。我运行下面的单元测试:
[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 未正确确定地址是否为本地地址。所以我需要一个替代方案。
我写了下面的扩展方法,我想知道是否有人能想到无法正确确定地址是否为 private/public 的场景。
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 日编辑:
- 确保第一个单词的长度至少为@RonMaupin 所建议的 4 个字符
- 根据@RonMaupin 的建议改进了 'else return false' 以上的评论
- 按照@KevinBurdett 的建议检查 'fe80' 前缀
- 按照@KevinBurdett 的建议检查 'Discard' 前缀
虽然不是特别优雅...我真的想不出更好的了:)
但是,我还会检查 link 个本地地址,前缀为 fe80:
。它们不可路由,但如果您直接从接口提取 IP,当不存在其他 IPv6 地址时,它仍可能报告 link 本地。
关于 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
添加一个特例并避免他的解决方案中的 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