是否有一个函数可以将 ipAddress 作为字符串并告诉我它是否是不可路由的 IP 地址?
Posted
技术标签:
【中文标题】是否有一个函数可以将 ipAddress 作为字符串并告诉我它是否是不可路由的 IP 地址?【英文标题】:Is there a function that can take an ipAddress as string and tell me if its a non-routable IP address? 【发布时间】:2012-01-04 01:38:41 【问题描述】:我正在尝试确定 IP 地址是否可路由。例如,如果我收到 127.0.0.1,我知道这是环回(即:localhost)。我无法在 .NET 或任何其他语言中找到此功能,因此我开始编写自己的功能,但还远未完成。
在我花很多时间写这个函数之前,有没有人知道是否有一个函数可以确定一个 ip 地址是否不可路由?我更喜欢 .NET 解决方案,但乞丐不能成为选择者,我很乐意转换任何解决方案。
编辑:用函数回答了我的问题。
【问题讨论】:
另外,由于 IPv6 快到了,你也应该考虑一下;) 不应该把 176. 改为 172. 吗? 你是对的。感谢您指出这一点。 【参考方案1】:我通过创建一个检查 IP 地址(ipv4 或 ipv6)是否为不可路由的 IP 地址的函数来回答我自己的问题。我参考了 McKay 帖子中的 wiki 文章,找到了很多保留的 IP 地址 (http://en.wikipedia.org/wiki/Reserved_IP_addresses)
解决方案:
/// <summary>
///
/// </summary>
/// <param name="ipAddress"></param>
/// <remarks>A null or empty string passed as the ipAddress will return true. An invalid ipAddress will be returned as true. </remarks>
/// <returns></returns>
public static bool IsNonRoutableIpAddress(string ipAddress)
//Reference: http://en.wikipedia.org/wiki/Reserved_IP_addresses
//if the ip address string is empty or null string, we consider it to be non-routable
if (String.IsNullOrEmpty(ipAddress))
return true;
//if we cannot parse the Ipaddress, then we consider it non-routable
IPAddress tempIpAddress = null;
if (!IPAddress.TryParse(ipAddress, out tempIpAddress))
return true;
byte[] ipAddressBytes = tempIpAddress.GetAddressBytes();
//if ipAddress is IPv4
if (tempIpAddress.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
if (IsIpAddressInRange(ipAddressBytes, "10.0.0.0/8")) //Class A Private network check
return true;
else if (IsIpAddressInRange(ipAddressBytes, "172.16.0.0/12")) //Class B private network check
return true;
else if (IsIpAddressInRange(ipAddressBytes, "192.168.0.0/16")) //Class C private network check
return true;
else if (IsIpAddressInRange(ipAddressBytes, "127.0.0.0/8")) //Loopback
return true;
else if (IsIpAddressInRange(ipAddressBytes, "0.0.0.0/8")) //reserved for broadcast messages
return true;
//its routable if its ipv4 and meets none of the criteria
return false;
//if ipAddress is IPv6
else if (tempIpAddress.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6)
//incomplete
if (IsIpAddressInRange(ipAddressBytes, "::/128")) //Unspecified address
return true;
else if (IsIpAddressInRange(ipAddressBytes, "::1/128")) //lookback address for localhost
return true;
else if (IsIpAddressInRange(ipAddressBytes, "2001:db8::/32")) //Addresses used in documentation
return true;
return false;
else
//we default to non-routable if its not Ipv4 or Ipv6
return true;
/// <summary>
///
/// </summary>
/// <param name="ipAddressBytes"></param>
/// <param name="reservedIpAddress"></param>
/// <returns></returns>
private static bool IsIpAddressInRange(byte[] ipAddressBytes, string reservedIpAddress)
if (String.IsNullOrEmpty(reservedIpAddress))
return false;
if (ipAddressBytes == null)
return false;
//Split the reserved ip address into a bitmask and ip address
string[] ipAddressSplit = reservedIpAddress.Split(new char[] '/' , StringSplitOptions.RemoveEmptyEntries);
if (ipAddressSplit.Length != 2)
return false;
string ipAddressRange = ipAddressSplit[0];
IPAddress ipAddress = null;
if (!IPAddress.TryParse(ipAddressRange, out ipAddress))
return false;
// Convert the IP address to bytes.
byte[] ipBytes = ipAddress.GetAddressBytes();
//parse the bits
int bits = 0;
if (!int.TryParse(ipAddressSplit[1], out bits))
bits = 0;
// BitConverter gives bytes in opposite order to GetAddressBytes().
byte[] maskBytes = null;
if (ipAddress.AddressFamily == AddressFamily.InterNetwork)
uint mask = ~(uint.MaxValue >> bits);
maskBytes = BitConverter.GetBytes(mask).Reverse().ToArray();
else if (ipAddress.AddressFamily == AddressFamily.InterNetworkV6)
//128 places
BitArray bitArray = new BitArray(128, false);
//shift <bits> times to the right
ShiftRight(bitArray, bits, true);
//turn into byte array
maskBytes = ConvertToByteArray(bitArray).Reverse().ToArray();
bool result = true;
//Calculate
for (int i = 0; i < ipBytes.Length; i++)
result &= (byte)(ipAddressBytes[i] & maskBytes[i]) == ipBytes[i];
return result;
/// <summary>
///
/// </summary>
/// <param name="bitArray"></param>
/// <param name="shiftN"></param>
/// <param name="fillValue"></param>
private static void ShiftRight(BitArray bitArray, int shiftN, bool fillValue)
for (int i = shiftN; i < bitArray.Count; i++)
bitArray[i - shiftN] = bitArray[i];
//fill the shifted bits as false
for (int index = bitArray.Count - shiftN; index < bitArray.Count; index++)
bitArray[index] = fillValue;
/// <summary>
///
/// </summary>
/// <param name="bitArray"></param>
/// <returns></returns>
private static byte[] ConvertToByteArray(BitArray bitArray)
// pack (in this case, using the first bool as the lsb - if you want
// the first bool as the msb, reverse things ;-p)
int bytes = (bitArray.Length + 7) / 8;
byte[] arr2 = new byte[bytes];
int bitIndex = 0;
int byteIndex = 0;
for (int i = 0; i < bitArray.Length; i++)
if (bitArray[i])
arr2[byteIndex] |= (byte)(1 << bitIndex);
bitIndex++;
if (bitIndex == 8)
bitIndex = 0;
byteIndex++;
return arr2;
【讨论】:
我错过了什么吗? “方法 'Reverse' 没有重载需要 0 个参数”。【参考方案2】:某事是否“可路由”将基于本地实现。在某些情况下(例如基于当前子网掩码),某些地址是可路由的,而其他地址则不能。
首先,我建议使用 System.Net.IPAddress 类:
http://msdn.microsoft.com/en-us/library/system.net.ipaddress.aspx
另外,请查看***中的保留 IP 文章。
http://en.wikipedia.org/wiki/Reserved_IP_addresses
【讨论】:
【参考方案3】:我找不到其他解决方案,但你基本上已经把它记下来了:检查字节(将 IP 作为字节 [4] 获取)比作为字符串更好,但它没有更多的东西. 请记住,B 类是 172.16.0.0/12;同样,使用字节值更容易检查,因为您可以对第二个字节的前四位使用位掩码。
【讨论】:
以上是关于是否有一个函数可以将 ipAddress 作为字符串并告诉我它是否是不可路由的 IP 地址?的主要内容,如果未能解决你的问题,请参考以下文章
如何将字符串转换为 System.Net.IPAddress