JavaScript: Является ли IP в одном из этих подсетей?
Итак, у меня есть ~ 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
Ответы
Ответ 1
Лучший подход - использование ИМО побитовых операторов. Например, 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 для маски.
Ответ 2
Попробуйте следующее:
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
Ответ 3
Преобразуйте нижний ip и верхний ip в диапазоне в целые числа и сохраните диапазон в db, затем убедитесь, что оба столбца проиндексированы.
Сверху моей головы (псевдокод):
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
Оптимизатор запросов должен иметь возможность значительно ускорить это.
Ответ 4
Мне удалось решить эту проблему, используя модуль 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
Ответ 5
Функции IPnumber
и IPmask
хороши, однако я бы скорее протестировал, например:
(IPnumber('123.123.49.123') & IPmask('22')) == (IPnumber('123.123.48.0') & IPmask('22'))
Потому что для каждого адреса вам нужно только учитывать сетевую часть адреса. Следовательно, при выполнении IPmask('22')
будет отключена компьютерная часть адреса, и вы должны сделать то же самое с сетевым адресом.