二进制搜索IPv6地址?

时间:2015-05-19 10:35:27

标签: javascript node.js ipv6

一年前,我不得不通过IPv4地址范围实现二进制搜索,以作为优化的HTTP请求过滤器,以应对可能的DOS攻击。

今天我需要重新实现它以使用IPv6,但由于如何转换和比较地址有很多不同,这似乎是一个相当大的挑战。我试图找到一个现有的解决方案,但没有太多运气。充其量,我可以找到简单的IPv6实用程序来解析地址并进行非常基本的操作,而无需为优化搜索提供太多条件。例如,此库:whitequark/ipaddr.js

我旧解决方案的关键方法是依靠地址的整数表示,使用以下转换:

function intFromIPv4(ip){
    var octets = ip.split(".");
     return octets[0] * 16777216 + octets[1] * 65536 + octets[2] * 256 + octets[3] * 1;
}

然后我可以合并/对齐IP范围,以便可以进行简单的二进制搜索。

这就是我写的那篇课程:

function IPv4Checker() {

    this.ipList = [];

    // takes array of [{f,l}] integers and returns its merged-range version as [{first, last}];
    // works only if:
    // a) the array is ordered by 'f' in ascending order.
    // b) 'f' is always defined, while 'l' is either undefined or not less than 'f'.
    this.mergeRanges = function (data) {
        var ips = [];
        if (data.length > 0) {
            var start = data[0].f;
            var end = data[0].l || start;
            for (var i = 1; i < data.length; i++) {
                if (data[i].f > end + 1) {
                    var d = {first: start};
                    if (end > start) {
                        d.last = end;
                    }
                    ips.push(d);
                    start = data[i].f;
                }
                var v = data[i].l || data[i].f;
                end = v > end ? v : end;
            }
            var d = {first: start};
            if (end > start) {
                d.last = end;
            }
            ips.push(d);
        }
        return ips;
    };

    // Calculates IP address against the current list,
    // using binary / logarithmic search algorithm.
    // It relies on the list of IP-s that is ordered by
    // 'first' in ascending order, and then with all the
    // range overlaps merged.
    this.isValid = function (ip) {
        if (ip === '127.0.0.1') {
            return true; // no checks for the local IP;
        }
        var addr = intFromIPv4(ip);
        var low = 0;
        var high = this.ipList.length - 1;
        var mid;
        while (low <= high) {
            mid = Math.round((low + high) / 2);
            var a = this.ipList[mid];
            if (addr > a.first) {
                if (a.last && addr <= a.last) {
                    return true;
                }
                low = mid + 1;
            } else {
                if (addr < a.first) {
                    high = mid - 1;
                } else {
                    return true;
                }
            }
        }
        return false;
    };
}

创建支持范围的优化IPv6过滤器的正确方法是什么,以实现类似的快速搜索结果?

在一天结束时,我只需要一个可以快速使用2-3个IPv6范围或2000-3000个IPv6范围的IPv6过滤器。那是因为我需要在每个HTTP请求中使用它,所以使用非二进制搜索并不是一个真正的选择。

如果有人能指出我可能错过的现有解决方案,那也很棒。

更新

虽然我接受了答案,但真正的帮助是答案:IPv6 as a comparable JavaScript string?

1 个答案:

答案 0 :(得分:1)

由于您可以将任何IPv6地址表示为128位数字,因此您的问题将减少为对128位数字执行二进制搜索。

现在JS没有能力本地处理128位数字。所以你可以使用BigInteger JS库;例如,快速谷歌搜索会出现big-integer

但是,这可能对您的应用程序来说太过分了。您可以简单地将数字表示为四个32位数字的元组。对于二进制搜索算法,您只需要实现一个函数来比较以这种格式编写的两个数字。这可以通过简单的词典比较来完成。