问题
I am trying to determine if an IP address is routable. For example, if I receive 127.0.0.1, I know that this is loopback(ie: localhost). I wasn't able to find a function for this in .NET or any other language, so I have started writing my own which is far from complete.
Before I spend lots of time writing this function, does anyone know if a function that determines if a ip address is non-routable exist? I would prefer a .NET solution, but beggers cant be choosers and I'll happily convert any solution.
EDIT: Answered my question with a function.
回答1:
I have answered my own question by creating a function that checks if an ip address (ipv4 or ipv6) is a non-routable ip address. I have referenced the wiki article from McKay's post to find alot of reserved ip addresses (http://en.wikipedia.org/wiki/Reserved_IP_addresses)
Solution:
/// <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;
}
回答2:
There is no other solution that I can find, but you basically have it down: it would be better to check the bytes (get the IP as a byte[4]) than as a string, but there's little more to it. Just remember that class B is 172.16.0.0/12; again, it's easier to check this with a byte value, as you can use a bit mask for the first four bits of the second byte.
回答3:
Whether or not something is "routable" is going to be based on local implementation. Under some cases (like based on the current subnet mask) certain addresses are routable, when others aren't.
First, I'd recommend using the System.Net.IPAddress class:
http://msdn.microsoft.com/en-us/library/system.net.ipaddress.aspx
Also, look at the Reserved IP article in wikipedia.
http://en.wikipedia.org/wiki/Reserved_IP_addresses
来源:https://stackoverflow.com/questions/8230728/is-there-a-function-that-can-take-an-ipaddress-as-string-and-tell-me-if-its-a-no