#javascript #node.js #typescript
Вопрос:
Я работаю над проектом с использованием машинописного текста и имею доступ к хранилищу на основе значений ключей. Требование состоит в том, чтобы найти данные, относящиеся к одному IP-адресу (ключ соответствия).
К сожалению, ключом всегда является CIDR, охватывающий множество IP-адресов (для экономии памяти из-за большого количества записей). Во время моих тестов я не смог найти правильный CIDR, принадлежащий определенному IP-адресу.
Примеры данных:
"103.21.244.0/24" - "data, lorem ipsum, etc"
Пример IP-адреса для поиска:
"103.21.244.1"
Я протестировал несколько библиотек, таких как: ip-адрес, ip-номер, ip-to-int, ipaddr.js и многое другое, но я не могу получить желаемый результат.
Может быть, я просто глуп и неправильно понимаю спецификацию IP, или, может быть, я просто злоупотребляю этими библиотеками, пожалуйста, просветите меня.
Конечно, должен быть способ без вызова внешних API (например, RIPE) и без необходимости хранить миллиарды IP-адресов вместо их CIDR.
По сути, требование довольно простое: «найдите этот КЛЮЧ (в CIDR) по этому IP (v4 или v6)».
Любая помощь, советы, примеры решений высоко ценятся.
Ответ №1:
IP-адрес может быть преобразован в один номер. a.b.c.d
Форма представляет собой простое представление 32-разрядного числа на основе 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))) amp; 0xffffffff;
}
const cidr = "103.21.244.0/24";
const [networkAddr,subnetMask] = cidr.split("/");
const ipAddr = "103.21.244.1";
const match = (addrToNumber(ipAddr) amp; subnetMaskToNumber(subnetMask)) == addrToNumber(networkAddr)
console.log(match);
Чтобы сгенерировать все возможные CIDR для IP-адреса:
function addrToNumber(addr)
{
return addr.split(".").reduce((acc,cur,i)=> acc = (Number(cur) << ( (3-i) * 8) ) ,0)
}
function numberToAddr(num)
{
return `${(num >> 24) amp; 0xff}.${(num >> 16) amp; 0xff}.${(num >> 8) amp; 0xff}.${num amp; 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 amp; mask)}/${i}`;
});
console.log(possibleCIDR);
Для создания возможного CIDR для IPv6 сжатие нулей не обрабатывается.
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))) amp; 0xffff : 0;
return groups.map((value,j)=>{
return (j < groupIndex ? value : j == groupIndex ? parseInt(value,16) amp; mask : 0).toString(16)
}).join(":") `/${i}`;
});
console.log(possibleCIDR);
Комментарии:
1. Я поспешил прокомментировать, хотя это здорово, это не решает мою проблему. Мне нужно что-то, чтобы найти все возможные CIDR для 1 одного IP-адреса, потому что мое хранилище-это ключ:значение, поэтому я не могу искать внутри него только по ключу. Это означает, что мне нужно знать CIDR IP-адреса (или возможный список из них), чтобы попытаться найти правильный.
2. @NorbertBoros обновил ответ
3. Это идеально… именно то, что мне было нужно! Если это не слишком затруднит, не могли бы вы, пожалуйста, показать мне что-нибудь и для IPv6, пожалуйста? То же самое.
4. IPv6 состоит из 128 бит и не помещается в один номер. Сначала нужно разделить его на более мелкие группы для работы.
5. Я могу себе представить… Мне нужна только та часть, где я могу получить все возможные CIDR, потому что, как я уже упоминал, я буду выполнять предварительную проверку и попытаюсь найти CIDR в своем наборе данных. Был бы очень, очень признателен, если бы вы могли помочь!