I want to check if an IP address is in a certain range, matching by "*" only. For example, “202.121.189.8” is in “202.121.189.*“.
The scenario is that I have a list of banned IPs, some of them contains "*", so I wrote a function, it works fine so far:
static bool IsInRange(string ip, List<string> ipList)
{
if (ipList.Contains(ip))
{
return true;
}
var ipSets = ip.Split('.');
foreach (var item in ipList)
{
var itemSets = item.Split('.');
for (int i = 0; i < 4; i++)
{
if (itemSets[i] == "*")
{
bool isMatch = true;
for (int j = 0; j < i; j++)
{
if (ipSets[i - j - 1] != itemSets[i - j - 1])
{
isMatch = false;
}
}
if (isMatch)
{
return true;
}
}
}
}
return false;
}
Test code:
string ip = "202.121.189.8";
List<string> ipList = new List<string>() { "202.121.168.25", "202.121.189.*" };
Console.WriteLine(IsInRange(ip, ipList));
But I think what i wrote is very stupid, and I want to optimize it, does anyone have an idea how to simplify this function? not to use so many “for….if…”.
A good idea would be to represent the banned subnets in a form of a pair: mask + base address. So your check will look like that:
For 11.22.33.* the base address will be
11*0x1000000 + 22*0x10000 + 33*0x100, mask will be 0xffffff00.For single address 55.44.33.22 the address will be
55*0x1000000 + 44*0x10000 * 33*0x100 + 22, mask will be 0xffffffff.You’ll need to convert the address to a 32-bit int as a separate procedure.
After that all, your code will look like that:
By the way, this way you’ll be able to represent even bans on smaller subsets.