如何使用Node.js检查给定IP是否在给定IP范围内?

14

请原谅这个琐碎的问题。

给定一组IP,该集合非常大,可能会增加 https://github.com/client9/ipcat/blob/master/datacenters.csv#L4

小例子集-第一列开始IP第二列结束IP范围

enter image description here

我将从请求中获取用户IP。 我需要检查IP是否在这些范围内。 我该如何实现。

我已经研究了ip_range_checkrange_check

但它们不会检查给定范围内的IP。 如何在node js中以最高性能实现此目标。 我不想进行详尽的搜索,因为性能是很重要的。

请帮助我解决这个全新的并且迄今为止相当具有挑战性的问题。


这可能不是最优的方式。但我建议你将IP范围转换为CIDR,然后使用ip_range_check来检查一个IP是否属于该CIDR。我相信你可以使用rangecalc来将范围转换为CIDR。 - Deja
@Deja 一个小例子会非常感激。谢谢。 - INFOSYS
3个回答

32

如果我们将IP地址转换为简单数字,这将变得非常容易:

function IPtoNum(ip){
  return Number(
    ip.split(".")
      .map(d => ("000"+d).substr(-3) )
      .join("")
  );
}

那么我们可以检查一定范围,如下:

Then we can check a certain range as:

 if( IPtoNum(min) < IPtoNum(val) &&    IPtoNum(max) > IPtoNum(val) ) alert("in range");

这也可以应用到表格中:

const ranges = [
  ["..41", "192.168.45"],
  ["123.124.125"," 126.124.123"]
];

const ip = "125.12.125";
const inRange = ranges.some(
  ([min,max]) => IPtoNum(min) < IPtoNum(ip) &&   IPtoNum(max) > IPtoNum(ip)
);

@infosys 你可以通过将表格从ips转换为数字来进行优化(我认为进一步的优化需要大量的内存消耗)。另外,看看 布隆过滤器,它们可能能够实现你想要的功能。 - Jonas Wilms
@infosys 不客气 ;) ,正如我所说,如果您使用大表进行查找(例如,每个IP地址都存储为布尔值),那么您将消耗巨大的内存,但速度非常快。 Bloom过滤器可以用更小的内存完成相同的任务,但会失去一些精度。 - Jonas Wilms
我研究了布隆过滤器,它就像Java中的哈希表。但是如何插入IP范围并获取IP范围,这可能是另一个让我困惑的问题。或者如何使用最小值和最大值搜索布隆过滤器? - INFOSYS
1
@dmitrizzle 是的。最初的问题是关于IPv4列表的,显然这个问题在过去五年中变得有些流行。这个答案从来没有意味着要持续下去。 - Jonas Wilms
1
与此同时,pyBlob已经写下了我今天为这个问题所写的答案。 - Jonas Wilms
显示剩余5条评论

9
//Use getCIDR from rangecalc
getCIDR("5.9.0.0", "5.9.255.255")
//This return 5.9.0.0/16

//You can then use ipRangeCheck from ip_range_check
ipRangeCheck("IP TO BE CHECKED", "5.9.0.0/16")
//returns true or false

我相信还有其他方法可以做到这一点。


这个方案可以行得通,但是它会非常耗费资源,就像蛮力算法一样。考虑到我们有大量的 IP 范围,更高效的解决方案会更好,你不觉得吗?尽管如此,这仍然是一个解决方案。 - INFOSYS
这可能会有帮助 iptrie - Deja
关于Tries的快速提醒:它们在内存方面不太好。因此,您正在以内存换取性能。 - Alexander Santos

9

从 Node.js v15 开始,我们也可以使用原生的 net 包中的 BlockList

https://nodejs.org/api/net.html#class-netblocklist

我们可以创建 BlockList 对象,并从表格中填充相关条目:

import { BlockList } from "net"

const blockList = new BlockList()
blockList.addAddress("123.123.123.123")
blockList.addRange("10.0.0.1", "10.0.0.10")
blockList.addSubnet("8592:757c:efae:4e45::", 64, "ipv6")

并测试列表是否与各个地址匹配:

console.log(blockList.check('123.123.123.123'));  // Prints: true
console.log(blockList.check('10.0.0.3'));  // Prints: true
console.log(blockList.check('222.111.111.222'));  // Prints: false

// IPv6 notation for IPv4 addresses works:
console.log(blockList.check('::ffff:7b7b:7b7b', 'ipv6')); // Prints: true
console.log(blockList.check('::ffff:123.123.123.123', 'ipv6')); // Prints: true

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接