0

我想检查一个 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;
}

测试代码:

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

Console.WriteLine(IsInRange(ip, ipList));

但是我认为我写的很愚蠢,我想优化它,有没有人知道如何简化这个功能?不要使用这么多“for....if...”。

4

4 回答 4

1

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

banned = (ip & mask == baseaddress & mask);

对于 11.22.33.*,基地址为11*0x1000000 + 22*0x10000 + 33*0x100,掩码为 0xffffff00。

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

您需要将地址转换为 32 位 int 作为单独的过程。

毕竟,您的代码将如下所示:

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();
于 2012-07-23T12:32:43.710 回答
1

我认为您应该为带有 * 和没有星号的 IP 保留一个单独的列表。

说 IpList1 包含没有 * 的 IP 和

IpList2 --那些包含 * ..实际上我们将存储的是此列表中 .* 之前的部分。例如 202.121.189.* 将仅存储为 202.121.189..

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

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

于 2012-07-23T12:39:51.430 回答
0

我会使用 xkcd 漫画中的空间填充曲线:http: //xkcd.com/195/。它是函数 H(x,y) = (H(x),H(y)) ,它将二维减少为一维。这也表明你是一个真正的 b*** 编码器。

于 2012-07-23T12:55:17.977 回答
0

用 Java 编写(未经测试):

static boolean IsInRange(String ip, Vector<String> ipList) {
    int indexOfStar = 0;
    for (int i=0; i<ipList.size(); i++) {
        if (ipList.contains("*")) {
            indexOfStar = ipList.indexOf("*");
            if ((ip.substring(0, indexOfStar)).equals(ipList.get(i).substring(0, indexOfStar))) {
                return true;
            }
        }
    }
    return false;
}
于 2012-07-23T12:44:31.983 回答