Math 优化匹配IP范围的简单算法

Math 优化匹配IP范围的简单算法,math,ip,Math,Ip,我想检查IP地址是否在特定范围内,仅通过“*”匹配。例如,“202.121.189.8”在“202.121.189.*”中 场景是我有一个被禁止IP的列表,其中一些包含“*”,因此我编写了一个函数,到目前为止效果良好: static bool IsInRange(string ip, List<string> ipList) { if (ipList.Contains(ip)) { return true; } var ipSets

我想检查IP地址是否在特定范围内,仅通过
“*”
匹配。例如,“202.121.189.8”在“202.121.189.
*
”中

场景是我有一个被禁止IP的列表,其中一些包含
“*”
,因此我编写了一个函数,到目前为止效果良好:

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;
}
静态布尔IsInRange(字符串ip,列表ipList)
{
if(ipList.Contains(ip))
{
返回true;
}
var ipSets=ip.分割('.');
foreach(ipList中的变量项)
{
var itemSets=item.Split('.');
对于(int i=0;i<4;i++)
{
如果(项集[i]=“*”)
{
bool-isMatch=true;
对于(int j=0;j
测试代码:

string ip = "202.121.189.8";
List<string> ipList = new List<string>() { "202.121.168.25", "202.121.189.*" };

Console.WriteLine(IsInRange(ip, ipList));
string ip=“202.121.189.8”;
List ipList=新列表(){“202.121.168.25”,“202.121.189.*.”;
控制台写入线(IsInRange(ip,ipList));

但是我觉得我写的东西很愚蠢,我想优化它,有人知道如何简化这个函数吗?不要使用太多的“for…if…”。

一个好主意是以一对的形式表示被禁止的子网:掩码+基址。因此,您的支票将如下所示:

banned = (ip & mask == baseaddress & mask);
int numip = ip2int(ip);
bool isIpBanned = banList.Any(item =>
            numip & item.mask == item.baseaddress & item.mask);
对于11.22.33.*基址将是
11*0x1000000+22*0x10000+33*0x100
,掩码将是0xFFFF00

对于单个地址55.44.33.22,地址将为
55*0x1000000+44*0x10000*33*0x100+22
,掩码将为0xFFFFFF

您需要将地址转换为32位整数,这是一个单独的过程

在此之后,您的代码将如下所示:

banned = (ip & mask == baseaddress & mask);
int numip = ip2int(ip);
bool isIpBanned = banList.Any(item =>
            numip & item.mask == item.baseaddress & item.mask);
顺便说一句,通过这种方式,您将能够在较小的子集上表示甚至禁止

int ip2int(string ip) // error checking omitted
{
    var parts = ip.Split('.');
    int result = 0;
    foreach (var p in parts)
        result = result * 0x100 + int.Parse(p);
}


class BanItem { public int baseaddres; public int mask; }

BanItem ip2banItem(string ip)
{
    BanItem bi = new BanItem() { baseaddres = 0, mask = 0 };
    var parts = ip.Split('.');
    foreach (var p in parts)
    {
        bi.baseaddress *= 0x100;
        bi.mask *= 0x100;
        if (p != "*")
        {
            bi.mask += 0xff;
            bi.baseaddress += int.Parse(p);
        }
    }
    return bi;
}

banList = banIps.Select(ip2banItem).ToList();

我认为你应该为带*的IP和不带星号的IP保留一个单独的列表

假设IpList1包含不带* 及

IpList2——包含*。实际上,我们将存储的是此列表中*之前的部分。例如,对于202.121.189。*将仅存储为202.121.189

因此,对于一个给定的IP地址,您只需要在IpList1中检查该IP地址,如果在那里找不到该地址的话 对于IPList 2中的每个Ip,您需要检查它是否是输入Ip的子字符串

因此不需要复杂的for和if循环。

用Java编写(未测试):

静态布尔值IsInRange(字符串ip,向量ipList){
int indexOfStar=0;

对于(int i=0;i我会使用一个空间填充曲线,如xkcd漫画中所示:。它是函数H(x,y)=(H(x),H(y)),它将2维压缩为1维。这也表明你是一个真正的b***编码器