ค้นหาเว็บไซต์

javascript - การหาค่า CIDR สำหรับที่อยู่ IP เดียว (v4/v6) (TypeScript)


ฉันกำลังทำงานเกี่ยวกับโปรเจกต์โดยใช้ TypeScript และสามารถเข้าถึงการจัดเก็บข้อมูลแบบคู่คีย์-ค่าได้ ข้อกำหนดคือการค้นหาข้อมูลที่เกี่ยวข้องกับ IP เดียว (จับคู่คีย์)

โชคร้ายที่กุญแจมักจะเป็น CIDR ที่ครอบคลุม IP จำนวนมาก (เพื่อประหยัดพื้นที่เก็บข้อมูลเนื่องจากมีเรคคอร์ดจำนวนมาก) ในระหว่างการทดสอบของฉัน ฉันไม่สามารถหาค่า CIDR ที่ถูกต้องที่เป็นของ IP เฉพาะเจาะจงได้

ตัวอย่างข้อมูล:

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

ตัวอย่าง IP ที่ต้องการหา:

"103.21.244.1"

ฉันได้ทดสอบไลบรารีหลายตัวเช่น: ip-address, ip-num, ip-to-int, ipaddr.js และอื่นๆ แต่ฉันไม่สามารถได้ผลลัพธ์ที่ต้องการ

บางทีฉันอาจโง่และไม่เข้าใจข้อกำหนด IP อย่างถูกต้อง หรือบางทีฉันอาจใช้ไลบรารีเหล่านี้ผิดวิธี โปรดชี้แนะฉันด้วย

แน่นอนต้องมีวิธีโดยไม่ต้องเรียกใช้ API ภายนอก (เช่น RIPE) และไม่ต้องเก็บที่อยู่ IP พันล้านรายการแทนที่จะเก็บเป็น CIDR ของพวกมัน

โดยพื้นฐานแล้วข้อกำหนดค่อนข้างเรียบง่าย: "ค้นหา KEY นี้ (ใน CIDR) โดยใช้ IP นี้ (v4 หรือ v6)".

ความช่วยเหลือ คำแนะนำ หรือ ตัวอย่างวิธีแก้ปัญหาใด ๆ จะได้รับการชื่นชมอย่างมาก

คำตอบ #1

ที่อยู่ IP สามารถแปลงเป็นตัวเลขเพียงตัวเดียวได้ รูปแบบ a.b.c.d เป็นเพียงการแทนค่าฐาน-256 ของตัวเลข 32 บิต แปลงทั้งที่อยู่และมาสก์เครือข่ายเป็นจำนวนเต็ม จากนั้นใช้การดำเนินการ "bitwise and" เพื่อใช้มาสก์กับที่อยู่ 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))) & 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);

เพื่อสร้าง 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) & 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);

เพื่อสร้าง 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))) & 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);