sqlite 如何检查IP是否在其中一个子网中

iqxoj9l9  于 2023-04-06  发布在  SQLite
关注(0)|答案(6)|浏览(176)

我有~12600个子网:
例如:123.123.208.0/20
一个IP。
我可以使用SQLite数据库或数组等
大约一个月前有一个类似的问题,但我不是在寻找检查一个IP对一个子网,而是一堆子网(显然是最有效的方式,希望不是O(总子网)):)
我如何检查IP是在这些子网之一,我需要真或假,而不是子网,如果这有助于优化。
当前列表中有类似的子网,例如:(实际浸提液)

123.123.48.0/22 <-- not a typo
123.123.48.0/24 <-- not a typo
123.123.90.0/24
123.123.91.0/24
123.123.217.0/24

它们的总范围为4.x.y.z至222.x.y.z

xj3cbfub

xj3cbfub1#

最好的方法是使用位运算符的IMO。例如,123.123.48.0/22表示(123<<24)+(123<<16)+(48<<8)+0(=2071670784;这可能是一个负数)作为一个32位数字IP地址,-1<<(32-22) = -1024作为一个掩码。用这个,同样,你的测试IP地址转换为一个数字,你可以做:

(inputIP & testMask) == testIP

例如,123.123.49.123就在该范围内,因为2071671163 & -1024是2071670784
下面是一些工具函数:

function IPnumber(IPaddress) {
    var ip = IPaddress.match(/^(\d+)\.(\d+)\.(\d+)\.(\d+)$/);
    if(ip) {
        return (+ip[1]<<24) + (+ip[2]<<16) + (+ip[3]<<8) + (+ip[4]);
    }
    // else ... ?
    return null;
}

function IPmask(maskSize) {
    return -1<<(32-maskSize)
}

测试:

(IPnumber('123.123.49.123') & IPmask('22')) == IPnumber('123.123.48.0')

得到true
如果您的掩码格式为'255.255.252.0',则您也可以使用掩码的IPnumber函数。

fd3cxomn

fd3cxomn2#

试试这个:

var ip2long = function(ip){
    var components;

    if(components = ip.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/))
    {
        var iplong = 0;
        var power  = 1;
        for(var i=4; i>=1; i-=1)
        {
            iplong += power * parseInt(components[i]);
            power  *= 256;
        }
        return iplong;
    }
    else return -1;
};

var inSubNet = function(ip, subnet)
{   
    var mask, base_ip, long_ip = ip2long(ip);
    if( (mask = subnet.match(/^(.*?)\/(\d{1,2})$/)) && ((base_ip=ip2long(mask[1])) >= 0) )
    {
        var freedom = Math.pow(2, 32 - parseInt(mask[2]));
        return (long_ip > base_ip) && (long_ip < base_ip + freedom - 1);
    }
    else return false;
};

使用方法:

inSubNet('192.30.252.63', '192.30.252.0/22') => true
inSubNet('192.31.252.63', '192.30.252.0/22') => false
pgpifvop

pgpifvop3#

我通过使用node netmask模块成功解决了这个问题。您可以通过如下方式检查IP是否属于子网:

import { Netmask } from 'netmask'

const block = new Netmask('123.123.208.0/20')
const ip = '123.123.208.0'
console.log(block.contains(ip))

将在这里打印true
您可以使用以下命令安装它:

npm i --save netmask
ct2axkht

ct2axkht4#

将范围中的低ip和高ip转换为整数,并将范围存储在数据库中,然后确保两列都被索引。
Off the top of my head(伪代码):

function ipmap(w,x,y,z) {
  return 16777216*w + 65536*x + 256*y + z;
}

var masks = array[ipmap(128,0,0,0), ipmap(196,0,0,0), ..., ipmap(255,255,255,255)]

function lowrange(w, x, y, z, rangelength) {
  return ipmap(w, x, y, z) & masks[rangelength]
}

function hirange(w, x, y, z, rangelength) {
  return lowrange(w, x, y, z, ,rangelength) + ipmap(255,255,255,255) - masks[rangelength];
}

应该可以了
要查找特定ip是否福尔斯任何范围,请将其转换为整数并执行以下操作:

SELECT COUNT(*) FROM ipranges WHERE lowrange <= 1234567 AND 1234567 <= highrange

查询优化器应该能够大大加快这一过程。

j1dl9f46

j1dl9f465#

函数IPnumberIPmask很好,但是我更愿意像这样测试:

(IPnumber('123.123.49.123') & IPmask('22')) == (IPnumber('123.123.48.0')  & IPmask('22'))

因为对于每个地址,您只需要考虑地址的网络部分。因此执行IPmask('22')将清零地址的计算机部分,您应该对网络地址执行相同的操作。

icnyk63a

icnyk63a6#

关键词:二分查找、预处理、排序

我也遇到过类似的问题,如果你能对子网列表进行预处理并排序,那么二分查找似乎非常有效。然后你可以实现**O(log n)**的渐近时间复杂度。
下面是我的代码(MIT许可证,原始位置:https://github.com/iBug/pac/blob/854289a674578d096f60241804f5893a3fa17523/code.js):

function belongsToSubnet(host, list) {
  var ip = host.split(".").map(Number);
  ip = 0x1000000 * ip[0] + 0x10000 * ip[1] + 0x100 * ip[2] + ip[3];

  if (ip < list[0][0])
    return false;

  // Binary search
  var x = 0, y = list.length, middle;
  while (y - x > 1) {
    middle = Math.floor((x + y) / 2);
    if (list[middle][0] < ip)
      x = middle;
    else
      y = middle;
  }

  // Match
  var masked = ip & list[x][1];
  return (masked ^ list[x][0]) == 0;
}

以及示例用法:

function isLan(host) {
  return belongsToSubnet(host, LAN);
}

var LAN = [
  [0x0A000000, 0xFF000000], // 10.0.0.0/8
  [0x64400000, 0xFFC00000], // 100.64.0.0/10
  [0x7F000000, 0xFF000000], // 127.0.0.0/8
  [0xA9FE0000, 0xFFFF0000], // 169.254.0.0/16
  [0xAC100000, 0xFFF00000], // 172.16.0.0/12
  [0xC0A80000, 0xFFFF0000]  // 192.168.0.0/16
];
isLan("127.12.34.56"); // => true
isLan("8.8.8.8"); // => false (Google's Public DNS)

你可以get a PAC script*,看看它是如何执行的(它从其他地方加载中国IP列表,对它们进行排序并适当地格式化)对5000个子网。在实践中,它的速度令人惊讶地令人满意。
预处理代码可以使用上面页面上的F12 Dev Tools进行检查。简而言之,您需要将1.2.3.4/16转换为[0x01020304, 0xFFFF0000],即IP地址和网络掩码的32位无符号整数。

  • 链接到我的个人网站。

相关问题