JavaScript: IP находится в одной из этих подсетей? - PullRequest
16 голосов
/ 02 февраля 2009

Итак, у меня ~ 12600 подсетей:

например. 123.123.208.0/20

и IP.

Я могу использовать базу данных SQLite или массив или что-то еще

Был подобный вопрос, заданный около месяца назад, однако я не ищу проверку одного IP для одной подсети, а для группы подсетей (очевидно, самый эффективный способ, надеюсь, не O (всего подсетей)):)

Как я могу проверить, является ли IP-адрес одним из этих подсетей, мне нужно true или false, а не подсеть, если это помогает оптимизации.

В текущем списке есть похожие подсети, например: (фактическая выписка)

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

Ответы [ 5 ]

23 голосов
/ 02 февраля 2009

Наилучшим подходом является 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 и для маски.

7 голосов
/ 01 августа 2013

Попробуйте это:

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
2 голосов
/ 25 сентября 2015

Мне удалось решить эту проблему с помощью модуля netmask node . Вы можете проверить, принадлежит ли 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
2 голосов
/ 02 февраля 2009

Преобразуйте нижний ip и верхний ip в диапазоне в целые числа и сохраните диапазон в БД, затем убедитесь, что оба столбца проиндексированы.

С макушки головы (псевдокод):

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

Оптимизатор запросов должен иметь возможность значительно ускорить это.

1 голос
/ 21 марта 2017

Функции IPnumber и IPmask хороши, однако я бы предпочел проверить как:

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

Потому что для каждого адреса нужно учитывать только сетевую часть адреса. Следовательно, выполнение IPmask('22') обнулит компьютерную часть адреса, и вы должны сделать то же самое с сетевым адресом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...