【问题标题】:Finding out CIDR for a single IP (v4/v6) Address (TypeScript)找出单个 IP (v4/v6) 地址的 CIDR (TypeScript)
【发布时间】:2021-10-20 07:22:56
【问题描述】:

我正在使用 TypeScript 开发一个项目,并且可以访问基于键值的存储。要求是找到与单个 IP 相关的数据(匹配键)。

不幸的是,关键始终是覆盖大量 IP 的 CIDR(由于许多记录而节省存储空间)。在我的测试中,我无法找到属于特定 IP 的正确 CIDR。

示例数据:

"103.21.244.0/24" - "data, lorem ipsum, etc"

要查找的示例 IP:

"103.21.244.1"

我已经测试了几个库,例如:ip-addressip-numip-to-intipaddr.js 等等,但我无法得到我想要的结果。

也许我只是愚蠢并且没有正确理解IP规范,或者我只是滥用这些库,请赐教。

肯定有一种方法,无需调用外部 API(如 RIPE),也无需存储数十亿个 IP 而不是其 CIDR。

本质上,要求非常简单:“通过此 IP(v4 或 v6)找到此 KEY(在 CIDR 中)”。

我们非常感谢任何帮助、建议、示例解决方案。

【问题讨论】:

    标签: javascript node.js typescript


    【解决方案1】:

    IP 地址可以转换为单个数字。 a.b.c.d 形式是 32 位数字的 base-256 表示形式。将地址和子网掩码都转换为整数。然后使用“按位与”运算将掩码应用于目标 IP 地址并与网络地址进行比较。

    function addrToNumber(addr)
    {
      return addr.split(".").reduce((acc,cur,i)=> acc += (Number(cur) << ( (3-i) * 8) ) ,0)
    }
    
    function subnetMaskToNumber(mask)
    {
      return (0xffffffff << (32 - Number(mask))) & 0xffffffff;
    }
    
    const cidr = "103.21.244.0/24";
    const [networkAddr,subnetMask] = cidr.split("/");
    
    const ipAddr = "103.21.244.1";
    
    const match = (addrToNumber(ipAddr) & subnetMaskToNumber(subnetMask)) == addrToNumber(networkAddr)
    console.log(match);

    为一个 IP 地址生成所有可能的 CIDR:

    function addrToNumber(addr)
    {
      return addr.split(".").reduce((acc,cur,i)=> acc += (Number(cur) << ( (3-i) * 8) ) ,0)
    }
    function numberToAddr(num)
    {
      return `${(num >> 24) & 0xff}.${(num >> 16) & 0xff}.${(num >> 8) & 0xff}.${num & 0xff}`
    }
    
    const ipAddr = "103.21.244.1";
    
    const ipValue = addrToNumber(ipAddr);
    
    let possibleCIDR = [...Array(33)].map((_,i)=>{
      let mask = i == 0 ? 0 : (0xffffffff << (32 - i)) >>> 0;
      return `${numberToAddr(ipValue & mask)}/${i}`;
    });
    
    console.log(possibleCIDR);

    要为 IPv6 生成可能的 CIDR,未处理零压缩。

    const ipv6 = "2001:db8:85a3:8d3:1319:8a2e:370:7348";
    const groups = ipv6.split(":");
    let possibleCIDR = [...Array(129)].map((_,i)=>{
      let groupIndex = Math.floor(i / 16);
      let mask = (i % 16) ? (0xffff << (16 - (i % 16))) & 0xffff : 0;
      return groups.map((value,j)=>{
        return (j < groupIndex ? value : j == groupIndex ? parseInt(value,16) & mask : 0).toString(16)
      }).join(":") + `/${i}`;
    });
    console.log(possibleCIDR);

    【讨论】:

    • 我急于发表评论,尽管这很棒,但这并不能解决我的问题。我需要一些东西来为 1 个单个 IP 找到所有可能的 CIDR,因为我的存储是键:值,所以我不能通过键在其中搜索。意思是,我需要知道 IP 的 CIDR(或可能的列表)才能尝试找到正确的 CIDR。
    • @NorbertBoros 更新了答案
    • 这太完美了……正是我需要的!如果不是太麻烦的话,你能不能也给我看一些关于 IPv6 的东西?同样的事情。
    • IPv6 由 128 位组成,不适合单个数字。需要先将其分成较小的组才能使用。
    • 我可以想象...我只需要可以获得所有可能的 CIDR 的部分,因为正如我所提到的,我将进行一次 foreach 并尝试在我的数据集中找到 CIDR。如果您能提供帮助,将非常非常感激!
    猜你喜欢
    • 1970-01-01
    • 2017-08-23
    • 2015-09-21
    • 1970-01-01
    • 1970-01-01
    • 2012-11-07
    • 2021-05-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多