Определение CIDR для одного IP-адреса (v4/v6) Адрес (машинописный текст)

#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 в своем наборе данных. Был бы очень, очень признателен, если бы вы могли помочь!