Finding out CIDR for a single IP (v4/v6) Address (TypeScript)

Viewed 430

I`m working on a project using TypeScript and have access to a key-value based storage. The requirement is to find data related to a single IP (match key).

Unfortunately the key is always a CIDR covering a lot of IP's (to save storage due to many records). During my tests I was unable to find the correct CIDR belonging to a specific IP.

Example data:

"103.21.244.0/24" - "data, lorem ipsum, etc"

Example IP to find:

"103.21.244.1"

I have tested several libraries like: ip-address, ip-num, ip-to-int, ipaddr.js and more, but I am unable to get the result I want.

Maybe I am just being dumb and do not understand the IP specification correctly, or maybe I am just misusing these libraries, please enlighten me.

Surely there has to be a way without calling external API's (like RIPE) and without having to store billions of IP's instead of their CIDR.

Essentially the requirement is quite simple: "find this KEY (in CIDR) by this IP (v4 or v6)".

Any help, advice, example solutions are highly appreciated.

1 Answers

IP address can be converted to a single number. The a.b.c.d form is a just base-256 representation of a 32-bit number. Convert both the address and the subnet mask to integer. Then use "bitwise and" operation to apply the mask to the target IP addresses and compare with the network address.

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))) & 0xffffffff;
}

const cidr = "103.21.244.0/24";
const [networkAddr,subnetMask] = cidr.split("/");

const ipAddr = "103.21.244.1";

const match = (addrToNumber(ipAddr) & subnetMaskToNumber(subnetMask)) == addrToNumber(networkAddr)
console.log(match);

To generate all possible CIDR for an IP address:

function addrToNumber(addr)
{
  return addr.split(".").reduce((acc,cur,i)=> acc += (Number(cur) << ( (3-i) * 8) ) ,0)
}
function numberToAddr(num)
{
  return `${(num >> 24) & 0xff}.${(num >> 16) & 0xff}.${(num >> 8) & 0xff}.${num & 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 & mask)}/${i}`;
});

console.log(possibleCIDR);

To generate possible CIDR for IPv6, zeros compression not handled.

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))) & 0xffff : 0;
  return groups.map((value,j)=>{
    return (j < groupIndex ? value : j == groupIndex ? parseInt(value,16) & mask : 0).toString(16)
  }).join(":") + `/${i}`;
});
console.log(possibleCIDR);

Related