一年前,我不得不通过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?
答案 0 :(得分:1)
由于您可以将任何IPv6地址表示为128位数字,因此您的问题将减少为对128位数字执行二进制搜索。
现在JS没有能力本地处理128位数字。所以你可以使用BigInteger JS库;例如,快速谷歌搜索会出现big-integer。
但是,这可能对您的应用程序来说太过分了。您可以简单地将数字表示为四个32位数字的元组。对于二进制搜索算法,您只需要实现一个函数来比较以这种格式编写的两个数字。这可以通过简单的词典比较来完成。